diff --git a/android/app/build.gradle b/android/app/build.gradle index 6b51e6c..4022ff6 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'com.android.application' android { compileSdkVersion rootProject.ext.compileSdkVersion defaultConfig { - applicationId "io.ionic.starter" + applicationId "org.gcube.workspace" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode 1 diff --git a/android/app/capacitor.build.gradle b/android/app/capacitor.build.gradle index 06a5be4..ca1c63f 100644 --- a/android/app/capacitor.build.gradle +++ b/android/app/capacitor.build.gradle @@ -12,6 +12,7 @@ dependencies { implementation project(':capacitor-app') implementation project(':capacitor-haptics') implementation project(':capacitor-keyboard') + implementation project(':capacitor-splash-screen') implementation project(':capacitor-status-bar') } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 4d471dc..1bac385 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ + package="gcube.workspace.starter"> '../../node_modules/@capacitor/app' pod 'CapacitorHaptics', :path => '../../node_modules/@capacitor/haptics' pod 'CapacitorKeyboard', :path => '../../node_modules/@capacitor/keyboard' + pod 'CapacitorSplashScreen', :path => '../../node_modules/@capacitor/splash-screen' pod 'CapacitorStatusBar', :path => '../../node_modules/@capacitor/status-bar' pod 'CordovaPlugins', :path => '../capacitor-cordova-ios-plugins' end diff --git a/package-lock.json b/package-lock.json index a3abb76..992795d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "workspace", "version": "0.0.1", "dependencies": { + "-": "^0.0.1", "@angular/common": "^15.0.0", "@angular/core": "^15.0.0", "@angular/forms": "^15.0.0", @@ -22,18 +23,20 @@ "@capacitor/haptics": "4.1.0", "@capacitor/ios": "4.6.3", "@capacitor/keyboard": "4.1.1", + "@capacitor/splash-screen": "^4.2.0", "@capacitor/status-bar": "4.1.1", "@fortawesome/angular-fontawesome": "^0.12.1", "@fortawesome/fontawesome-svg-core": "^6.3.0", "@fortawesome/free-regular-svg-icons": "^6.3.0", "@fortawesome/free-solid-svg-icons": "^6.3.0", "@ionic/angular": "^6.5.4", + "angular-oauth2-oidc": "^15.0.1", "cordova-plugin-file-opener2": "^4.0.0", - "cordova-plugin-preview-any-file": "^0.2.9", "ionicons": "^6.1.3", "material-icons": "^1.13.1", "node-angular-http-client": "^1.1.7", "rxjs": "~7.5.0", + "save": "^2.9.0", "tslib": "^2.3.0", "zone.js": "~0.11.4" }, @@ -69,6 +72,11 @@ "typescript": "~4.8.4" } }, + "node_modules/-": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/-/-/--0.0.1.tgz", + "integrity": "sha512-3HfneK3DGAm05fpyj20sT3apkNcvPpCuccOThOPdzz8sY7GgQGe0l93XH9bt+YzibcTIgUAIMoyVJI740RtgyQ==" + }, "node_modules/@ampproject/remapping": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", @@ -2565,6 +2573,14 @@ "@capacitor/core": "^4.0.0" } }, + "node_modules/@capacitor/splash-screen": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@capacitor/splash-screen/-/splash-screen-4.2.0.tgz", + "integrity": "sha512-XtGqM7J/yVEl/tKksKa7l1B6IDzhq4JJkadRuT8ohf/N7fD/1z45+id/4twM2Vnsxazh1fur2gq8rma7HaXMEw==", + "peerDependencies": { + "@capacitor/core": "^4.0.0" + } + }, "node_modules/@capacitor/status-bar": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/@capacitor/status-bar/-/status-bar-4.1.1.tgz", @@ -5453,6 +5469,18 @@ "ajv": "^8.8.2" } }, + "node_modules/angular-oauth2-oidc": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/angular-oauth2-oidc/-/angular-oauth2-oidc-15.0.1.tgz", + "integrity": "sha512-5gpqO9QL+qFqMItYFHe8F6H5nOIEaowcNUc9iTDs3P1bfVYnoKoVAaijob53PuPTF4YwzdfwKWZi4Mq6P7GENQ==", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/common": ">=14.0.0", + "@angular/core": ">=14.0.0" + } + }, "node_modules/ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", @@ -5627,6 +5655,11 @@ "node": ">=8" } }, + "node_modules/async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" + }, "node_modules/at-least-node": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", @@ -6577,11 +6610,6 @@ } } }, - "node_modules/cordova-plugin-preview-any-file": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/cordova-plugin-preview-any-file/-/cordova-plugin-preview-any-file-0.2.9.tgz", - "integrity": "sha512-OXgbmbfH+jeUme5q4NM7KZMra05E8G2ddolWrAQYt2cBAspikqSCg43a0TfaTQp/dBP94mzG/WA3ea+f7KSoKg==" - }, "node_modules/core-js-compat": { "version": "3.28.0", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.28.0.tgz", @@ -7101,6 +7129,11 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -8000,6 +8033,20 @@ "node": ">= 0.6" } }, + "node_modules/event-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-4.0.1.tgz", + "integrity": "sha512-qACXdu/9VHPBzcyhdOWR5/IahhGMf0roTeZJfzz077GwylcDd90yOHLouhmv7GJ5XzPi6ekaQWd8AvPP2nOvpA==", + "dependencies": { + "duplexer": "^0.1.1", + "from": "^0.1.7", + "map-stream": "0.0.7", + "pause-stream": "^0.0.11", + "split": "^1.0.1", + "stream-combiner": "^0.2.2", + "through": "^2.3.8" + } + }, "node_modules/eventemitter-asyncresource": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz", @@ -8420,6 +8467,11 @@ "node": ">= 0.6" } }, + "node_modules/from": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", + "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==" + }, "node_modules/fs-extra": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", @@ -10588,6 +10640,11 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "node_modules/lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha512-hFuH8TY+Yji7Eja3mGiuAxBqLagejScbG8GbG0j6o9vzn0YL14My+ktnqtZgFTosKymC9/44wP6s7xyuLfnClw==" + }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -10915,6 +10972,11 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/map-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", + "integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==" + }, "node_modules/material-icons": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/material-icons/-/material-icons-1.13.1.tgz", @@ -11026,6 +11088,11 @@ "node": ">=6" } }, + "node_modules/mingo": { + "version": "6.2.7", + "resolved": "https://registry.npmjs.org/mingo/-/mingo-6.2.7.tgz", + "integrity": "sha512-r+yKmrZ+6SjwGxSot+/3S8sP9+LCxWNueR6xppMx7BzV60OegjbeklWAf/UveyQi8PDW8g/mwrQSHZVY/5jBJQ==" + }, "node_modules/mini-css-extract-plugin": { "version": "2.7.2", "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.2.tgz", @@ -12303,6 +12370,14 @@ "node": ">=8" } }, + "node_modules/pause-stream": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==", + "dependencies": { + "through": "~2.3" + } + }, "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -13328,6 +13403,17 @@ } } }, + "node_modules/save": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/save/-/save-2.9.0.tgz", + "integrity": "sha512-eg8+g8CjvehE/2C6EbLdtK1pINVD27pcJLj4M9PjWWhoeha/y5bWf4dp/0RF+OzbKTcG1bae9qi3PAqiR8CJTg==", + "dependencies": { + "async": "^3.2.2", + "event-stream": "^4.0.1", + "lodash.assign": "^4.2.0", + "mingo": "^6.1.0" + } + }, "node_modules/sax": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.1.4.tgz", @@ -13920,6 +14006,17 @@ "wbuf": "^1.7.3" } }, + "node_modules/split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "dependencies": { + "through": "2" + }, + "engines": { + "node": "*" + } + }, "node_modules/split2": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz", @@ -13968,6 +14065,15 @@ "node": ">= 0.4" } }, + "node_modules/stream-combiner": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", + "integrity": "sha512-6yHMqgLYDzQDcAkL+tjJDC5nSNuNIx0vZtRZeiPh7Saef7VHX9H5Ijn9l2VIol2zaNYlYEX6KyuT/237A58qEQ==", + "dependencies": { + "duplexer": "~0.1.1", + "through": "~2.3.4" + } + }, "node_modules/streamroller": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", @@ -14386,8 +14492,7 @@ "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" }, "node_modules/through2": { "version": "4.0.2", diff --git a/package.json b/package.json index 7ca7bbb..c3524f9 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ }, "private": true, "dependencies": { + "-": "^0.0.1", "@angular/common": "^15.0.0", "@angular/core": "^15.0.0", "@angular/forms": "^15.0.0", @@ -27,18 +28,20 @@ "@capacitor/haptics": "4.1.0", "@capacitor/ios": "4.6.3", "@capacitor/keyboard": "4.1.1", + "@capacitor/splash-screen": "^4.2.0", "@capacitor/status-bar": "4.1.1", "@fortawesome/angular-fontawesome": "^0.12.1", "@fortawesome/fontawesome-svg-core": "^6.3.0", "@fortawesome/free-regular-svg-icons": "^6.3.0", "@fortawesome/free-solid-svg-icons": "^6.3.0", "@ionic/angular": "^6.5.4", + "angular-oauth2-oidc": "^15.0.1", "cordova-plugin-file-opener2": "^4.0.0", - "cordova-plugin-preview-any-file": "^0.2.9", "ionicons": "^6.1.3", "material-icons": "^1.13.1", "node-angular-http-client": "^1.1.7", "rxjs": "~7.5.0", + "save": "^2.9.0", "tslib": "^2.3.0", "zone.js": "~0.11.4" }, diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 913de3d..f897a46 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -6,5 +6,6 @@ import { Component } from '@angular/core'; styleUrls: ['app.component.scss'], }) export class AppComponent { - constructor() {} + constructor(){} + } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index f9121bd..3cedf0e 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -4,19 +4,19 @@ import { BrowserModule } from '@angular/platform-browser'; import { RouteReuseStrategy } from '@angular/router'; import { IonicModule, IonicRouteStrategy } from '@ionic/angular'; - +import { OAuthModule } from 'angular-oauth2-oidc' import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; @NgModule({ declarations: [AppComponent], - imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule, HttpClientModule], + imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule, HttpClientModule, HttpClientModule], providers: [{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }], bootstrap: [AppComponent] }) export class AppModule { - + constructor() { } - + } diff --git a/src/app/items-grid/items-grid.component.html b/src/app/items-grid/items-grid.component.html new file mode 100644 index 0000000..311b067 --- /dev/null +++ b/src/app/items-grid/items-grid.component.html @@ -0,0 +1,27 @@ +
+ +

Empty folder

+
+ + + + + description + {{ u }} + + + + + {{ i.getIconInfo() }} + + {{ i.getTitle() }} +

{{ i.item.owner }}

+ +

{{i.item.lastModificationTime | date: 'dd MMM yyyy'}}

+
+ +
+ more_horiz +
+
+
diff --git a/src/app/items-grid/items-grid.component.scss b/src/app/items-grid/items-grid.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/items-grid/items-grid.component.spec.ts b/src/app/items-grid/items-grid.component.spec.ts new file mode 100644 index 0000000..98bec57 --- /dev/null +++ b/src/app/items-grid/items-grid.component.spec.ts @@ -0,0 +1,24 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; +import { IonicModule } from '@ionic/angular'; + +import { ItemsGridComponent } from './items-grid.component'; + +describe('ItemsGridComponent', () => { + let component: ItemsGridComponent; + let fixture: ComponentFixture; + + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [ ItemsGridComponent ], + imports: [IonicModule.forRoot()] + }).compileComponents(); + + fixture = TestBed.createComponent(ItemsGridComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + })); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/items-grid/items-grid.component.ts b/src/app/items-grid/items-grid.component.ts new file mode 100644 index 0000000..3e5f17b --- /dev/null +++ b/src/app/items-grid/items-grid.component.ts @@ -0,0 +1,33 @@ +import { CommonModule } from '@angular/common'; +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { MatIconModule } from '@angular/material/icon'; +import { IonicModule } from '@ionic/angular'; +import { WSItem } from '../model/ws-item'; + +@Component({ + selector: 'app-items-grid', + templateUrl: './items-grid.component.html', + styleUrls: ['./items-grid.component.scss'], + imports: [CommonModule, IonicModule, MatIconModule] +}) +export class ItemsGridComponent implements OnInit { + + @Output() actionSheetClickedEvent = new EventEmitter(); + @Output() itemClickedEvent = new EventEmitter(); + + @Input() items: WSItem[] | undefined; + @Input() underUploadItem: string[] = []; + + constructor() { } + + ngOnInit() {} + + itemClicked(item: WSItem){ + this.itemClickedEvent.emit(item); + } + + actionsSheetClicked(item: WSItem){ + this.actionSheetClickedEvent.emit(item); + } + +} diff --git a/src/app/items-list/items-list.component.html b/src/app/items-list/items-list.component.html new file mode 100644 index 0000000..311b067 --- /dev/null +++ b/src/app/items-list/items-list.component.html @@ -0,0 +1,27 @@ +
+ +

Empty folder

+
+ + + + + description + {{ u }} + + + + + {{ i.getIconInfo() }} + + {{ i.getTitle() }} +

{{ i.item.owner }}

+ +

{{i.item.lastModificationTime | date: 'dd MMM yyyy'}}

+
+ +
+ more_horiz +
+
+
diff --git a/src/app/items-list/items-list.component.scss b/src/app/items-list/items-list.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/items-list/items-list.component.spec.ts b/src/app/items-list/items-list.component.spec.ts new file mode 100644 index 0000000..d44a2fa --- /dev/null +++ b/src/app/items-list/items-list.component.spec.ts @@ -0,0 +1,24 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; +import { IonicModule } from '@ionic/angular'; + +import { ItemsListComponent } from './items-list.component'; + +describe('ItemsListComponent', () => { + let component: ItemsListComponent; + let fixture: ComponentFixture; + + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [ ItemsListComponent ], + imports: [IonicModule.forRoot()] + }).compileComponents(); + + fixture = TestBed.createComponent(ItemsListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + })); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/items-list/items-list.component.ts b/src/app/items-list/items-list.component.ts new file mode 100644 index 0000000..5db4b11 --- /dev/null +++ b/src/app/items-list/items-list.component.ts @@ -0,0 +1,34 @@ +import { CommonModule } from '@angular/common'; +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { MatIconModule } from '@angular/material/icon'; +import { IonicModule } from '@ionic/angular'; +import { WSItem } from '../model/ws-item'; + +@Component({ + standalone: true, + selector: 'app-items-list', + templateUrl: './items-list.component.html', + styleUrls: ['./items-list.component.scss'], + imports: [CommonModule, IonicModule, MatIconModule] +}) +export class ItemsListComponent implements OnInit { + + @Output() actionSheetClickedEvent = new EventEmitter(); + @Output() itemClickedEvent = new EventEmitter(); + + @Input() items: WSItem[] | undefined; + @Input() underUploadItem: string[] = []; + + constructor() { } + + ngOnInit() {} + + itemClicked(item: WSItem){ + this.itemClickedEvent.emit(item); + } + + actionsSheetClicked(item: WSItem){ + this.actionSheetClickedEvent.emit(item); + } + +} diff --git a/src/app/model/actions/actions.ts b/src/app/model/actions/actions.ts index 141d8ab..1def8d5 100644 --- a/src/app/model/actions/actions.ts +++ b/src/app/model/actions/actions.ts @@ -6,22 +6,29 @@ import { RenameAction } from "./rename-item"; export class Actions { - private static actions: Action[] = [new MoveAction(), new CopyAction(),new RenameAction(), new DeleteAction()]; + private static mv = new MoveAction(); + private static cp = new CopyAction(); + private static ren = new RenameAction(); + private static del = new DeleteAction(); + public static getActionsPerType(type: string): Action[] { - /*switch (type) { + switch (type) { case 'SharedFolder': - break; + return []; case 'FolderItem': - break; + return [this.mv, this.ren, this.del]; + case 'TrashItem': + return [this.del]; case 'PDFFileItem': - break; + return [this.mv, this.cp, this.ren, this.del]; case 'ImageFile': - break; + return [this.mv, this.cp, this.ren, this.del]; case 'ExternalLink': - break; + return [this.mv, this.cp, this.ren, this.del]; default: - }*/ - return Actions.actions; + return [this.mv, this.cp, this.ren, this.del]; + } + } } diff --git a/src/app/model/sorting.ts b/src/app/model/sorting.ts new file mode 100644 index 0000000..fd9b0e8 --- /dev/null +++ b/src/app/model/sorting.ts @@ -0,0 +1,49 @@ +import { WSItem } from "./ws-item"; + +export enum SortName { + Name = "Name", + LastModificationTime = "Last Modified", + FolderFirst = "Folders First" +} + +export enum SortType { + Asc = "arrow_upward", + Desc = "arrow_downward" +} + +export class Sorting { + + private static sortByNameASC = (item1: WSItem, item2: WSItem) => item1.getTitle().toLowerCase() > item2.getTitle().toLowerCase() ? -1 : 1; + private static sortByNameDESC = (item1: WSItem, item2: WSItem) => item1.getTitle().toLowerCase() > item2.getTitle().toLowerCase() ? 1 : -1; + + private static sortByLastModificationASC = (item1: WSItem, item2: WSItem) => item1.item.lastModificationTime > item2.item.lastModificationTime ? 1 : -1; + private static sortByLastModificationDESC = (item1: WSItem, item2: WSItem) => item1.item.lastModificationTime > item2.item.lastModificationTime ? -1 : 1; + + private static folderFirst(item1: WSItem, item2: WSItem) { + if (item1.isFolder() && !item2.isFolder()) return -1; + if (!item1.isFolder() && item2.isFolder()) return 1; + if (item1.item.title > item2.item.title) return 1; + if (item1.item.title < item2.item.title) return -1; + return 0; + } + + static getSortFunction(name: SortName, type: SortType): (a: WSItem, b: WSItem) => number { + switch (name) { + case SortName.Name: + switch (type) { + case SortType.Asc: return this.sortByNameASC; + case SortType.Desc: return this.sortByNameDESC; + } + case SortName.LastModificationTime: + switch (type) { + case SortType.Asc: return this.sortByLastModificationASC; + case SortType.Desc: return this.sortByLastModificationDESC; + } + case SortName.FolderFirst: + return this.folderFirst; + } + } + + + +} \ No newline at end of file diff --git a/src/app/model/ws-item.ts b/src/app/model/ws-item.ts index fcf0e4e..bc9fa7c 100644 --- a/src/app/model/ws-item.ts +++ b/src/app/model/ws-item.ts @@ -22,6 +22,9 @@ export class WSItem { case 'FolderItem': retrievedName = "folder"; break; + case 'TrashItem': + retrievedName = "delete"; + break; case 'PDFFileItem': retrievedName = "picture_as_pdf"; break; @@ -47,8 +50,15 @@ export class WSItem { this.type === 'FolderItem'; } - getTitle(): string | undefined{ - return this.item.vreFolder? this.item.displayName: this.item.title; + isFile(): boolean { + return this.type === 'PDFFileItem' || + this.type === 'ImageFile' || + this.type === 'GenericFileItem'; + } + + getTitle(): string{ + var title = this.item.vreFolder? this.item.displayName: this.item.title; + return title? title : this.item.name; } } diff --git a/src/app/show-folder/show-folder.component.html b/src/app/show-folder/show-folder.component.html index 39aa734..f9eeb23 100644 --- a/src/app/show-folder/show-folder.component.html +++ b/src/app/show-folder/show-folder.component.html @@ -1,42 +1,43 @@ + + + All + + + Folders + + + Shared Folders + + + Files + + - - + + arrow_back_ios_new - {{ !root && parentItem ? parentItem.getTitle() : tabName }} + {{ title }} create_new_folder upload_file + - - - -

Empty folder

-
- - - - - description - {{ u }} - - - - - {{ i.getIconInfo() }} - - {{ i.getTitle() }} -

{{ i.item.owner }}

- -

{{i.item.lastModificationTime | date: 'dd MMM yyyy'}}

-
- -
- more_horiz -
-
- +
+ + + + Name + Last Modified + + + {{ currentSortType }} + +
+ +
\ No newline at end of file diff --git a/src/app/show-folder/show-folder.component.ts b/src/app/show-folder/show-folder.component.ts index b9b34ab..80477b5 100644 --- a/src/app/show-folder/show-folder.component.ts +++ b/src/app/show-folder/show-folder.component.ts @@ -10,7 +10,8 @@ import { WSItem } from '../model/ws-item'; import { Action } from '../model/actions/action'; import { CreateFolderAction } from '../model/actions/create-folder'; import { Actions } from '../model/actions/actions'; -import { BehaviorSubject } from 'rxjs'; +import { ItemsListComponent } from '../items-list/items-list.component'; +import { Sorting, SortName, SortType } from '../model/sorting'; @Component({ standalone: true, @@ -20,25 +21,44 @@ import { BehaviorSubject } from 'rxjs'; styleUrls: ['./show-folder.component.scss'], schemas: [CUSTOM_ELEMENTS_SCHEMA], imports: [ - CommonModule, IonicModule, MatIconModule + CommonModule, IonicModule, MatIconModule, ItemsListComponent ] }) export class ShowFolderComponent implements OnInit { @Output() folderClickedEvent = new EventEmitter(); - @Input() items: WSItem[] = []; + filteredItems: WSItem[] | undefined; + _items: WSItem[] | undefined; - @Input() parentItem: WSItem | undefined; + currentSortName = SortName.Name; + currentSortType = SortType.Asc; - @Input() tabName: string = ""; + @Input() set items(items: WSItem[] | undefined) { + this._items = items?.sort(Sorting.getSortFunction(this.currentSortName, this.currentSortType)); + this.filteredItems = this._items; + } + + @Input() parentItem: WSItem | undefined = undefined; + + @Input() title: string | undefined; @Input() root: boolean = false; underUploadItem: string[] = []; + selectedSegment = "all"; + + public get sortName(): typeof SortName { + return SortName; + } + @ViewChild('filepicker') uploader!: ElementRef; + customSortAlertOptions = { + header: 'Sort by', + translucent: true, + }; constructor( private actionSheetCtrl: ActionSheetController, @@ -46,23 +66,84 @@ export class ShowFolderComponent implements OnInit { private alertCtrl: AlertController, private modalCtrl: ModalController, private toastController: ToastController - ) { } + ) { + } + ngOnInit(): void { } - loadDocuments() { + this.filteredItems = undefined; if (this.parentItem) { this.storagehub.getChildren(this.parentItem.item.id).subscribe( (res) => { const tmpItems$: WSItem[] = [] - res.forEach(i => tmpItems$.push(new WSItem(i))); - this.items = tmpItems$; + const tmpFiltered$: WSItem[] = [] + var segmentFilterFunction = this.getSegmentFilterFunction(); + res.forEach(i => { + var localItem = new WSItem(i); + tmpItems$.push(localItem); + if (segmentFilterFunction(localItem)) + tmpFiltered$.push(localItem); + }); + this._items = tmpItems$.sort(Sorting.getSortFunction(this.currentSortName, this.currentSortType)); + this.filteredItems = tmpFiltered$.sort(Sorting.getSortFunction(this.currentSortName, this.currentSortType)); }) } } + getSegmentFilterFunction(): (value: WSItem) => unknown { + var filterItemFunction; + switch (this.selectedSegment) { + case "shared": + filterItemFunction = (value: WSItem) => value.type == "SharedFolder"; + break; + case "folders": + filterItemFunction = (value: WSItem) => value.isFolder(); + break; + case "files": + filterItemFunction = (value: WSItem) => value.isFile(); + break; + default: + filterItemFunction = (value: WSItem) => true; + } + return filterItemFunction; + } + + filterBy(value: string) { + if (value == this.selectedSegment) return; + this.filteredItems = undefined; + this.selectedSegment = value; + if (this.selectedSegment == "all") + this.filteredItems = this._items; + else { + const tmpFiltered$: WSItem[] = [] + this._items?.filter(this.getSegmentFilterFunction()).forEach((i) => tmpFiltered$.push(i)); + this.filteredItems = tmpFiltered$; + } + } + + changeSortType() { + if (this.currentSortType == SortType.Asc) + this.currentSortType = SortType.Desc; + else this.currentSortType = SortType.Asc; + this.updateSort(); + } + + changeSortName($event: any) { + var sort : SortName = $event.target.value; + if (this.currentSortName != sort){ + this.currentSortName = sort; + this.updateSort(); + } + } + + updateSort() { + this._items = this._items?.sort(Sorting.getSortFunction(this.currentSortName, this.currentSortType)); + this.filteredItems = this.filteredItems?.sort(Sorting.getSortFunction(this.currentSortName, this.currentSortType)); + } + itemClicked(item: WSItem) { if (item.isFolder()) { this.folderClickedEvent.emit(item); @@ -77,13 +158,13 @@ export class ShowFolderComponent implements OnInit { const selected = $event.target.files[0]; if (selected && this.parentItem) { - this.underUploadItem= [selected.name]; + this.underUploadItem = [selected.name]; const upload$ = this.storagehub.uploadFile(this.parentItem.item.id, selected.name, selected); upload$.subscribe({ - next: () => this.loadDocuments(), + next: () => this.loadDocuments(), error: () => this.underUploadItem = [], complete: () => this.underUploadItem = [] - + }); } diff --git a/src/app/storagehub.service.ts b/src/app/storagehub.service.ts index d660c8b..b8b551b 100644 --- a/src/app/storagehub.service.ts +++ b/src/app/storagehub.service.ts @@ -10,6 +10,7 @@ import { ItemWrapper } from './model/item-wrapper.model'; const token = "b7c80297-e4ed-42ab-ab42-fdc0b8b0eabf-98187548"; +//const shURL ="https://workspace-repository.dev.d4science.org/storagehub/workspace" const shURL = "/shub/storagehub/workspace"; diff --git a/src/app/tabs/tabs-routing.module.ts b/src/app/tabs/tabs-routing.module.ts index 9d92e0f..aae0477 100644 --- a/src/app/tabs/tabs-routing.module.ts +++ b/src/app/tabs/tabs-routing.module.ts @@ -13,7 +13,7 @@ const routes: Routes = [ loadChildren: () => import('../ws/ws.module').then(m => m.WsPageModule) }, { - path: 'ws/:folderid', + path: 'ws/:folderId', pathMatch: 'full', loadChildren: () => import('../ws/ws.module').then(m => m.WsPageModule) }, @@ -22,7 +22,7 @@ const routes: Routes = [ loadChildren: () => import('../vres/vres.module').then(m => m.VresPageModule) }, { - path: 'vres/:folderid', + path: 'vres/:folderId', pathMatch: 'full', loadChildren: () => import('../vres/vres.module').then(m => m.VresPageModule) }, diff --git a/src/app/trash/trash.page.html b/src/app/trash/trash.page.html index 0bd6c2f..797fdac 100644 --- a/src/app/trash/trash.page.html +++ b/src/app/trash/trash.page.html @@ -1,4 +1,4 @@ - + diff --git a/src/app/vres/vres.page.html b/src/app/vres/vres.page.html index 9aaad82..f3817f7 100644 --- a/src/app/vres/vres.page.html +++ b/src/app/vres/vres.page.html @@ -1,3 +1,3 @@ - + diff --git a/src/app/vres/vres.page.ts b/src/app/vres/vres.page.ts index 09a03a9..291cf62 100644 --- a/src/app/vres/vres.page.ts +++ b/src/app/vres/vres.page.ts @@ -12,60 +12,78 @@ import { StoragehubService } from '../storagehub.service'; }) export class VresPage implements OnInit { - values: WSItem[] = []; + values: WSItem[] | undefined; item: WSItem | undefined; - folderid: string | undefined; - root: boolean = false; + private static cashItems: WSItem[] = []; + constructor(private storagehub: StoragehubService, private router: Router, private route: ActivatedRoute) { } ngOnInit() { - this.folderid = this.route.snapshot.paramMap.get('folderid') || undefined; - this.root = !this.folderid; - if (!this.folderid) - this.storagehub.getVres().subscribe( - (res) => { - const tmpItems$ : WSItem[] = [] - res.forEach(i => tmpItems$.push(new WSItem(i))); - this.values = tmpItems$; - } - ); - else - this.storagehub.getItem(this.folderid).subscribe( - (res) => { - this.item = new WSItem(res); - this.onSuccess(res); - } - ); + var folderId: string | undefined = this.route.snapshot.paramMap.get('folderId') || undefined; + var tmpItem: WSItem | undefined = undefined; + if (folderId) + tmpItem = VresPage.cashItems.find((value) => value.item.id === folderId); + + this.root = !folderId; + if (!tmpItem) { + if (!folderId) + this.storagehub.getVres().subscribe( + (res) => { + const tmpItems$: WSItem[] = [] + res.forEach(i => tmpItems$.push(new WSItem(i))); + this.values = tmpItems$; + } + ); + else //folder is not cached + this.storagehub.getItem(folderId).subscribe( + (res) => { + this.item = new WSItem(res); + this.onSuccess(res) + } + ); + + } else { + this.item = tmpItem; + this.onSuccess(tmpItem.item); + } } private onSuccess(item: Item) { - + this.storagehub.getChildren(item.id, false).subscribe( (res) => { - const tmpItems$ : WSItem[] = [] + const tmpItems$: WSItem[] = [] res.forEach(i => tmpItems$.push(new WSItem(i))); this.values = tmpItems$; } ) } - public getValues(): WSItem[] { + public getValues(): WSItem[] | undefined { return this.values; } openFolder(item: WSItem) { + if (this.values) + VresPage.cashItems = this.values; + this.router.navigateByUrl(`tabs/vres/${item.item.id}`); } - public getCurrentItem(): WSItem | undefined{ + public getCurrentItem(): WSItem | undefined { return this.item; } + + getTitle() { + return this.root ? "My VREs" : this.item?.getTitle() + } + } diff --git a/src/app/ws-viewer/ws-viewer.component.ts b/src/app/ws-viewer/ws-viewer.component.ts index 6e6bfdd..34d6530 100644 --- a/src/app/ws-viewer/ws-viewer.component.ts +++ b/src/app/ws-viewer/ws-viewer.component.ts @@ -2,6 +2,7 @@ import { CommonModule } from '@angular/common'; import { Component, Input, OnInit } from '@angular/core'; import { MatIconModule } from '@angular/material/icon'; import { IonicModule, LoadingController, ModalController, ToastController } from '@ionic/angular'; +import { Sorting, SortName, SortType } from '../model/sorting'; import { WSItem } from '../model/ws-item'; import { StoragehubService } from '../storagehub.service'; @@ -44,7 +45,7 @@ export class WsViewerComponent implements OnInit { (res) => { const tmpItems$: WSItem[] = [] res.forEach(i => tmpItems$.push(new WSItem(i))); - this.items = tmpItems$.sort(this.sort); + this.items = tmpItems$.sort(Sorting.getSortFunction(SortName.FolderFirst, SortType.Asc)); }) } else this.storagehub.getWsRoot().subscribe( @@ -99,11 +100,5 @@ export class WsViewerComponent implements OnInit { return this.modalCtrl.dismiss(null, 'confirm'); } - sort(item1: WSItem, item2: WSItem) { - if (item1.isFolder() && !item2.isFolder()) return -1; - if (!item1.isFolder() && item2.isFolder()) return 1; - if (item1.item.title > item2.item.title) return 1; - if (item1.item.title < item2.item.title) return -1; - return 0; - } + } diff --git a/src/app/ws/ws.page.html b/src/app/ws/ws.page.html index ec5fa5a..5f4def9 100644 --- a/src/app/ws/ws.page.html +++ b/src/app/ws/ws.page.html @@ -1,5 +1,5 @@ - + diff --git a/src/app/ws/ws.page.ts b/src/app/ws/ws.page.ts index ae3b1d0..9d5fa51 100644 --- a/src/app/ws/ws.page.ts +++ b/src/app/ws/ws.page.ts @@ -5,6 +5,7 @@ import { FileOpener } from '@awesome-cordova-plugins/file-opener/ngx'; import { StoragehubService } from '../storagehub.service'; import { WSItem } from '../model/ws-item'; import { Item } from '../model/item.model'; +import { concatMap, from } from 'rxjs'; @Component({ selector: 'app-ws', @@ -14,57 +15,74 @@ import { Item } from '../model/item.model'; }) export class WsPage implements OnInit { - values: WSItem[] = []; + values: WSItem[] | undefined = undefined; - folderid: string | undefined; - - item : WSItem | undefined ; + item: WSItem | undefined; root: boolean = false; + private static cashItems: WSItem[] = []; + constructor(private storagehub: StoragehubService, private router: Router, private route: ActivatedRoute) { } ngOnInit() { - this.folderid = this.route.snapshot.paramMap.get('folderid') || undefined; - this.root = !this.folderid; - if (!this.folderid) - this.storagehub.getWsRoot().subscribe( - (res) => { - this.item = new WSItem(res); - this.onSuccess(res) - } - ); - else - this.storagehub.getItem(this.folderid).subscribe( - (res) => { - this.item = new WSItem(res); - this.onSuccess(res); - } - ); + var folderId: string | undefined = this.route.snapshot.paramMap.get('folderId') || undefined; + var tmpItem: WSItem | undefined = undefined; + if (folderId) + tmpItem = WsPage.cashItems.find((value) => value.item.id === folderId); + + this.root = !folderId; + if (!tmpItem) { + if (!folderId) + this.storagehub.getWsRoot().subscribe( + (res) => { + this.item = new WSItem(res); + this.onSuccess(res) + } + ); + else //folder is not cached + this.storagehub.getItem(folderId).subscribe( + (res) => { + this.item = new WSItem(res); + this.onSuccess(res) + } + ); + } else { + this.item = tmpItem; + this.onSuccess(tmpItem.item); + } + } private onSuccess(item: Item) { - + this.storagehub.getChildren(item.id, false).subscribe( (res) => { - const tmpItems$ : WSItem[] = [] + const tmpItems$: WSItem[] = [] res.forEach(i => tmpItems$.push(new WSItem(i))); this.values = tmpItems$; } ) } - public getValues(): WSItem[] { - return this.values; + public getValues(): WSItem[] | undefined { + return this.values; } openFolder(item: WSItem) { + if (this.values) + WsPage.cashItems = this.values; + this.router.navigateByUrl(`tabs/ws/${item.item.id}`); } - public getCurrentItem() : WSItem | undefined{ - return this.item; + public getCurrentItem(): WSItem | undefined { + return this.item; + } + + getTitle() { + return this.root ? "My Workspace" : this.item?.getTitle() } }