@yuuvis/app-drive 0.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -0
- package/esm2022/extensions/index.mjs +2 -0
- package/esm2022/extensions/lib/extensions.module.mjs +35 -0
- package/esm2022/extensions/lib/extensions.service.mjs +44 -0
- package/esm2022/extensions/lib/object-config.defaults.mjs +19 -0
- package/esm2022/extensions/yuuvis-app-drive-extensions.mjs +5 -0
- package/esm2022/index.mjs +5 -0
- package/esm2022/lib/actions/copy-link/copy-link.action.mjs +40 -0
- package/esm2022/lib/actions/index.mjs +7 -0
- package/esm2022/lib/actions/manage-versions/manage-versions.action.mjs +33 -0
- package/esm2022/lib/actions/manage-versions/manage-versions.component.mjs +105 -0
- package/esm2022/lib/actions/paste/paste.action.mjs +41 -0
- package/esm2022/lib/actions/rename/rename.action.mjs +31 -0
- package/esm2022/lib/actions/rename/rename.component.mjs +42 -0
- package/esm2022/lib/actions/rename/rename.validator.mjs +23 -0
- package/esm2022/lib/actions/updateContent/update.content.action.mjs +52 -0
- package/esm2022/lib/components/add-button/add-button-overlay/add-button-overlay.component.mjs +109 -0
- package/esm2022/lib/components/add-button/add-button.component.mjs +39 -0
- package/esm2022/lib/components/breadcrumb/breadcrumb.component.mjs +74 -0
- package/esm2022/lib/components/folder-tree/folder-tree.component.mjs +89 -0
- package/esm2022/lib/components/index.mjs +10 -0
- package/esm2022/lib/components/object-name/object-name.component.mjs +60 -0
- package/esm2022/lib/components/overlay/create-folder/create-folder.component.mjs +48 -0
- package/esm2022/lib/components/paste-from-clipboard/paste-from-clipboard.component.mjs +28 -0
- package/esm2022/lib/components/ribbon/ribbon.component.mjs +102 -0
- package/esm2022/lib/components/search-filter/date-range-picker/date-range-picker.component.mjs +38 -0
- package/esm2022/lib/components/search-filter/search-filter.component.mjs +429 -0
- package/esm2022/lib/components/sort/sort.component.mjs +156 -0
- package/esm2022/lib/components/versions-list/tile/tile.component.mjs +60 -0
- package/esm2022/lib/components/versions-list/versions-list.component.mjs +94 -0
- package/esm2022/lib/container/drive/drive.component.mjs +116 -0
- package/esm2022/lib/drive.icons.mjs +16 -0
- package/esm2022/lib/drive.schema.mjs +49 -0
- package/esm2022/lib/lib.routes.mjs +17 -0
- package/esm2022/lib/pages/files/files.component.mjs +377 -0
- package/esm2022/lib/pages/object/object.component.mjs +200 -0
- package/esm2022/lib/services/drive/drive.interface.mjs +14 -0
- package/esm2022/lib/services/drive/drive.service.mjs +437 -0
- package/esm2022/lib/services/drive/resolve-name-conflicts/resolve-name-conflicts.component.mjs +158 -0
- package/esm2022/lib/services/drive/resolve-name-conflicts/resolve-name-conflicts.interface.mjs +2 -0
- package/esm2022/lib/services/drive/versions/versions.mapping.mjs +42 -0
- package/esm2022/lib/services/index.mjs +5 -0
- package/esm2022/lib/services/providers/drive.providers.mjs +10 -0
- package/esm2022/lib/services/resolver/files.resolver.mjs +12 -0
- package/esm2022/lib/services/resolver/index.mjs +3 -0
- package/esm2022/lib/services/resolver/versions.route.resolver.mjs +10 -0
- package/esm2022/lib/services/stored-query/stored-query.data.mjs +25 -0
- package/esm2022/lib/services/stored-query/stored-query.interface.mjs +2 -0
- package/esm2022/lib/services/stored-query/stored-query.service.mjs +41 -0
- package/esm2022/lib/services/tokens/breadcrumb-max-depth.token.mjs +3 -0
- package/esm2022/lib/services/tokens/index.mjs +2 -0
- package/esm2022/yuuvis-app-drive.mjs +5 -0
- package/extensions/README.md +3 -0
- package/extensions/index.d.ts +1 -0
- package/extensions/lib/extensions.module.d.ts +6 -0
- package/extensions/lib/extensions.service.d.ts +7 -0
- package/extensions/lib/object-config.defaults.d.ts +2 -0
- package/fesm2022/yuuvis-app-drive-extensions.mjs +99 -0
- package/fesm2022/yuuvis-app-drive-extensions.mjs.map +1 -0
- package/fesm2022/yuuvis-app-drive.mjs +2945 -0
- package/fesm2022/yuuvis-app-drive.mjs.map +1 -0
- package/index.d.ts +4 -0
- package/lib/actions/copy-link/copy-link.action.d.ts +18 -0
- package/lib/actions/index.d.ts +6 -0
- package/lib/actions/manage-versions/manage-versions.action.d.ts +17 -0
- package/lib/actions/manage-versions/manage-versions.component.d.ts +32 -0
- package/lib/actions/paste/paste.action.d.ts +17 -0
- package/lib/actions/rename/rename.action.d.ts +17 -0
- package/lib/actions/rename/rename.component.d.ts +12 -0
- package/lib/actions/rename/rename.validator.d.ts +5 -0
- package/lib/actions/updateContent/update.content.action.d.ts +18 -0
- package/lib/components/add-button/add-button-overlay/add-button-overlay.component.d.ts +26 -0
- package/lib/components/add-button/add-button.component.d.ts +12 -0
- package/lib/components/breadcrumb/breadcrumb.component.d.ts +25 -0
- package/lib/components/folder-tree/folder-tree.component.d.ts +13 -0
- package/lib/components/index.d.ts +8 -0
- package/lib/components/object-name/object-name.component.d.ts +21 -0
- package/lib/components/overlay/create-folder/create-folder.component.d.ts +12 -0
- package/lib/components/paste-from-clipboard/paste-from-clipboard.component.d.ts +13 -0
- package/lib/components/ribbon/ribbon.component.d.ts +24 -0
- package/lib/components/search-filter/date-range-picker/date-range-picker.component.d.ts +13 -0
- package/lib/components/search-filter/search-filter.component.d.ts +23 -0
- package/lib/components/sort/sort.component.d.ts +31 -0
- package/lib/components/versions-list/tile/tile.component.d.ts +14 -0
- package/lib/components/versions-list/versions-list.component.d.ts +17 -0
- package/lib/container/drive/drive.component.d.ts +36 -0
- package/lib/drive.icons.d.ts +15 -0
- package/lib/drive.schema.d.ts +23 -0
- package/lib/lib.routes.d.ts +2 -0
- package/lib/pages/files/files.component.d.ts +101 -0
- package/lib/pages/object/object.component.d.ts +35 -0
- package/lib/services/drive/drive.interface.d.ts +62 -0
- package/lib/services/drive/drive.service.d.ts +64 -0
- package/lib/services/drive/resolve-name-conflicts/resolve-name-conflicts.component.d.ts +31 -0
- package/lib/services/drive/resolve-name-conflicts/resolve-name-conflicts.interface.d.ts +8 -0
- package/lib/services/drive/versions/versions.mapping.d.ts +2 -0
- package/lib/services/index.d.ts +4 -0
- package/lib/services/providers/drive.providers.d.ts +7 -0
- package/lib/services/resolver/files.resolver.d.ts +2 -0
- package/lib/services/resolver/index.d.ts +2 -0
- package/lib/services/resolver/versions.route.resolver.d.ts +2 -0
- package/lib/services/stored-query/stored-query.data.d.ts +5 -0
- package/lib/services/stored-query/stored-query.interface.d.ts +5 -0
- package/lib/services/stored-query/stored-query.service.d.ts +10 -0
- package/lib/services/tokens/breadcrumb-max-depth.token.d.ts +2 -0
- package/lib/services/tokens/index.d.ts +1 -0
- package/package.json +41 -0
|
@@ -0,0 +1,2945 @@
|
|
|
1
|
+
import * as i1$3 from '@angular/common';
|
|
2
|
+
import { CommonModule, DOCUMENT, NgClass, DatePipe, AsyncPipe } from '@angular/common';
|
|
3
|
+
import * as i0 from '@angular/core';
|
|
4
|
+
import { InjectionToken, inject, Component, Injectable, input, effect, output, signal, viewChild, ElementRef, HostBinding, viewChildren, computed, ChangeDetectionStrategy, HostListener, DestroyRef, contentChild, ViewEncapsulation, untracked } from '@angular/core';
|
|
5
|
+
import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
|
|
6
|
+
import * as i1 from '@angular/forms';
|
|
7
|
+
import { FormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';
|
|
8
|
+
import * as i1$2 from '@angular/router';
|
|
9
|
+
import { Router, NavigationStart, ActivatedRoute, RouterModule, NavigationEnd } from '@angular/router';
|
|
10
|
+
import * as i2 from '@yuuvis/client-core';
|
|
11
|
+
import { SystemType, ClipboardService, TranslateService, TranslateModule, BaseObjectTypeField, EventService, DmsService, SearchService, BackendService, YuvEventType, ContentStreamField, NotificationService, Utils, SystemService, UserService, LocaleDatePipe, Operator, OperatorLabel, ObjectConfigService, DeviceService, AppCacheService } from '@yuuvis/client-core';
|
|
12
|
+
import { ActionsService, BASE_ACTION, SelectionRange, AbstractContextAction } from '@yuuvis/client-framework/actions';
|
|
13
|
+
import { YUV_ICONS } from '@yuuvis/client-framework/icons';
|
|
14
|
+
import { UploadProgressComponent } from '@yuuvis/client-framework/upload-progress';
|
|
15
|
+
import { AppLogoComponent } from '@yuuvis/client-shell';
|
|
16
|
+
import * as i1$1 from '@yuuvis/components/icon';
|
|
17
|
+
import { YvcIconModule, ICONS } from '@yuuvis/components/icon';
|
|
18
|
+
import { YvcOverflowMenuComponent } from '@yuuvis/components/overflow-menu';
|
|
19
|
+
import { YvcOverlayRef, YvcOverlayService, YvcOverlayModule } from '@yuuvis/components/overlay';
|
|
20
|
+
import { switchMap as switchMap$1, map as map$1, finalize as finalize$1, filter as filter$1 } from 'rxjs/operators';
|
|
21
|
+
import { marker } from '@colsen1991/ngx-translate-extract-marker';
|
|
22
|
+
import { signalState, patchState } from '@ngrx/signals';
|
|
23
|
+
import { tap, Subject, filter, switchMap, of, forkJoin, map, catchError, timer, finalize, from } from 'rxjs';
|
|
24
|
+
import { TranslateService as TranslateService$1, TranslateModule as TranslateModule$1 } from '@ngx-translate/core';
|
|
25
|
+
import { FormInputComponent, StringComponent, DatetimeRangeComponent } from '@yuuvis/client-framework/forms';
|
|
26
|
+
import { ShellService } from '@yuuvis/client-shell-core';
|
|
27
|
+
import { ObjectPreviewComponent } from '@yuuvis/client-framework/object-preview';
|
|
28
|
+
import { ObjectSummaryDataComponent, ObjectSummaryComponent, MultiObjectSummaryComponent } from '@yuuvis/client-framework/object-summary';
|
|
29
|
+
import * as i3 from '@yuuvis/components/split-view';
|
|
30
|
+
import { YvcSplitViewModule, SplitViewComponent } from '@yuuvis/components/split-view';
|
|
31
|
+
import * as i2$2 from '@yuuvis/components/tabs';
|
|
32
|
+
import { YvcTabsModule } from '@yuuvis/components/tabs';
|
|
33
|
+
import { ListComponent, ListItemDirective } from '@yuuvis/client-framework/list';
|
|
34
|
+
import { ActiveDescendantKeyManager } from '@angular/cdk/a11y';
|
|
35
|
+
import { Directionality } from '@angular/cdk/bidi';
|
|
36
|
+
import * as i2$1 from '@yuuvis/components/drag-scroll';
|
|
37
|
+
import { YvcDragScrollModule } from '@yuuvis/components/drag-scroll';
|
|
38
|
+
import { FocusWithinDirective, ClickDoubleDirective, FileDropZoneDirective, ContainerSizeDirective } from '@yuuvis/client-framework/common';
|
|
39
|
+
import { TreeComponent } from '@yuuvis/client-framework/tree';
|
|
40
|
+
import { SimpleSearchComponent } from '@yuuvis/client-framework/simple-search';
|
|
41
|
+
import { TileListComponent, TileConfigTriggerComponent } from '@yuuvis/client-framework/tile-list';
|
|
42
|
+
import { ClipboardComponent } from '@yuuvis/client-framework/clipboard';
|
|
43
|
+
import * as i1$4 from '@yuuvis/components/dropdown';
|
|
44
|
+
import { YvcDropdownModule } from '@yuuvis/components/dropdown';
|
|
45
|
+
import { ObjectMetadataComponent, ObjectAuditComponent } from '@yuuvis/client-framework/object-details';
|
|
46
|
+
import { ObjectFlavorComponent } from '@yuuvis/client-framework/object-flavor';
|
|
47
|
+
import { RendererDirective } from '@yuuvis/client-framework/renderer';
|
|
48
|
+
|
|
49
|
+
const APP_DRIVE_ICONS = {
|
|
50
|
+
file: '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="M240-80q-33 0-56.5-23.5T160-160v-640q0-33 23.5-56.5T240-880h320l240 240v480q0 33-23.5 56.5T720-80H240Zm280-520v-200H240v640h480v-440H520ZM240-800v200-200 640-640Z"/></svg>',
|
|
51
|
+
folder: '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h240l80 80h320q33 0 56.5 23.5T880-640H447l-80-80H160v480l96-320h684L837-217q-8 26-29.5 41.5T760-160H160Zm84-80h516l72-240H316l-72 240Zm0 0 72-240-72 240Zm-84-400v-80 80Z"/></svg>',
|
|
52
|
+
folderx: '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h240l80 80h320q33 0 56.5 23.5T880-640v400q0 33-23.5 56.5T800-160H160Zm0-80h640v-400H447l-80-80H160v480Zm0 0v-480 480Z"/></svg>',
|
|
53
|
+
favorite: '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="m354-287 126-76 126 77-33-144 111-96-146-13-58-136-58 135-146 13 111 97-33 143ZM233-120l65-281L80-590l288-25 112-265 112 265 288 25-218 189 65 281-247-149-247 149Zm247-350Z"/></svg>',
|
|
54
|
+
settings: '<svg xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 -960 960 960" width="20px" fill="#e8eaed"><path d="M447-288h64l14-56.31q14-4.69 26.5-11.19Q564-362 575-372l55 16 32-55-41-38.52q2-13.48 3-29.98t-2-29.5l40-38-32-55-54 15q-11-10-24-17t-27-12l-13-56h-65l-12 56q-14 5-27 12t-24 17l-54-16-32 56 41 38q-3 14-3 29.5t3 29.5l-41 39 32 56 55-17q11 9 23.5 16t26.5 12l12 56Zm32.79-120Q450-408 429-429.21t-21-51Q408-510 429.21-531t51-21Q510-552 531-530.79t21 51Q552-450 530.79-429t-51 21ZM216-144q-29.7 0-50.85-21.15Q144-186.3 144-216v-528q0-29.7 21.15-50.85Q186.3-816 216-816h528q29.7 0 50.85 21.15Q816-773.7 816-744v528q0 29.7-21.15 50.85Q773.7-144 744-144H216Zm0-72h528v-528H216v528Zm0-528v528-528Z"/></svg>',
|
|
55
|
+
sort: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#5f6368" viewBox="0 -960 960 960"><path d="M320-440v-287L217-624l-57-56 200-200 200 200-57 56-103-103v287h-80ZM600-80 400-280l57-56 103 103v-287h80v287l103-103 57 56L600-80Z"/></svg>',
|
|
56
|
+
home: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#e8eaed" viewBox="0 -960 960 960"><path d="M240-200h120v-240h240v240h120v-360L480-740 240-560v360Zm-80 80v-480l320-240 320 240v480H520v-240h-80v240H160Zm320-350Z"/></svg>',
|
|
57
|
+
toggleLeft: '<svg xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 -960 960 960" width="20px" fill="#e8eaed"><path d="M211-144q-27.64 0-47.32-19.68T144-211v-538q0-27.64 19.68-47.32T211-816h538q27.64 0 47.32 19.68T816-749v538q0 27.64-19.68 47.32T749-144H211Zm125-72v-528H216v528h120Zm72 0h336v-528H408v528Zm-72 0H216h120Z"/></svg>',
|
|
58
|
+
toggleRight: '<svg xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 -960 960 960" width="20px" fill="#e8eaed"><path d="M211-144q-27.64 0-47.32-19.68T144-211v-538q0-27.64 19.68-47.32T211-816h538q27.64 0 47.32 19.68T816-749v538q0 27.64-19.68 47.32T749-144H211Zm413-72h120v-528H624v528Zm-72 0v-528H216v528h336Zm72 0h120-120Z"/></svg>',
|
|
59
|
+
clipboard: '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="M620-163 450-333l56-56 114 114 226-226 56 56-282 282Zm220-397h-80v-200h-80v120H280v-120h-80v560h240v80H200q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h167q11-35 43-57.5t70-22.5q40 0 71.5 22.5T594-840h166q33 0 56.5 23.5T840-760v200ZM480-760q17 0 28.5-11.5T520-800q0-17-11.5-28.5T480-840q-17 0-28.5 11.5T440-800q0 17 11.5 28.5T480-760Z"/></svg>',
|
|
60
|
+
addCircle: '<svg xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 -960 960 960" width="20px" fill="#e8eaed"><path d="M444-288h72v-156h156v-72H516v-156h-72v156H288v72h156v156Zm36.28 192Q401-96 331-126t-122.5-82.5Q156-261 126-330.96t-30-149.5Q96-560 126-629.5q30-69.5 82.5-122T330.96-834q69.96-30 149.5-30t149.04 30q69.5 30 122 82.5T834-629.28q30 69.73 30 149Q864-401 834-331t-82.5 122.5Q699-156 629.28-126q-69.73 30-149 30Zm-.28-72q130 0 221-91t91-221q0-130-91-221t-221-91q-130 0-221 91t-91 221q0 130 91 221t221 91Zm0-312Z"/></svg>',
|
|
61
|
+
createFolder: '<svg xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 -960 960 960" width="20px" fill="#e8eaed"><path d="M576-324h72v-72h72v-72h-72v-72h-72v72h-72v72h72v72ZM168-192q-29 0-50.5-21.5T96-264v-432q0-29.7 21.5-50.85Q139-768 168-768h216l96 96h312q29.7 0 50.85 21.15Q864-629.7 864-600v336q0 29-21.15 50.5T792-192H168Zm0-72h624v-336H450l-96-96H168v432Zm0 0v-432 432Z"/></svg>',
|
|
62
|
+
createFile: '<svg xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 -960 960 960" width="20px" fill="#e8eaed"><path d="M444-240h72v-108h108v-72H516v-108h-72v108H336v72h108v108ZM263.72-96Q234-96 213-117.15T192-168v-624q0-29.7 21.15-50.85Q234.3-864 264-864h312l192 192v504q0 29.7-21.16 50.85Q725.68-96 695.96-96H263.72ZM528-624v-168H264v624h432v-456H528ZM264-792v189-189 624-624Z"/></svg>'
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// Mapping schema for this apps backend schema
|
|
66
|
+
// use marker to extract the labels for the app schema types
|
|
67
|
+
// make sure to provide a marker for each type/flavor ID
|
|
68
|
+
marker('io.yuuvis.app.drive.folder');
|
|
69
|
+
marker('io.yuuvis.app.drive.file');
|
|
70
|
+
const FS_PROPERTIES = {
|
|
71
|
+
name: 'appOsdrive:fileName'
|
|
72
|
+
};
|
|
73
|
+
const FS_SOTS = {
|
|
74
|
+
object: 'appOsdrive:file'
|
|
75
|
+
};
|
|
76
|
+
const APP_PREFIX = 'appDrive:';
|
|
77
|
+
const APP_ID = 'io.yuuvis.app.drive';
|
|
78
|
+
const APP_SCHEMA = {
|
|
79
|
+
id: APP_ID,
|
|
80
|
+
name: 'OS Drive',
|
|
81
|
+
icon: '<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M340-320h300q50 0 85-35t35-85q0-50-35-85t-85-35q-8-58-53-99t-101-41q-51 0-92.5 26T332-600q-57 5-94.5 43.5T200-460q0 58 41 99t99 41Zm0-80q-25 0-42.5-17.5T280-460q0-25 17.5-42.5T340-520h60v-20q0-33 23.5-56.5T480-620q33 0 56.5 23.5T560-540v60h80q17 0 28.5 11.5T680-440q0 17-11.5 28.5T640-400H340ZM480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/></svg>',
|
|
82
|
+
types: {
|
|
83
|
+
folder: {
|
|
84
|
+
id: `${APP_ID}.folder`,
|
|
85
|
+
icon: APP_DRIVE_ICONS.folder,
|
|
86
|
+
objectType: SystemType.FOLDER,
|
|
87
|
+
sots: [FS_SOTS.object]
|
|
88
|
+
},
|
|
89
|
+
file: {
|
|
90
|
+
id: `${APP_ID}.file`,
|
|
91
|
+
icon: APP_DRIVE_ICONS.file,
|
|
92
|
+
objectType: SystemType.DOCUMENT,
|
|
93
|
+
sots: [FS_SOTS.object]
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
flavors: []
|
|
97
|
+
};
|
|
98
|
+
const APP_ACTIONS = {
|
|
99
|
+
rename: 'app.drive.action.rename',
|
|
100
|
+
paste: 'app.drive.action.paste',
|
|
101
|
+
copyLink: 'app.drive.action.copy.link',
|
|
102
|
+
contentUpdate: 'app.drive.action.content.update',
|
|
103
|
+
manageVersions: 'app.drive.action.manage-versions'
|
|
104
|
+
};
|
|
105
|
+
const ACTION_CONTEXT = {
|
|
106
|
+
subjectProperty: FS_PROPERTIES.name,
|
|
107
|
+
appId: APP_ID
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const DRIVE_APP_BREADCRUMB_MAX_DEPTH = new InjectionToken('Max depth of the folder strukture in the Breadcrumb', { factory: () => 3 });
|
|
111
|
+
|
|
112
|
+
// ID representing the root folder
|
|
113
|
+
const DRIVE_ROOT_FOLDER_ID = 'root';
|
|
114
|
+
// ID representing a custom view like 'recently edited documents'
|
|
115
|
+
const DRIVE_QUERY_FOLDER_ID = 'query';
|
|
116
|
+
var DRIVE_EVENT;
|
|
117
|
+
(function (DRIVE_EVENT) {
|
|
118
|
+
DRIVE_EVENT["refresh"] = "refresh";
|
|
119
|
+
})(DRIVE_EVENT || (DRIVE_EVENT = {}));
|
|
120
|
+
var DRIVE_ACTION_MODE;
|
|
121
|
+
(function (DRIVE_ACTION_MODE) {
|
|
122
|
+
DRIVE_ACTION_MODE["CUT"] = "cut";
|
|
123
|
+
DRIVE_ACTION_MODE["COPY"] = "copy";
|
|
124
|
+
})(DRIVE_ACTION_MODE || (DRIVE_ACTION_MODE = {}));
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Component to resolve name conflicts. Based on its mode, it
|
|
128
|
+
* will handle files or objects that are about to be uploaded,
|
|
129
|
+
* copied or moved.
|
|
130
|
+
*/
|
|
131
|
+
class ResolveNameConflictsComponent {
|
|
132
|
+
constructor() {
|
|
133
|
+
this.#oRef = inject(YvcOverlayRef);
|
|
134
|
+
this.#drive = inject(DriveService);
|
|
135
|
+
this.#clipboard = inject(ClipboardService);
|
|
136
|
+
this.translate = inject(TranslateService);
|
|
137
|
+
this.validItems = [];
|
|
138
|
+
this.existingFileNames = [];
|
|
139
|
+
this.invalidFileNames = [];
|
|
140
|
+
this.content = {
|
|
141
|
+
headline: '',
|
|
142
|
+
message: '',
|
|
143
|
+
messageValid: '',
|
|
144
|
+
proceed: ''
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
#oRef;
|
|
148
|
+
#drive;
|
|
149
|
+
#clipboard;
|
|
150
|
+
proceed() {
|
|
151
|
+
if (!this.payload)
|
|
152
|
+
return;
|
|
153
|
+
switch (this.payload.mode) {
|
|
154
|
+
case 'upload': {
|
|
155
|
+
this.#upload(this.validItems.map((i) => i.item));
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
case 'copy': {
|
|
159
|
+
this.#copy(this.validItems.map((i) => i.item));
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
case 'move': {
|
|
163
|
+
this.#move(this.validItems.map((i) => i.item));
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
#upload(files) {
|
|
169
|
+
this.#drive.upload(files, this.payload?.data).subscribe();
|
|
170
|
+
// upload errors and progress are handled by the upload progress component
|
|
171
|
+
this.#oRef.close();
|
|
172
|
+
}
|
|
173
|
+
#copy(objects) {
|
|
174
|
+
this.#drive.setBusy(true);
|
|
175
|
+
this.#oRef.close();
|
|
176
|
+
this.#drive
|
|
177
|
+
.copyToCurrentFolder(objects, false)
|
|
178
|
+
.pipe(tap((res) => {
|
|
179
|
+
res && this.#drive.emitEvent(DRIVE_EVENT.refresh);
|
|
180
|
+
this.#clipboard.clear();
|
|
181
|
+
}))
|
|
182
|
+
.subscribe({
|
|
183
|
+
complete: () => {
|
|
184
|
+
this.#drive.setBusy(false);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
#move(objects) {
|
|
189
|
+
this.#drive.setBusy(true);
|
|
190
|
+
this.#oRef.close();
|
|
191
|
+
this.#drive
|
|
192
|
+
.moveToCurrentFolder(objects)
|
|
193
|
+
.pipe(tap((res) => {
|
|
194
|
+
res && this.#drive.emitEvent(DRIVE_EVENT.refresh);
|
|
195
|
+
this.#clipboard.clear();
|
|
196
|
+
}))
|
|
197
|
+
.subscribe({
|
|
198
|
+
complete: () => {
|
|
199
|
+
this.#drive.setBusy(false);
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
cancel() {
|
|
204
|
+
this.#oRef.close();
|
|
205
|
+
}
|
|
206
|
+
#setupValidItems() {
|
|
207
|
+
if (!this.payload)
|
|
208
|
+
return;
|
|
209
|
+
if (this.payload?.mode === 'upload') {
|
|
210
|
+
this.validItems = this.payload.items
|
|
211
|
+
.filter((f) => !this.existingFileNames.includes(f.name))
|
|
212
|
+
.map((item) => ({
|
|
213
|
+
name: item.name,
|
|
214
|
+
item
|
|
215
|
+
}));
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
this.validItems = this.payload.items
|
|
219
|
+
.filter((o) => !this.existingFileNames.includes(o.data[FS_PROPERTIES.name]))
|
|
220
|
+
.map((item) => ({
|
|
221
|
+
name: item.data[FS_PROPERTIES.name],
|
|
222
|
+
item
|
|
223
|
+
}));
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
#setupContent() {
|
|
227
|
+
if (!this.payload)
|
|
228
|
+
return;
|
|
229
|
+
switch (this.payload.mode) {
|
|
230
|
+
case 'upload': {
|
|
231
|
+
this.content = {
|
|
232
|
+
headline: this.translate.instant('yuv.app.drive.name.conflict.upload.headline'),
|
|
233
|
+
message: this.translate.instant('yuv.app.drive.name.conflict.upload.message'),
|
|
234
|
+
messageValid: this.translate.instant('yuv.app.drive.name.conflict.upload.messageValid'),
|
|
235
|
+
proceed: this.translate.instant('yuv.app.drive.name.conflict.upload.proceed')
|
|
236
|
+
};
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
239
|
+
case 'copy': {
|
|
240
|
+
this.content = {
|
|
241
|
+
headline: this.translate.instant('yuv.app.drive.name.conflict.copy.headline'),
|
|
242
|
+
message: this.translate.instant('yuv.app.drive.name.conflict.copy.message'),
|
|
243
|
+
messageValid: this.translate.instant('yuv.app.drive.name.conflict.copy.messageValid'),
|
|
244
|
+
proceed: this.translate.instant('yuv.app.drive.name.conflict.copy.proceed')
|
|
245
|
+
};
|
|
246
|
+
break;
|
|
247
|
+
}
|
|
248
|
+
case 'move': {
|
|
249
|
+
this.content = {
|
|
250
|
+
headline: this.translate.instant('yuv.app.drive.name.conflict.move.headline'),
|
|
251
|
+
message: this.translate.instant('yuv.app.drive.name.conflict.move.message'),
|
|
252
|
+
messageValid: this.translate.instant('yuv.app.drive.name.conflict.move.messageValid'),
|
|
253
|
+
proceed: this.translate.instant('yuv.app.drive.name.conflict.move.proceed')
|
|
254
|
+
};
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
ngOnInit() {
|
|
260
|
+
this.payload = this.#oRef.data;
|
|
261
|
+
this.existingFileNames = this.payload.existingFileNames;
|
|
262
|
+
this.invalidFileNames = this.payload.invalidFileNames;
|
|
263
|
+
this.#setupValidItems();
|
|
264
|
+
this.#setupContent();
|
|
265
|
+
}
|
|
266
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ResolveNameConflictsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
267
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: ResolveNameConflictsComponent, isStandalone: true, selector: "ymd-resolve-name-conflicts", ngImport: i0, template: "<h2>{{ content.headline }}</h2>\n<p>{{ content.message }}</p>\n\n<ul>\n @for (ef of existingFileNames; track $index) {\n <li>{{ ef }}</li>\n }\n</ul>\n\n@if (validItems.length) {\n <p>{{ content.messageValid }}</p>\n <ul>\n @for (f of validItems; track $index) {\n <li>{{ f.name }}</li>\n }\n </ul>\n}\n\n<footer>\n @if (validItems.length) {\n <button class=\"primary\" (click)=\"proceed()\">{{ content.proceed }}</button>\n }\n <button class=\"secondary\" (click)=\"cancel()\">{{ 'yuv.app.drive.name.conflict.cancel' | translate }}</button>\n</footer>\n", styles: ["@charset \"UTF-8\";:host{display:block;padding:var(--app-pane-padding);position:relative}:host .yuv-loader-linear{position:absolute;inset:0}:host h2{margin:0 0 2em;font-size:var(--font-title);font-weight:400}:host ul{font-weight:700;list-style:none;padding:0 1em}:host ul li{padding:.25rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host ul li:before{content:\"\\2022\";margin-inline-end:.5rem}:host footer{margin-block-start:calc(var(--app-pane-padding) * 2);display:flex;flex-flow:row-reverse;gap:calc(var(--app-pane-padding) / 4)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }] }); }
|
|
268
|
+
}
|
|
269
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ResolveNameConflictsComponent, decorators: [{
|
|
270
|
+
type: Component,
|
|
271
|
+
args: [{ selector: 'ymd-resolve-name-conflicts', standalone: true, imports: [CommonModule, TranslateModule], template: "<h2>{{ content.headline }}</h2>\n<p>{{ content.message }}</p>\n\n<ul>\n @for (ef of existingFileNames; track $index) {\n <li>{{ ef }}</li>\n }\n</ul>\n\n@if (validItems.length) {\n <p>{{ content.messageValid }}</p>\n <ul>\n @for (f of validItems; track $index) {\n <li>{{ f.name }}</li>\n }\n </ul>\n}\n\n<footer>\n @if (validItems.length) {\n <button class=\"primary\" (click)=\"proceed()\">{{ content.proceed }}</button>\n }\n <button class=\"secondary\" (click)=\"cancel()\">{{ 'yuv.app.drive.name.conflict.cancel' | translate }}</button>\n</footer>\n", styles: ["@charset \"UTF-8\";:host{display:block;padding:var(--app-pane-padding);position:relative}:host .yuv-loader-linear{position:absolute;inset:0}:host h2{margin:0 0 2em;font-size:var(--font-title);font-weight:400}:host ul{font-weight:700;list-style:none;padding:0 1em}:host ul li{padding:.25rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host ul li:before{content:\"\\2022\";margin-inline-end:.5rem}:host footer{margin-block-start:calc(var(--app-pane-padding) * 2);display:flex;flex-flow:row-reverse;gap:calc(var(--app-pane-padding) / 4)}\n"] }]
|
|
272
|
+
}] });
|
|
273
|
+
|
|
274
|
+
const getResolvedObjectConfigItem = (propertyName, instanceData) => {
|
|
275
|
+
const item = {
|
|
276
|
+
propertyName: propertyName,
|
|
277
|
+
value: instanceData[propertyName]
|
|
278
|
+
};
|
|
279
|
+
// Meta data are considered properties that start with the property name followed by an underscore.
|
|
280
|
+
// Organization fields for example have an additional property 'xyz_title' that contains the resolved
|
|
281
|
+
// name of a user while the value itself is the users ID.
|
|
282
|
+
const metaData = Object.keys(instanceData)
|
|
283
|
+
.filter((key) => key.startsWith(propertyName + '_'))
|
|
284
|
+
.map((key) => ({ [key.substring(key.indexOf('_') + 1)]: instanceData[key] }));
|
|
285
|
+
// If there are meta data properties, they'll be merged into a Record where the
|
|
286
|
+
// key is the property name without the underscore and the actual properties name.
|
|
287
|
+
// So { 'xyz_title': 'John Doe' } will be merged into { title: 'John Doe' }
|
|
288
|
+
if (metaData.length) {
|
|
289
|
+
const meta = metaData.reduce((acc, cur) => ({ ...acc, ...cur }), {});
|
|
290
|
+
item.meta = meta;
|
|
291
|
+
}
|
|
292
|
+
return item;
|
|
293
|
+
};
|
|
294
|
+
const mapToTileData = (objects) => {
|
|
295
|
+
return objects.map((dmsObject) => {
|
|
296
|
+
const sots = dmsObject.sots || [];
|
|
297
|
+
const tli = {
|
|
298
|
+
objectTypeId: dmsObject.objectTypeId,
|
|
299
|
+
id: dmsObject.id,
|
|
300
|
+
actions: undefined,
|
|
301
|
+
badges: undefined,
|
|
302
|
+
instanceData: dmsObject.data,
|
|
303
|
+
dmsObject,
|
|
304
|
+
title: { rendererType: 'text', propertyName: BaseObjectTypeField.PARENT_OBJECT_TYPE_ID, value: dmsObject.data[FS_PROPERTIES.name] }
|
|
305
|
+
};
|
|
306
|
+
tli.icon = { rendererType: 'icon', propertyName: BaseObjectTypeField.OBJECT_TYPE_ID, value: BaseObjectTypeField.OBJECT_TYPE_ID };
|
|
307
|
+
return tli;
|
|
308
|
+
});
|
|
309
|
+
};
|
|
310
|
+
const mapSearchResult = (res) => {
|
|
311
|
+
return mapToTileData(res);
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
class DriveService {
|
|
315
|
+
#actionsService;
|
|
316
|
+
#eventService;
|
|
317
|
+
#router;
|
|
318
|
+
#dmsService;
|
|
319
|
+
#searchService;
|
|
320
|
+
#overlay;
|
|
321
|
+
#backend;
|
|
322
|
+
#clipboardService;
|
|
323
|
+
#eventSource;
|
|
324
|
+
#defaultSort;
|
|
325
|
+
constructor() {
|
|
326
|
+
this.#actionsService = inject(ActionsService);
|
|
327
|
+
this.#eventService = inject(EventService);
|
|
328
|
+
this.#router = inject(Router);
|
|
329
|
+
this.#dmsService = inject(DmsService);
|
|
330
|
+
this.#searchService = inject(SearchService);
|
|
331
|
+
this.#overlay = inject(YvcOverlayService);
|
|
332
|
+
this.#backend = inject(BackendService);
|
|
333
|
+
this.#clipboardService = inject(ClipboardService);
|
|
334
|
+
this.MAX_DEPTH = inject(DRIVE_APP_BREADCRUMB_MAX_DEPTH);
|
|
335
|
+
this.breadcrumbCache = new Map();
|
|
336
|
+
this.#eventSource = new Subject();
|
|
337
|
+
this.events$ = this.#eventSource.asObservable();
|
|
338
|
+
this.#defaultSort = {
|
|
339
|
+
property: FS_PROPERTIES.name,
|
|
340
|
+
order: 'asc'
|
|
341
|
+
};
|
|
342
|
+
this.initialState = {
|
|
343
|
+
currentFolder: null,
|
|
344
|
+
query: null,
|
|
345
|
+
queryTitle: null,
|
|
346
|
+
selection: [],
|
|
347
|
+
actions: [],
|
|
348
|
+
busy: false,
|
|
349
|
+
sort: this.#defaultSort,
|
|
350
|
+
breadcrumb: {
|
|
351
|
+
loading: false,
|
|
352
|
+
partial: false,
|
|
353
|
+
items: [],
|
|
354
|
+
folder: null
|
|
355
|
+
},
|
|
356
|
+
versions: {
|
|
357
|
+
versionsList: [],
|
|
358
|
+
selectedVersion: null
|
|
359
|
+
},
|
|
360
|
+
selectedDmsObject: null
|
|
361
|
+
};
|
|
362
|
+
this.state$ = signalState(this.initialState);
|
|
363
|
+
this.breadcrumbFolderPreview = this.state$.breadcrumb.folder;
|
|
364
|
+
this._busyTaskCount = 0;
|
|
365
|
+
this._defaultRibbonActions = [];
|
|
366
|
+
this.#router.events
|
|
367
|
+
.pipe(takeUntilDestroyed(), filter((e) => this.state$.selection().length > 0 && e instanceof NavigationStart))
|
|
368
|
+
// clear selection on route chnages
|
|
369
|
+
.subscribe({ next: () => this.setSelection([]) });
|
|
370
|
+
this.#eventService.on(YuvEventType.DMS_OBJECT_UPDATED).subscribe((e) => {
|
|
371
|
+
// check if current selection contains the updated object
|
|
372
|
+
const dmsObject = e.data;
|
|
373
|
+
const selection = this.state$.selection();
|
|
374
|
+
const matchIdx = selection.findIndex((o) => o.id === dmsObject.id);
|
|
375
|
+
if (matchIdx !== -1) {
|
|
376
|
+
// update the object in the selection
|
|
377
|
+
selection[matchIdx] = dmsObject;
|
|
378
|
+
patchState(this.state$, { selection: [...selection] });
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
this.#eventService
|
|
382
|
+
.on(YuvEventType.DMS_OBJECT_DELETED, YuvEventType.DMS_OBJECT_CREATED, YuvEventType.DMS_OBJECTS_MOVED)
|
|
383
|
+
.subscribe(() => this.emitEvent(DRIVE_EVENT.refresh));
|
|
384
|
+
}
|
|
385
|
+
#mapedCurrentFolder() {
|
|
386
|
+
return this.state$.currentFolder() === DRIVE_ROOT_FOLDER_ID ? null : this.state$.currentFolder();
|
|
387
|
+
}
|
|
388
|
+
emitEvent(evt) {
|
|
389
|
+
this.#eventSource.next(evt);
|
|
390
|
+
}
|
|
391
|
+
setBusy(busy) {
|
|
392
|
+
if (busy)
|
|
393
|
+
this._busyTaskCount++;
|
|
394
|
+
else if (this._busyTaskCount > 0)
|
|
395
|
+
this._busyTaskCount--;
|
|
396
|
+
patchState(this.state$, { busy: this._busyTaskCount !== 0 });
|
|
397
|
+
}
|
|
398
|
+
setSelection(o) {
|
|
399
|
+
patchState(this.state$, { selection: o });
|
|
400
|
+
this._getActions();
|
|
401
|
+
}
|
|
402
|
+
updateQuery(query, queryTitle = null) {
|
|
403
|
+
patchState(this.state$, {
|
|
404
|
+
query: this.applyFolderListSearchConditions(query),
|
|
405
|
+
queryTitle: queryTitle
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
setSort(property, order) {
|
|
409
|
+
const stateQuery = this.state$.query();
|
|
410
|
+
if (stateQuery) {
|
|
411
|
+
const clonedQueryState = structuredClone(stateQuery);
|
|
412
|
+
// TODO: remove if folders should stay on top
|
|
413
|
+
clonedQueryState.sort = [];
|
|
414
|
+
const sort = property ? { property, order } : { ...this.#defaultSort, order };
|
|
415
|
+
patchState(this.state$, { query: clonedQueryState, sort });
|
|
416
|
+
this.applyFolderListSearchConditions(clonedQueryState, !property);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
updateCurrentFolder(currentFolderID) {
|
|
420
|
+
patchState(this.state$, { currentFolder: currentFolderID || null });
|
|
421
|
+
}
|
|
422
|
+
#copyToFolder(objects, folderId, options, validateNames = true) {
|
|
423
|
+
return validateNames
|
|
424
|
+
? this.validateNames(objects.filter((o) => o.sots.includes(FS_SOTS.object)).map((f) => f.data[FS_PROPERTIES.name]), folderId).pipe(switchMap((res) => {
|
|
425
|
+
if (res.existingFileNames?.length || res.invalidFileNames?.length) {
|
|
426
|
+
this.#resolveNameConflicts({
|
|
427
|
+
existingFileNames: res.existingFileNames,
|
|
428
|
+
invalidFileNames: res.invalidFileNames,
|
|
429
|
+
mode: 'copy',
|
|
430
|
+
items: objects
|
|
431
|
+
});
|
|
432
|
+
return of([]);
|
|
433
|
+
}
|
|
434
|
+
else
|
|
435
|
+
return this.#dmsService.copyDmsObjects(folderId, objects, options);
|
|
436
|
+
}))
|
|
437
|
+
: this.#dmsService.copyDmsObjects(folderId, objects, options);
|
|
438
|
+
}
|
|
439
|
+
#moveToFolder(objects, folderId, options, validateNames = true) {
|
|
440
|
+
return validateNames
|
|
441
|
+
? this.validateNames(objects.filter((o) => o.sots.includes(FS_SOTS.object)).map((f) => f.data[FS_PROPERTIES.name]), folderId).pipe(switchMap((res) => {
|
|
442
|
+
if (res.existingFileNames?.length || res.invalidFileNames?.length) {
|
|
443
|
+
console.log('VALIDATION: ', { res });
|
|
444
|
+
this.#resolveNameConflicts({
|
|
445
|
+
existingFileNames: res.existingFileNames,
|
|
446
|
+
invalidFileNames: res.invalidFileNames,
|
|
447
|
+
mode: 'move',
|
|
448
|
+
items: objects
|
|
449
|
+
});
|
|
450
|
+
return of([]);
|
|
451
|
+
}
|
|
452
|
+
else
|
|
453
|
+
return this.#dmsService.moveDmsObjects(folderId, objects, options);
|
|
454
|
+
}))
|
|
455
|
+
: this.#dmsService.moveDmsObjects(folderId, objects, options);
|
|
456
|
+
}
|
|
457
|
+
copyToCurrentFolder(objects, validateNames = true) {
|
|
458
|
+
const options = { waitForSearchConsistency: true };
|
|
459
|
+
return this.#copyToFolder(objects, this.#mapedCurrentFolder(), options, validateNames);
|
|
460
|
+
}
|
|
461
|
+
moveToCurrentFolder(objects, validateNames = true) {
|
|
462
|
+
const options = { waitForSearchConsistency: true };
|
|
463
|
+
return this.#moveToFolder(objects, this.#mapedCurrentFolder(), options, validateNames);
|
|
464
|
+
}
|
|
465
|
+
#resolveNameConflicts(payload) {
|
|
466
|
+
this.#overlay.open(ResolveNameConflictsComponent, payload, {
|
|
467
|
+
maxWidth: '400px'
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
pasteFromClipboard(destinationObject) {
|
|
471
|
+
const cd = this.#clipboardService.getClipboardData(APP_ID);
|
|
472
|
+
const destination = destinationObject?.isFolder ? destinationObject.id : this.#mapedCurrentFolder();
|
|
473
|
+
return (cd && cd.objects && cd.objects.length > 0
|
|
474
|
+
? cd?.mode === DRIVE_ACTION_MODE.CUT
|
|
475
|
+
? this.#moveToFolder(cd.objects || [], destination, { waitForSearchConsistency: true }, true)
|
|
476
|
+
: cd?.mode === DRIVE_ACTION_MODE.COPY
|
|
477
|
+
? this.#copyToFolder(cd.objects || [], destination, { waitForSearchConsistency: true }, true)
|
|
478
|
+
: of(null)
|
|
479
|
+
: of(null)).pipe(tap((res) => {
|
|
480
|
+
res && this.emitEvent(DRIVE_EVENT.refresh);
|
|
481
|
+
this.#clipboardService.clear();
|
|
482
|
+
}));
|
|
483
|
+
}
|
|
484
|
+
checkNamesAndUpload(files, data) {
|
|
485
|
+
return this.validateNames(files.map((f) => f.name), this.#mapedCurrentFolder()).pipe(switchMap((res) => {
|
|
486
|
+
if (res.existingFileNames?.length || res.invalidFileNames?.length) {
|
|
487
|
+
const resPayload = {
|
|
488
|
+
existingFileNames: res.existingFileNames,
|
|
489
|
+
invalidFileNames: res.invalidFileNames,
|
|
490
|
+
mode: 'upload',
|
|
491
|
+
items: files,
|
|
492
|
+
data
|
|
493
|
+
};
|
|
494
|
+
this.#overlay.open(ResolveNameConflictsComponent, resPayload);
|
|
495
|
+
return of([]);
|
|
496
|
+
}
|
|
497
|
+
else
|
|
498
|
+
return this.upload(files, data);
|
|
499
|
+
}));
|
|
500
|
+
}
|
|
501
|
+
uploadContent(objectId, file) {
|
|
502
|
+
return this.#dmsService.uploadContent(objectId, file);
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Uploads files to the current folder
|
|
506
|
+
* @param files files to be uploaded
|
|
507
|
+
* @param data additional data to be applied to the object
|
|
508
|
+
*/
|
|
509
|
+
upload(files, data) {
|
|
510
|
+
return forkJoin(files.map((file) => {
|
|
511
|
+
const uploadData = data || {};
|
|
512
|
+
// apply filesystem SOT
|
|
513
|
+
const sots = uploadData[BaseObjectTypeField.SECONDARY_OBJECT_TYPE_IDS] || [];
|
|
514
|
+
uploadData[BaseObjectTypeField.SECONDARY_OBJECT_TYPE_IDS] = [...sots, FS_SOTS.object];
|
|
515
|
+
// setup the name to be the filename
|
|
516
|
+
uploadData[FS_PROPERTIES.name] = file.name;
|
|
517
|
+
const cf = this.#mapedCurrentFolder();
|
|
518
|
+
if (cf && cf !== DRIVE_ROOT_FOLDER_ID)
|
|
519
|
+
uploadData[BaseObjectTypeField.PARENT_ID] = cf;
|
|
520
|
+
return this.#dmsService.createDmsObject(SystemType.DOCUMENT, uploadData, [file], file.name).pipe(map((res) => ({ id: res[0] })), catchError((e) => of({ error: this.#mapCreateError(e) })));
|
|
521
|
+
}));
|
|
522
|
+
}
|
|
523
|
+
createFolder(name) {
|
|
524
|
+
const parentID = this.#mapedCurrentFolder();
|
|
525
|
+
const data = {};
|
|
526
|
+
data[FS_PROPERTIES.name] = name;
|
|
527
|
+
// apply filesystem SOT
|
|
528
|
+
data[BaseObjectTypeField.SECONDARY_OBJECT_TYPE_IDS] = [FS_SOTS.object];
|
|
529
|
+
if (parentID && parentID !== DRIVE_ROOT_FOLDER_ID)
|
|
530
|
+
data[BaseObjectTypeField.PARENT_ID] = parentID;
|
|
531
|
+
return this.#dmsService.createDmsObject(APP_SCHEMA.types.folder.objectType || '', data, []).pipe(map((res) => ({ id: res[0] })), catchError((e) => of({ error: this.#mapCreateError(e) })));
|
|
532
|
+
}
|
|
533
|
+
#mapCreateError(e) {
|
|
534
|
+
let error = 'default';
|
|
535
|
+
const ec = e.error.serviceErrorCode;
|
|
536
|
+
if (ec === 99999) {
|
|
537
|
+
const iec = e.error.innerError?.serviceErrorCode;
|
|
538
|
+
if (iec === 11000)
|
|
539
|
+
error = 'nameExists';
|
|
540
|
+
}
|
|
541
|
+
return error;
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* Checks for existing names and invalid characters
|
|
545
|
+
* @param name The name to be checked
|
|
546
|
+
* @param parentId The parent folder (will be 'root' if not provided)
|
|
547
|
+
* @returns already existing names
|
|
548
|
+
*/
|
|
549
|
+
validateNames(names, parentId) {
|
|
550
|
+
console.log({ names, parentId });
|
|
551
|
+
if (parentId === DRIVE_ROOT_FOLDER_ID)
|
|
552
|
+
parentId = undefined;
|
|
553
|
+
const dvp = {
|
|
554
|
+
app: 'osdrive',
|
|
555
|
+
fileNames: names,
|
|
556
|
+
targetFolderId: parentId || undefined
|
|
557
|
+
};
|
|
558
|
+
return this.#backend.post('/dms/objects/validate', dvp).pipe(catchError((res) => of(res.error)));
|
|
559
|
+
}
|
|
560
|
+
getDefaultRibbonActions() {
|
|
561
|
+
if (!this._defaultRibbonActions.length) {
|
|
562
|
+
//[BASE_ACTION.download, BASE_ACTION.delete, 'app.drive.action.rename', BASE_ACTION.copy, BASE_ACTION.cut]
|
|
563
|
+
Object.values({ ...BASE_ACTION, rename: 'app.drive.action.rename' }).forEach((id) => {
|
|
564
|
+
const a = this.#actionsService.getActionById(id, ACTION_CONTEXT);
|
|
565
|
+
if (a)
|
|
566
|
+
this._defaultRibbonActions.push(a);
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
return this._defaultRibbonActions;
|
|
570
|
+
}
|
|
571
|
+
_getActions() {
|
|
572
|
+
this.setBusy(true);
|
|
573
|
+
this.#actionsService
|
|
574
|
+
.getActions(this.state$.selection(), {
|
|
575
|
+
context: ACTION_CONTEXT
|
|
576
|
+
})
|
|
577
|
+
.subscribe((actions) => {
|
|
578
|
+
patchState(this.state$, { actions });
|
|
579
|
+
})
|
|
580
|
+
.add(() => this.setBusy(false));
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Apply search conditions regarding folder listings
|
|
584
|
+
* @param q
|
|
585
|
+
*/
|
|
586
|
+
applyFolderListSearchConditions(q, addBaseTypeId = true) {
|
|
587
|
+
// folders first
|
|
588
|
+
if (!q.sort)
|
|
589
|
+
q.sort = [];
|
|
590
|
+
addBaseTypeId &&
|
|
591
|
+
q.sort.push({
|
|
592
|
+
field: BaseObjectTypeField.BASE_TYPE_ID,
|
|
593
|
+
order: 'desc'
|
|
594
|
+
});
|
|
595
|
+
q = this.applyBasicSearchConditions(q);
|
|
596
|
+
return q;
|
|
597
|
+
}
|
|
598
|
+
applyBasicSearchConditions(q) {
|
|
599
|
+
q.fields = [
|
|
600
|
+
BaseObjectTypeField.OBJECT_ID,
|
|
601
|
+
BaseObjectTypeField.MODIFICATION_DATE,
|
|
602
|
+
BaseObjectTypeField.MODIFIED_BY,
|
|
603
|
+
ContentStreamField.FILENAME,
|
|
604
|
+
ContentStreamField.MIME_TYPE,
|
|
605
|
+
ContentStreamField.ID,
|
|
606
|
+
ContentStreamField.LENGTH
|
|
607
|
+
];
|
|
608
|
+
if (!q.types || !q.types.includes(FS_SOTS.object))
|
|
609
|
+
q.types = [...(q.types || []), FS_SOTS.object];
|
|
610
|
+
// q.sortOptions.push(new SortOption(BaseObjectTypeField.BASE_TYPE_ID, 'desc'));
|
|
611
|
+
const sort = this.state$.sort() || this.#defaultSort;
|
|
612
|
+
if (!q.sort)
|
|
613
|
+
q.sort = [];
|
|
614
|
+
q.sort.push({
|
|
615
|
+
field: sort.property,
|
|
616
|
+
order: sort.order
|
|
617
|
+
});
|
|
618
|
+
q.includePermissions = true;
|
|
619
|
+
// new SortOption(sort.property, sort.order));
|
|
620
|
+
return q;
|
|
621
|
+
}
|
|
622
|
+
resolveFilesState(id) {
|
|
623
|
+
return this.getFolderHierarchy(id);
|
|
624
|
+
}
|
|
625
|
+
getFolderHierarchy(folderId) {
|
|
626
|
+
patchState(this.state$, {
|
|
627
|
+
breadcrumb: {
|
|
628
|
+
...this.initialState.breadcrumb,
|
|
629
|
+
loading: true
|
|
630
|
+
}
|
|
631
|
+
});
|
|
632
|
+
return folderId === DRIVE_ROOT_FOLDER_ID
|
|
633
|
+
? of([])
|
|
634
|
+
: this.#fetchFolder(folderId, 0, this.MAX_DEPTH).pipe(tap((res) => {
|
|
635
|
+
let items = [];
|
|
636
|
+
if (res.items.length > 0) {
|
|
637
|
+
items = [...items, ...res.items];
|
|
638
|
+
}
|
|
639
|
+
patchState(this.state$, {
|
|
640
|
+
breadcrumb: {
|
|
641
|
+
...this.initialState.breadcrumb,
|
|
642
|
+
partial: res.partial,
|
|
643
|
+
loading: false,
|
|
644
|
+
items
|
|
645
|
+
}
|
|
646
|
+
});
|
|
647
|
+
}), map((res) => res.items));
|
|
648
|
+
}
|
|
649
|
+
#fetchFolder(folderId, depth, maxDepth) {
|
|
650
|
+
if (depth >= maxDepth)
|
|
651
|
+
return of({ partial: true, items: [] });
|
|
652
|
+
const cachedFolder = this.breadcrumbCache.get(folderId);
|
|
653
|
+
if (cachedFolder) {
|
|
654
|
+
return cachedFolder.parentId
|
|
655
|
+
? this.#fetchFolder(cachedFolder.parentId, depth + 1, maxDepth).pipe(map((parentFolders) => ({
|
|
656
|
+
partial: parentFolders.partial,
|
|
657
|
+
items: [...parentFolders.items, { name: cachedFolder.name, id: cachedFolder.id }]
|
|
658
|
+
})))
|
|
659
|
+
: of({
|
|
660
|
+
partial: false,
|
|
661
|
+
items: [{ name: cachedFolder.name, id: cachedFolder.id }]
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
return this.#dmsService.getDmsObject(folderId).pipe(map((folder) => {
|
|
665
|
+
const currentFolder = {
|
|
666
|
+
name: folder.data[FS_PROPERTIES.name],
|
|
667
|
+
id: folder.data[BaseObjectTypeField.OBJECT_ID],
|
|
668
|
+
parentId: folder.parentId
|
|
669
|
+
};
|
|
670
|
+
// this.breadcrumbCache.set(folder.id, currentFolder);
|
|
671
|
+
return currentFolder;
|
|
672
|
+
}), switchMap((folder) => {
|
|
673
|
+
if (!folder.parentId) {
|
|
674
|
+
return of({
|
|
675
|
+
partial: false,
|
|
676
|
+
items: [{ name: folder.name, id: folder.id }]
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
return this.#fetchFolder(folder.parentId, depth + 1, maxDepth).pipe(map((parentFolders) => ({
|
|
680
|
+
partial: parentFolders.partial,
|
|
681
|
+
items: [...parentFolders.items, { name: folder.name, id: folder.id }]
|
|
682
|
+
})));
|
|
683
|
+
}));
|
|
684
|
+
}
|
|
685
|
+
getVersions(id) {
|
|
686
|
+
patchState(this.state$, { busy: true });
|
|
687
|
+
return this.#dmsService.getDmsObjectVersions(id).pipe(tap((versions) => {
|
|
688
|
+
patchState(this.state$, {
|
|
689
|
+
busy: false,
|
|
690
|
+
versions: {
|
|
691
|
+
versionsList: mapSearchResult(versions),
|
|
692
|
+
selectedVersion: this.state$.versions().selectedVersion
|
|
693
|
+
}
|
|
694
|
+
});
|
|
695
|
+
}));
|
|
696
|
+
}
|
|
697
|
+
getSelectedDmsObject(id) {
|
|
698
|
+
return this.#dmsService.getDmsObject(id).pipe(tap((dmsObject) => patchState(this.state$, {
|
|
699
|
+
selectedDmsObject: dmsObject,
|
|
700
|
+
versions: {
|
|
701
|
+
versionsList: this.state$.versions.versionsList(),
|
|
702
|
+
selectedVersion: [dmsObject]
|
|
703
|
+
}
|
|
704
|
+
})));
|
|
705
|
+
}
|
|
706
|
+
setSelectedVersion(version) {
|
|
707
|
+
this.setBusy(true);
|
|
708
|
+
return this.#dmsService.getDmsObjectVersion(version.dmsObject.id, version.dmsObject.version).pipe(tap((res) => patchState(this.state$, {
|
|
709
|
+
versions: {
|
|
710
|
+
versionsList: this.state$.versions.versionsList(),
|
|
711
|
+
selectedVersion: [res]
|
|
712
|
+
}
|
|
713
|
+
})), tap(() => this.setBusy(false)));
|
|
714
|
+
}
|
|
715
|
+
setNewVersion(version) {
|
|
716
|
+
patchState(this.state$, { busy: true });
|
|
717
|
+
const selectedVersion = this.state$.versions.selectedVersion();
|
|
718
|
+
if (selectedVersion) {
|
|
719
|
+
const versionNumber = version ?? selectedVersion[0].version;
|
|
720
|
+
return this.#dmsService.restoreDmsObject(selectedVersion[0].id, versionNumber).pipe(switchMap((object) => this.getVersions(object.id)));
|
|
721
|
+
}
|
|
722
|
+
return of(null);
|
|
723
|
+
}
|
|
724
|
+
clearVersions() {
|
|
725
|
+
patchState(this.state$, { versions: this.initialState.versions });
|
|
726
|
+
}
|
|
727
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DriveService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
728
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DriveService, providedIn: 'root' }); }
|
|
729
|
+
}
|
|
730
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DriveService, decorators: [{
|
|
731
|
+
type: Injectable,
|
|
732
|
+
args: [{
|
|
733
|
+
providedIn: 'root'
|
|
734
|
+
}]
|
|
735
|
+
}], ctorParameters: () => [] });
|
|
736
|
+
|
|
737
|
+
class RenameValidator {
|
|
738
|
+
static createValidator(driveService) {
|
|
739
|
+
return (control) => {
|
|
740
|
+
return timer(500).pipe(switchMap$1(() => {
|
|
741
|
+
return control.value['name'] !== control.value['_initialName']
|
|
742
|
+
? driveService.validateNames([control.value['name']], driveService.state$.currentFolder()).pipe(map$1((result) => {
|
|
743
|
+
let res = null;
|
|
744
|
+
if (result.existingFileNames.length) {
|
|
745
|
+
res = { nameAlreadyExists: true };
|
|
746
|
+
}
|
|
747
|
+
else if (result.invalidFileNames?.length) {
|
|
748
|
+
res = { invalidFileNames: true };
|
|
749
|
+
}
|
|
750
|
+
return res;
|
|
751
|
+
}))
|
|
752
|
+
: of(null);
|
|
753
|
+
}));
|
|
754
|
+
};
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
/**
|
|
759
|
+
*
|
|
760
|
+
* @param breadkrumbMaxDepth default 3
|
|
761
|
+
* @returns
|
|
762
|
+
*/
|
|
763
|
+
const provideDrive = (breadkrumbMaxDepth = 3) => {
|
|
764
|
+
return { provide: DRIVE_APP_BREADCRUMB_MAX_DEPTH, useValue: breadkrumbMaxDepth };
|
|
765
|
+
};
|
|
766
|
+
|
|
767
|
+
class ObjectNameComponent {
|
|
768
|
+
constructor() {
|
|
769
|
+
this.#fb = inject(FormBuilder);
|
|
770
|
+
this.#drive = inject(DriveService);
|
|
771
|
+
this.busy = false;
|
|
772
|
+
this.headline = input();
|
|
773
|
+
this.submitButton = input.required();
|
|
774
|
+
this.cancelButton = input('');
|
|
775
|
+
this.isFile = input(false);
|
|
776
|
+
this.isRename = input(false);
|
|
777
|
+
this.item = input();
|
|
778
|
+
this.disabled = input(false);
|
|
779
|
+
this.#disabledEffect = effect(() => {
|
|
780
|
+
const d = this.disabled();
|
|
781
|
+
d ? this.nameForm.get('name')?.disable() : this.nameForm.get('name')?.enable();
|
|
782
|
+
});
|
|
783
|
+
this.#itemFormEffect = effect(() => this.item() && this.#setupForm(this.item()?.data));
|
|
784
|
+
this.nameChange = output();
|
|
785
|
+
this.onClose = output();
|
|
786
|
+
this.nameForm = this.#fb.group({
|
|
787
|
+
_initialName: [''],
|
|
788
|
+
name: ['', Validators.required]
|
|
789
|
+
}, {
|
|
790
|
+
asyncValidators: [RenameValidator.createValidator(this.#drive)]
|
|
791
|
+
});
|
|
792
|
+
}
|
|
793
|
+
#fb;
|
|
794
|
+
#drive;
|
|
795
|
+
#disabledEffect;
|
|
796
|
+
#itemFormEffect;
|
|
797
|
+
#setupForm(data) {
|
|
798
|
+
this.nameForm.patchValue({
|
|
799
|
+
_initialName: data ? data[FS_PROPERTIES.name] || '' : '',
|
|
800
|
+
name: data ? data[FS_PROPERTIES.name] || '' : ''
|
|
801
|
+
}, {
|
|
802
|
+
emitEvent: false
|
|
803
|
+
});
|
|
804
|
+
}
|
|
805
|
+
submitForm() {
|
|
806
|
+
this.nameChange.emit(this.nameForm.value.name);
|
|
807
|
+
}
|
|
808
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ObjectNameComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
809
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: ObjectNameComponent, isStandalone: true, selector: "ymd-object-name", inputs: { headline: { classPropertyName: "headline", publicName: "headline", isSignal: true, isRequired: false, transformFunction: null }, submitButton: { classPropertyName: "submitButton", publicName: "submitButton", isSignal: true, isRequired: true, transformFunction: null }, cancelButton: { classPropertyName: "cancelButton", publicName: "cancelButton", isSignal: true, isRequired: false, transformFunction: null }, isFile: { classPropertyName: "isFile", publicName: "isFile", isSignal: true, isRequired: false, transformFunction: null }, isRename: { classPropertyName: "isRename", publicName: "isRename", isSignal: true, isRequired: false, transformFunction: null }, item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { nameChange: "nameChange", onClose: "onClose" }, ngImport: i0, template: "<form [formGroup]=\"nameForm\" (ngSubmit)=\"submitForm()\">\n @if (headline() && headline()?.length) {\n <header>{{ headline() }}</header>\n }\n <main>\n <yuv-form-input [label]=\"'yuv.app.drive.property.name' | translate\" [required]=\"true\"> <yuv-string formControlName=\"name\"></yuv-string></yuv-form-input>\n @if (nameForm.hasError('nameAlreadyExists')) {\n <div class=\"error\">{{ 'yuv.app.drive.create.error.name.exist' | translate }}</div>\n }\n @if (nameForm.hasError('invalidFileNames')) {\n <div class=\"error\">{{ 'yuv.app.drive.create.error.name.invalid' | translate }}</div>\n }\n </main>\n\n <footer>\n <button class=\"primary\" type=\"submit\" [disabled]=\"disabled() || nameForm.invalid || busy || error\">{{ submitButton() }}</button>\n @if (cancelButton() && cancelButton().length) {\n <button class=\"secondary\" type=\"button\" (click)=\"onClose.emit()\" [disabled]=\"busy\">{{ cancelButton() }}</button>\n }\n </footer>\n</form>\n", styles: [":host header{font-size:var(--font-title)}:host main{padding:var(--app-pane-padding) 0}:host main .error{color:var(--text-color-caption);background-color:var(--panel-background-lightgrey);border:1px solid var(--panel-divider-color);border-radius:.25rem;padding:calc(var(--app-pane-padding) / 4) calc(var(--app-pane-padding) / 2);margin-block-start:calc(var(--app-pane-padding) / 2)}:host footer{display:flex;flex-flow:row-reverse;justify-content:end;align-items:center;gap:calc(var(--app-pane-padding) / 4)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: FormInputComponent, selector: "yuv-form-input", inputs: ["label", "tag", "description", "invalid", "disabled", "required"] }, { kind: "component", type: StringComponent, selector: "yuv-string", inputs: ["multiselect", "rows", "readonly", "autofocus", "classifications", "situation", "regex", "minLength", "maxLength"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }] }); }
|
|
810
|
+
}
|
|
811
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ObjectNameComponent, decorators: [{
|
|
812
|
+
type: Component,
|
|
813
|
+
args: [{ selector: 'ymd-object-name', standalone: true, imports: [CommonModule, ReactiveFormsModule, FormInputComponent, StringComponent, TranslateModule], template: "<form [formGroup]=\"nameForm\" (ngSubmit)=\"submitForm()\">\n @if (headline() && headline()?.length) {\n <header>{{ headline() }}</header>\n }\n <main>\n <yuv-form-input [label]=\"'yuv.app.drive.property.name' | translate\" [required]=\"true\"> <yuv-string formControlName=\"name\"></yuv-string></yuv-form-input>\n @if (nameForm.hasError('nameAlreadyExists')) {\n <div class=\"error\">{{ 'yuv.app.drive.create.error.name.exist' | translate }}</div>\n }\n @if (nameForm.hasError('invalidFileNames')) {\n <div class=\"error\">{{ 'yuv.app.drive.create.error.name.invalid' | translate }}</div>\n }\n </main>\n\n <footer>\n <button class=\"primary\" type=\"submit\" [disabled]=\"disabled() || nameForm.invalid || busy || error\">{{ submitButton() }}</button>\n @if (cancelButton() && cancelButton().length) {\n <button class=\"secondary\" type=\"button\" (click)=\"onClose.emit()\" [disabled]=\"busy\">{{ cancelButton() }}</button>\n }\n </footer>\n</form>\n", styles: [":host header{font-size:var(--font-title)}:host main{padding:var(--app-pane-padding) 0}:host main .error{color:var(--text-color-caption);background-color:var(--panel-background-lightgrey);border:1px solid var(--panel-divider-color);border-radius:.25rem;padding:calc(var(--app-pane-padding) / 4) calc(var(--app-pane-padding) / 2);margin-block-start:calc(var(--app-pane-padding) / 2)}:host footer{display:flex;flex-flow:row-reverse;justify-content:end;align-items:center;gap:calc(var(--app-pane-padding) / 4)}\n"] }]
|
|
814
|
+
}] });
|
|
815
|
+
|
|
816
|
+
class RenameComponent {
|
|
817
|
+
constructor() {
|
|
818
|
+
this.overlayRef = inject(YvcOverlayRef);
|
|
819
|
+
this.#drive = inject(DriveService);
|
|
820
|
+
this.#dmsService = inject(DmsService);
|
|
821
|
+
this.item = this.overlayRef.data;
|
|
822
|
+
this.busy = signal(false);
|
|
823
|
+
}
|
|
824
|
+
#drive;
|
|
825
|
+
#dmsService;
|
|
826
|
+
rename(name) {
|
|
827
|
+
this.busy.set(true);
|
|
828
|
+
const data = {};
|
|
829
|
+
data[FS_PROPERTIES.name] = name;
|
|
830
|
+
this.#dmsService.updateDmsObject(this.item.id, data).subscribe({
|
|
831
|
+
next: () => {
|
|
832
|
+
this.overlayRef.close();
|
|
833
|
+
this.#drive.emitEvent(DRIVE_EVENT.refresh);
|
|
834
|
+
},
|
|
835
|
+
complete: () => this.busy.set(false)
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RenameComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
839
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: RenameComponent, isStandalone: true, selector: "ymd-rename", host: { properties: { "class.busy": "busy()" } }, ngImport: i0, template: "<div class=\"yuv-loader-linear\"></div>\n<ymd-object-name\n [item]=\"item\"\n [isRename]=\"true\"\n [isFile]=\"!item.isFolder\"\n [headline]=\"'yuv.app.drive.action.rename.headline' | translate\"\n [submitButton]=\"'yuv.app.drive.action.rename.submit' | translate\"\n [cancelButton]=\"'yuv.app.drive.action.rename.cancel' | translate\"\n (nameChange)=\"rename($event)\"\n (onClose)=\"overlayRef.close()\"\n></ymd-object-name>\n", styles: [":host{display:block;position:relative}:host ymd-object-name{padding:var(--app-pane-padding);display:block}:host .yuv-loader-linear{position:absolute;inset-block-start:0;inset-inline-start:0;inset-inline-end:0}:host:not(.busy) .yuv-loader-linear{display:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: ObjectNameComponent, selector: "ymd-object-name", inputs: ["headline", "submitButton", "cancelButton", "isFile", "isRename", "item", "disabled"], outputs: ["nameChange", "onClose"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }] }); }
|
|
840
|
+
}
|
|
841
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RenameComponent, decorators: [{
|
|
842
|
+
type: Component,
|
|
843
|
+
args: [{ selector: 'ymd-rename', standalone: true, imports: [CommonModule, ObjectNameComponent, TranslateModule], host: {
|
|
844
|
+
'[class.busy]': 'busy()'
|
|
845
|
+
}, template: "<div class=\"yuv-loader-linear\"></div>\n<ymd-object-name\n [item]=\"item\"\n [isRename]=\"true\"\n [isFile]=\"!item.isFolder\"\n [headline]=\"'yuv.app.drive.action.rename.headline' | translate\"\n [submitButton]=\"'yuv.app.drive.action.rename.submit' | translate\"\n [cancelButton]=\"'yuv.app.drive.action.rename.cancel' | translate\"\n (nameChange)=\"rename($event)\"\n (onClose)=\"overlayRef.close()\"\n></ymd-object-name>\n", styles: [":host{display:block;position:relative}:host ymd-object-name{padding:var(--app-pane-padding);display:block}:host .yuv-loader-linear{position:absolute;inset-block-start:0;inset-inline-start:0;inset-inline-end:0}:host:not(.busy) .yuv-loader-linear{display:none}\n"] }]
|
|
846
|
+
}] });
|
|
847
|
+
|
|
848
|
+
class RenameAction {
|
|
849
|
+
constructor() {
|
|
850
|
+
this.translate = inject(TranslateService$1);
|
|
851
|
+
this.overlay = inject(YvcOverlayService);
|
|
852
|
+
this.id = 'app.drive.action.rename';
|
|
853
|
+
this.label = this.translate.instant('yuv.app.drive.action.rename.label');
|
|
854
|
+
this.description = this.translate.instant('yuv.app.drive.action.rename.description');
|
|
855
|
+
this.priority = 2;
|
|
856
|
+
this.icon = '<svg xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 -960 960 960" width="20px" fill="#e8eaed"><path d="M480.28-96Q401-96 331-126t-122.5-82.5Q156-261 126-330.96t-30-149.5Q96-560 126-629.5q30-69.5 82.5-122T330.96-834q69.96-30 149.5-30t149.04 30q69.5 30 122 82.5T834-629.28q30 69.73 30 149Q864-401 834-331t-82.5 122.5Q699-156 629.28-126q-69.73 30-149 30Zm-.28-72q130 0 221-91t91-221q0-130-91-221t-221-91q-130 0-221 91t-91 221q0 130 91 221t221 91ZM336-336v-113l210-209q7.26-7.41 16.13-10.71Q571-672 579.76-672q9.55 0 18.31 3.5Q606.83-665 614-658l44 45q6.59 7.26 10.29 16.13Q672-588 672-579.24t-3.29 17.92q-3.3 9.15-10.71 16.32L449-336H336Zm288-243-45-45 45 45ZM384-384h45l115-115-22-23-22-22-116 115v45Zm138-138-22-22 44 45-22-23Z"/></svg>';
|
|
857
|
+
this.group = 'common';
|
|
858
|
+
this.range = SelectionRange.SINGLE_SELECT;
|
|
859
|
+
this.supports = {};
|
|
860
|
+
}
|
|
861
|
+
isExecutable(selection) {
|
|
862
|
+
return of(selection?.length === 1 && !!selection[0].permissions?.writeIndexData);
|
|
863
|
+
}
|
|
864
|
+
run(selection) {
|
|
865
|
+
this.overlay.open(RenameComponent, selection[0], {
|
|
866
|
+
width: '400px',
|
|
867
|
+
maxWidth: '90vw',
|
|
868
|
+
});
|
|
869
|
+
return of(true);
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
class PasteAction extends AbstractContextAction {
|
|
874
|
+
constructor() {
|
|
875
|
+
super(...arguments);
|
|
876
|
+
this.translate = inject(TranslateService);
|
|
877
|
+
this.#clipboardService = inject(ClipboardService);
|
|
878
|
+
this.#drive = inject(DriveService);
|
|
879
|
+
this.#route = inject(ActivatedRoute);
|
|
880
|
+
this.id = 'app.drive.action.paste';
|
|
881
|
+
this.label = this.translate.instant('yuv.app.drive.action.paste.label');
|
|
882
|
+
this.description = this.translate.instant('yuv.app.drive.action.paste.description');
|
|
883
|
+
this.priority = 2;
|
|
884
|
+
this.icon = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#5f6368" viewBox="0 -960 960 960"><path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h167q11-35 43-57.5t70-22.5q40 0 71.5 22.5T594-840h166q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560h-80v120H280v-120h-80v560Zm280-560q17 0 28.5-11.5T520-800q0-17-11.5-28.5T480-840q-17 0-28.5 11.5T440-800q0 17 11.5 28.5T480-760Z"/></svg>';
|
|
885
|
+
this.group = 'common';
|
|
886
|
+
this.range = SelectionRange.SINGLE_SELECT;
|
|
887
|
+
this.supports = {};
|
|
888
|
+
}
|
|
889
|
+
#clipboardService;
|
|
890
|
+
#drive;
|
|
891
|
+
#route;
|
|
892
|
+
isExecutable(items) {
|
|
893
|
+
const canWrite = !!items[0]?.permissions?.writeIndexData;
|
|
894
|
+
const cd = this.#clipboardService.getClipboardData(APP_ID);
|
|
895
|
+
return of(canWrite && !!cd?.objects && cd.objects.length > 0);
|
|
896
|
+
}
|
|
897
|
+
run(items) {
|
|
898
|
+
this.#drive.setBusy(true);
|
|
899
|
+
this.#drive
|
|
900
|
+
.pasteFromClipboard(items[0])
|
|
901
|
+
.pipe(finalize(() => this.#drive.setBusy(false)))
|
|
902
|
+
.subscribe();
|
|
903
|
+
return of(true);
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
class UpdateContentAction extends AbstractContextAction {
|
|
908
|
+
constructor() {
|
|
909
|
+
super(...arguments);
|
|
910
|
+
this.translate = inject(TranslateService$1);
|
|
911
|
+
this.#router = inject(Router);
|
|
912
|
+
this.#drive = inject(DriveService);
|
|
913
|
+
this.#document = inject(DOCUMENT);
|
|
914
|
+
this.id = 'app.drive.action.new.content.version';
|
|
915
|
+
this.label = this.translate.instant('yuv.app.drive.action.new.version');
|
|
916
|
+
this.description = this.translate.instant('yuv.app.drive.action.new.version.description');
|
|
917
|
+
this.priority = 2;
|
|
918
|
+
this.icon = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#5f6368" viewBox="0 -960 960 960"><path d="M500-520h80v-80h80v-80h-80v-80h-80v80h-80v80h80v80Zm-80 160h240v-80H420v80ZM320-200q-33 0-56.5-23.5T240-280v-560q0-33 23.5-56.5T320-920h280l240 240v400q0 33-23.5 56.5T760-200H320Zm0-80h440v-360L560-840H320v560ZM160-40q-33 0-56.5-23.5T80-120v-560h80v560h440v80H160Zm160-240v-560 560Z"/></svg>';
|
|
919
|
+
this.group = 'common';
|
|
920
|
+
this.range = SelectionRange.SINGLE_SELECT;
|
|
921
|
+
this.supports = {};
|
|
922
|
+
}
|
|
923
|
+
#router;
|
|
924
|
+
#drive;
|
|
925
|
+
#document;
|
|
926
|
+
isExecutable(selection) {
|
|
927
|
+
const selected = selection[0];
|
|
928
|
+
const canWrite = !!selected?.permissions?.writeContent;
|
|
929
|
+
return of(canWrite && selection.length === 1 && !selected.isFolder);
|
|
930
|
+
}
|
|
931
|
+
run(selection) {
|
|
932
|
+
if (!selection[0].isFolder) {
|
|
933
|
+
const fileInput = this.#document.createElement('input');
|
|
934
|
+
fileInput.type = 'file';
|
|
935
|
+
fileInput.multiple = false;
|
|
936
|
+
fileInput.onchange = (e) => {
|
|
937
|
+
this.#drive.setBusy(true);
|
|
938
|
+
const file = e.target.files?.[0];
|
|
939
|
+
file &&
|
|
940
|
+
this.#drive
|
|
941
|
+
.uploadContent(selection[0].id, file)
|
|
942
|
+
.pipe(finalize(() => this.#drive.setBusy(false)))
|
|
943
|
+
.subscribe();
|
|
944
|
+
};
|
|
945
|
+
fileInput.click();
|
|
946
|
+
fileInput.remove();
|
|
947
|
+
}
|
|
948
|
+
return of(true);
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
class CopyLinkAction extends AbstractContextAction {
|
|
953
|
+
constructor() {
|
|
954
|
+
super(...arguments);
|
|
955
|
+
this.translate = inject(TranslateService$1);
|
|
956
|
+
this.#notification = inject(NotificationService);
|
|
957
|
+
this.#shell = inject(ShellService);
|
|
958
|
+
this.id = 'app.drive.action.copy-link';
|
|
959
|
+
this.label = this.translate.instant('yuv.app.drive.action.copy-link');
|
|
960
|
+
this.description = this.translate.instant('yuv.app.drive.action.copy-link.description');
|
|
961
|
+
this.priority = 2;
|
|
962
|
+
this.icon = '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="m678-134 46-46-64-64-46 46q-14 14-14 32t14 32q14 14 32 14t32-14Zm102-102 46-46q14-14 14-32t-14-32q-14-14-32-14t-32 14l-46 46 64 64ZM735-77q-37 37-89 37t-89-37q-37-37-37-89t37-89l148-148q37-37 89-37t89 37q37 37 37 89t-37 89L735-77ZM200-200v-560 560Zm0 80q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h168q13-36 43.5-58t68.5-22q38 0 68.5 22t43.5 58h168q33 0 56.5 23.5T840-760v245q-20-5-40-5t-40 3v-243H200v560h243q-3 20-3 40t5 40H200Zm280-670q13 0 21.5-8.5T510-820q0-13-8.5-21.5T480-850q-13 0-21.5 8.5T450-820q0 13 8.5 21.5T480-790ZM280-600v-80h400v80H280Zm0 160v-80h400v34q-8 5-15.5 11.5T649-460l-20 20H280Zm0 160v-80h269l-49 49q-8 8-14.5 15.5T474-280H280Z"/></svg>';
|
|
963
|
+
this.group = 'common';
|
|
964
|
+
this.range = SelectionRange.SINGLE_SELECT;
|
|
965
|
+
this.supports = {};
|
|
966
|
+
}
|
|
967
|
+
#notification;
|
|
968
|
+
#shell;
|
|
969
|
+
isExecutable(selection) {
|
|
970
|
+
return from(navigator.permissions.query({ name: 'clipboard-write' })).pipe(catchError(() => of({ state: 'denied' })), map((result) => (result.state === 'granted' || result.state === 'prompt') && selection.length === 1));
|
|
971
|
+
}
|
|
972
|
+
run(selection) {
|
|
973
|
+
const o = selection[0];
|
|
974
|
+
const uri = `${window.location.origin}${Utils.getBaseHref(true)}/${this.#shell.appBaseRoutes[APP_ID]}/${o.isFolder ? 'files' : 'object'}/${selection[0].id}`;
|
|
975
|
+
navigator.clipboard
|
|
976
|
+
.writeText(uri)
|
|
977
|
+
.then(() => this.#notification.info(this.translate.instant('yuv.app.drive.action.copy-link.success')))
|
|
978
|
+
.catch(() => {
|
|
979
|
+
//
|
|
980
|
+
});
|
|
981
|
+
return of(true);
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
class CreateFolderComponent {
|
|
986
|
+
constructor() {
|
|
987
|
+
this.drive = inject(DriveService);
|
|
988
|
+
this.translate = inject(TranslateService);
|
|
989
|
+
this.parentModalRef = inject(YvcOverlayRef);
|
|
990
|
+
this.busy = signal(false);
|
|
991
|
+
}
|
|
992
|
+
createFolder(name) {
|
|
993
|
+
this.message = undefined;
|
|
994
|
+
if (name) {
|
|
995
|
+
this.busy.set(true);
|
|
996
|
+
this.drive.createFolder(name).subscribe((res) => {
|
|
997
|
+
if (res.error) {
|
|
998
|
+
switch (res.error) {
|
|
999
|
+
case 'nameExists':
|
|
1000
|
+
this.message = this.translate.instant('yuv.app.drive.create.error.name.exist');
|
|
1001
|
+
break;
|
|
1002
|
+
default:
|
|
1003
|
+
this.message = this.translate.instant('yuv.app.drive.create.error');
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
else {
|
|
1007
|
+
this.close();
|
|
1008
|
+
}
|
|
1009
|
+
}).add(() => this.busy.set(false));
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
close() {
|
|
1013
|
+
this.parentModalRef.close();
|
|
1014
|
+
}
|
|
1015
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CreateFolderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1016
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: CreateFolderComponent, isStandalone: true, selector: "ymd-create-folder", host: { properties: { "class.busy": "busy()" } }, ngImport: i0, template: "<div class=\"yuv-loader-linear\"></div>\n\n<ymd-object-name [disabled]=\"busy()\"\n [headline]=\"'yuv.app.drive.folder.create.headline' | translate\"\n [submitButton]=\"'yuv.app.drive.folder.create.submit' | translate\"\n [cancelButton]=\"'yuv.app.drive.action.rename.cancel' | translate\"\n (onClose)=\"close()\"\n (nameChange)=\"createFolder($event)\"\n></ymd-object-name>\n\n@if (message) {\n <div class=\"message\">{{message}}</div>\n}", styles: [":host{display:block;position:relative}:host .yuv-loader-linear{position:absolute;inset-inline-start:0;inset-inline-end:0;inset-block-start:0;opacity:0}:host ymd-object-name{display:block;padding:var(--app-pane-padding)}:host.busy .yuv-loader-linear{opacity:1}:host .message{padding:var(--app-pane-padding);background-color:var(--panel-background-lightgrey);border-block-start:1px solid var(--panel-divider-color)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: ObjectNameComponent, selector: "ymd-object-name", inputs: ["headline", "submitButton", "cancelButton", "isFile", "isRename", "item", "disabled"], outputs: ["nameChange", "onClose"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }] }); }
|
|
1017
|
+
}
|
|
1018
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CreateFolderComponent, decorators: [{
|
|
1019
|
+
type: Component,
|
|
1020
|
+
args: [{ selector: 'ymd-create-folder', standalone: true, imports: [CommonModule, ObjectNameComponent, TranslateModule], host: {
|
|
1021
|
+
'[class.busy]': 'busy()'
|
|
1022
|
+
}, template: "<div class=\"yuv-loader-linear\"></div>\n\n<ymd-object-name [disabled]=\"busy()\"\n [headline]=\"'yuv.app.drive.folder.create.headline' | translate\"\n [submitButton]=\"'yuv.app.drive.folder.create.submit' | translate\"\n [cancelButton]=\"'yuv.app.drive.action.rename.cancel' | translate\"\n (onClose)=\"close()\"\n (nameChange)=\"createFolder($event)\"\n></ymd-object-name>\n\n@if (message) {\n <div class=\"message\">{{message}}</div>\n}", styles: [":host{display:block;position:relative}:host .yuv-loader-linear{position:absolute;inset-inline-start:0;inset-inline-end:0;inset-block-start:0;opacity:0}:host ymd-object-name{display:block;padding:var(--app-pane-padding)}:host.busy .yuv-loader-linear{opacity:1}:host .message{padding:var(--app-pane-padding);background-color:var(--panel-background-lightgrey);border-block-start:1px solid var(--panel-divider-color)}\n"] }]
|
|
1023
|
+
}] });
|
|
1024
|
+
|
|
1025
|
+
class AddButtonOverlayComponent {
|
|
1026
|
+
constructor() {
|
|
1027
|
+
this.#overlay = inject(YvcOverlayService);
|
|
1028
|
+
this.#oRef = inject(YvcOverlayRef);
|
|
1029
|
+
this.#drive = inject(DriveService);
|
|
1030
|
+
this.#shell = inject(ShellService);
|
|
1031
|
+
this.#system = inject(SystemService);
|
|
1032
|
+
this.translate = inject(TranslateService);
|
|
1033
|
+
this.fileInput = viewChild.required('fileInput');
|
|
1034
|
+
this.icons = {
|
|
1035
|
+
folder: APP_DRIVE_ICONS.createFolder,
|
|
1036
|
+
file: APP_DRIVE_ICONS.createFile
|
|
1037
|
+
};
|
|
1038
|
+
this.defaultItems = [
|
|
1039
|
+
{ icon: this.icons.folder, label: this.translate.instant('yuv.app.drive.create.folder') },
|
|
1040
|
+
{ icon: this.icons.file, label: this.translate.instant('yuv.app.drive.create.file') }
|
|
1041
|
+
];
|
|
1042
|
+
this.flavorListItems = this.#shell.getObjectCreateFlavors().map((flavor) => ({
|
|
1043
|
+
label: this.translate.instant(flavor.id),
|
|
1044
|
+
flavor
|
|
1045
|
+
}));
|
|
1046
|
+
}
|
|
1047
|
+
#overlay;
|
|
1048
|
+
#oRef;
|
|
1049
|
+
#drive;
|
|
1050
|
+
#shell;
|
|
1051
|
+
#system;
|
|
1052
|
+
#uploadTargetFlavor;
|
|
1053
|
+
onListItemSelect(idx) {
|
|
1054
|
+
if (idx.length === 0)
|
|
1055
|
+
return;
|
|
1056
|
+
const fi = idx[0];
|
|
1057
|
+
if (fi === 0) {
|
|
1058
|
+
this.startCreateFolder();
|
|
1059
|
+
}
|
|
1060
|
+
else if (fi === 1) {
|
|
1061
|
+
this.startCreateDocument();
|
|
1062
|
+
}
|
|
1063
|
+
else {
|
|
1064
|
+
this.startCreateDocument();
|
|
1065
|
+
this.#uploadTargetFlavor = this.flavorListItems[fi - this.defaultItems.length]?.flavor;
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
startCreateDocument() {
|
|
1069
|
+
if (!this.#uploadTargetFlavor || this.#uploadTargetFlavor.withFileUpload) {
|
|
1070
|
+
this.fileInput().nativeElement.click();
|
|
1071
|
+
}
|
|
1072
|
+
else if (this.#uploadTargetFlavor?.applyComponent) {
|
|
1073
|
+
this.#overlay.open(this.#uploadTargetFlavor.applyComponent, {
|
|
1074
|
+
flavor: this.#uploadTargetFlavor,
|
|
1075
|
+
onCancel: () => {
|
|
1076
|
+
console.log('cancel');
|
|
1077
|
+
}
|
|
1078
|
+
});
|
|
1079
|
+
this.#uploadTargetFlavor = undefined;
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
startCreateFolder() {
|
|
1083
|
+
this.#oRef?.close();
|
|
1084
|
+
this.#overlay.open(CreateFolderComponent, null, {
|
|
1085
|
+
width: '400px',
|
|
1086
|
+
maxWidth: '90vw'
|
|
1087
|
+
});
|
|
1088
|
+
}
|
|
1089
|
+
createDocument(inputEl) {
|
|
1090
|
+
this.#oRef?.close();
|
|
1091
|
+
const files = inputEl.files ? Array.from(inputEl.files) : undefined;
|
|
1092
|
+
if (files) {
|
|
1093
|
+
const data = this.#uploadTargetFlavor?.sot ? { [BaseObjectTypeField.SECONDARY_OBJECT_TYPE_IDS]: [this.#uploadTargetFlavor.sot] } : undefined;
|
|
1094
|
+
this.#drive.setBusy(true);
|
|
1095
|
+
this.#drive
|
|
1096
|
+
.checkNamesAndUpload(files, data)
|
|
1097
|
+
.subscribe((createResult) => {
|
|
1098
|
+
const uploadErrors = createResult.filter((r) => !!r.error);
|
|
1099
|
+
if (uploadErrors.length) {
|
|
1100
|
+
// TODO: Handle upload errors
|
|
1101
|
+
console.error(uploadErrors);
|
|
1102
|
+
}
|
|
1103
|
+
if (this.#uploadTargetFlavor?.applyComponent) {
|
|
1104
|
+
this.#overlay.open(this.#uploadTargetFlavor.applyComponent, {
|
|
1105
|
+
createdObjectIDs: createResult.filter((r) => r.id).map((r) => r.id),
|
|
1106
|
+
flavor: this.#uploadTargetFlavor
|
|
1107
|
+
});
|
|
1108
|
+
}
|
|
1109
|
+
this.#uploadTargetFlavor = undefined;
|
|
1110
|
+
})
|
|
1111
|
+
.add(() => this.#drive.setBusy(false));
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AddButtonOverlayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1115
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: AddButtonOverlayComponent, isStandalone: true, selector: "ymd-add-button-overlay", viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true, isSignal: true }], ngImport: i0, template: "<yuv-list (itemSelect)=\"onListItemSelect($event)\" selectOnEnter=\"true\">\n @for (i of defaultItems; track $index) {\n <div yuvListItem>\n <yvc-icon [svg]=\"i.icon\"></yvc-icon>\n {{ i.label }}\n </div>\n }\n\n <!-- Upload file with flavor -->\n @for (f of flavorListItems; track f.flavor.id) {\n <div class=\"flavor\" yuvListItem>\n <yvc-icon [svg]=\"f.flavor.icon\"></yvc-icon>\n {{ f.label }}\n </div>\n }\n</yuv-list>\n\n<input style=\"display: none\" multiple=\"true\" #fileInput type=\"file\" (change)=\"createDocument(fileInput)\" />\n", styles: [":host{background-color:var(--color-accent);color:var(--color-accent-tone);display:flex;flex-flow:column;padding:calc(var(--app-pane-padding) / 2) 0;border-radius:0 4px 4px}:host yuv-list{outline:0;--list-item-current-background: rgb(from var(--color-accent-tone) r g b / .2)}:host yuv-list [yuvListItem]{--icon-size: 18px;cursor:pointer;display:flex;align-items:center;gap:calc(var(--app-pane-padding) / 2);padding:calc(var(--app-pane-padding) / 2) var(--app-pane-padding)}:host yuv-list [yuvListItem]:hover{background-color:var(--list-item-current-background)}:host yuv-list [yuvListItem]:nth-child(2){border-block-end:1px solid rgb(from var(--color-accent-tone) r g b/.2)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: ListComponent, selector: "yuv-list", inputs: ["multiselect", "disableSelection"], outputs: ["itemSelect", "itemFocus"] }, { kind: "directive", type: ListItemDirective, selector: "[yuvListItem]", inputs: ["disabled", "active", "selected"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "ngmodule", type: YvcIconModule }, { kind: "component", type: i1$1.Icon, selector: "yvc-icon", inputs: ["label", "svg", "svgSrc"] }] }); }
|
|
1116
|
+
}
|
|
1117
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AddButtonOverlayComponent, decorators: [{
|
|
1118
|
+
type: Component,
|
|
1119
|
+
args: [{ selector: 'ymd-add-button-overlay', standalone: true, imports: [CommonModule, ListComponent, ListItemDirective, TranslateModule, YvcIconModule], template: "<yuv-list (itemSelect)=\"onListItemSelect($event)\" selectOnEnter=\"true\">\n @for (i of defaultItems; track $index) {\n <div yuvListItem>\n <yvc-icon [svg]=\"i.icon\"></yvc-icon>\n {{ i.label }}\n </div>\n }\n\n <!-- Upload file with flavor -->\n @for (f of flavorListItems; track f.flavor.id) {\n <div class=\"flavor\" yuvListItem>\n <yvc-icon [svg]=\"f.flavor.icon\"></yvc-icon>\n {{ f.label }}\n </div>\n }\n</yuv-list>\n\n<input style=\"display: none\" multiple=\"true\" #fileInput type=\"file\" (change)=\"createDocument(fileInput)\" />\n", styles: [":host{background-color:var(--color-accent);color:var(--color-accent-tone);display:flex;flex-flow:column;padding:calc(var(--app-pane-padding) / 2) 0;border-radius:0 4px 4px}:host yuv-list{outline:0;--list-item-current-background: rgb(from var(--color-accent-tone) r g b / .2)}:host yuv-list [yuvListItem]{--icon-size: 18px;cursor:pointer;display:flex;align-items:center;gap:calc(var(--app-pane-padding) / 2);padding:calc(var(--app-pane-padding) / 2) var(--app-pane-padding)}:host yuv-list [yuvListItem]:hover{background-color:var(--list-item-current-background)}:host yuv-list [yuvListItem]:nth-child(2){border-block-end:1px solid rgb(from var(--color-accent-tone) r g b/.2)}\n"] }]
|
|
1120
|
+
}] });
|
|
1121
|
+
|
|
1122
|
+
class AddButtonComponent {
|
|
1123
|
+
constructor() {
|
|
1124
|
+
this.overlay = inject(YvcOverlayService);
|
|
1125
|
+
this.elRef = inject(ElementRef);
|
|
1126
|
+
this.popoverOpen = false;
|
|
1127
|
+
this.icon = APP_DRIVE_ICONS.addCircle;
|
|
1128
|
+
this.disabled = input(false);
|
|
1129
|
+
}
|
|
1130
|
+
open() {
|
|
1131
|
+
this._oRef = this.overlay.open(AddButtonOverlayComponent, null, {
|
|
1132
|
+
overlayClass: null,
|
|
1133
|
+
focusHandled: true
|
|
1134
|
+
}, this.elRef.nativeElement);
|
|
1135
|
+
this.popoverOpen = true;
|
|
1136
|
+
this._oRef.afterClosed$.subscribe(() => {
|
|
1137
|
+
this.popoverOpen = false;
|
|
1138
|
+
});
|
|
1139
|
+
}
|
|
1140
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AddButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1141
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.2.13", type: AddButtonComponent, isStandalone: true, selector: "ymd-add-button", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.popover": "this.popoverOpen" } }, ngImport: i0, template: "\n <button class=\"toggle primary\" [disabled]=\"disabled()\" (click)=\"open()\">\n <yvc-icon [svg]=\"icon\"></yvc-icon><span class=\"label\">{{ 'yuv.app.drive.create.label' | translate }}</span>\n </button>\n\n", styles: [":host{--border-radius: var(--ribbon-button-border-radius)}:host.popover button{border-radius:4px 4px 0 0;pointer-events:none}:host button{padding:var(--ribbon-button-padding);border-radius:var(--border-radius);display:flex;gap:calc(var(--ribbon-icon-size) / 3);padding-inline-end:calc(var(--ribbon-icon-size) / 2)}:host button yvc-icon{--icon-size: var(--ribbon-icon-size)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: YvcIconModule }, { kind: "component", type: i1$1.Icon, selector: "yvc-icon", inputs: ["label", "svg", "svgSrc"] }, { kind: "ngmodule", type: TranslateModule$1 }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }] }); }
|
|
1142
|
+
}
|
|
1143
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AddButtonComponent, decorators: [{
|
|
1144
|
+
type: Component,
|
|
1145
|
+
args: [{ selector: 'ymd-add-button', standalone: true, imports: [CommonModule, YvcIconModule, TranslateModule$1], template: "\n <button class=\"toggle primary\" [disabled]=\"disabled()\" (click)=\"open()\">\n <yvc-icon [svg]=\"icon\"></yvc-icon><span class=\"label\">{{ 'yuv.app.drive.create.label' | translate }}</span>\n </button>\n\n", styles: [":host{--border-radius: var(--ribbon-button-border-radius)}:host.popover button{border-radius:4px 4px 0 0;pointer-events:none}:host button{padding:var(--ribbon-button-padding);border-radius:var(--border-radius);display:flex;gap:calc(var(--ribbon-icon-size) / 3);padding-inline-end:calc(var(--ribbon-icon-size) / 2)}:host button yvc-icon{--icon-size: var(--ribbon-icon-size)}\n"] }]
|
|
1146
|
+
}], propDecorators: { popoverOpen: [{
|
|
1147
|
+
type: HostBinding,
|
|
1148
|
+
args: ['class.popover']
|
|
1149
|
+
}] } });
|
|
1150
|
+
|
|
1151
|
+
class SortComponent {
|
|
1152
|
+
constructor() {
|
|
1153
|
+
this.#drive = inject(DriveService);
|
|
1154
|
+
this.#systemService = inject(SystemService);
|
|
1155
|
+
this.#fb = inject(FormBuilder);
|
|
1156
|
+
this.#dir = inject(Directionality);
|
|
1157
|
+
this.sortIcon = APP_DRIVE_ICONS.sort;
|
|
1158
|
+
this.items = viewChildren(ListItemDirective);
|
|
1159
|
+
this.#itemsEffect = effect(() => {
|
|
1160
|
+
const i = this.items();
|
|
1161
|
+
if (this.#keyManager)
|
|
1162
|
+
this.#keyManager.destroy();
|
|
1163
|
+
this.#keyManager = new ActiveDescendantKeyManager(i).withWrap().withHorizontalOrientation(this.#dir.value);
|
|
1164
|
+
});
|
|
1165
|
+
this.sortOptions = signal(this.#initSortOptions());
|
|
1166
|
+
this.orderOptions = signal([
|
|
1167
|
+
{ label: 'Ascending', value: 'asc', type: 'order' },
|
|
1168
|
+
{ label: 'Descending', value: 'desc', type: 'order' }
|
|
1169
|
+
]);
|
|
1170
|
+
this.sortFields = computed(() => [...this.sortOptions(), ...this.orderOptions()]);
|
|
1171
|
+
this.sortChanged = output();
|
|
1172
|
+
}
|
|
1173
|
+
#drive;
|
|
1174
|
+
#systemService;
|
|
1175
|
+
#fb;
|
|
1176
|
+
#dir;
|
|
1177
|
+
onBlur() {
|
|
1178
|
+
this.#keyManager.setActiveItem(-1);
|
|
1179
|
+
}
|
|
1180
|
+
onKeydown(event) {
|
|
1181
|
+
event.code === 'Escape' && this.#keyManager.setActiveItem(-1);
|
|
1182
|
+
event.target instanceof HTMLButtonElement && this.#keyManager.setActiveItem(-1);
|
|
1183
|
+
if (event.code === 'Space' || event.code === 'Enter') {
|
|
1184
|
+
const aii = this.#keyManager.activeItemIndex !== null ? this.#keyManager.activeItemIndex : -1;
|
|
1185
|
+
aii >= 0 && this.selectSortByIndex(aii);
|
|
1186
|
+
}
|
|
1187
|
+
else
|
|
1188
|
+
this.#keyManager?.onKeydown(event);
|
|
1189
|
+
}
|
|
1190
|
+
#keyManager;
|
|
1191
|
+
#itemsEffect;
|
|
1192
|
+
selectSortByIndex(idx) {
|
|
1193
|
+
this.selectSort(this.sortFields()[idx].type, this.sortFields()[idx].value);
|
|
1194
|
+
}
|
|
1195
|
+
selectSort(type, value) {
|
|
1196
|
+
this.sortForm.get('sort')?.value === value ? this.sortForm.get('sort')?.setValue(null) : this.sortForm.get(type)?.setValue(value);
|
|
1197
|
+
this.onSelectionChange();
|
|
1198
|
+
}
|
|
1199
|
+
ngOnInit() {
|
|
1200
|
+
this.sortForm = this.#fb.nonNullable.group({
|
|
1201
|
+
sort: [],
|
|
1202
|
+
order: [this.orderOptions()[0].value] // Default: Ascending
|
|
1203
|
+
});
|
|
1204
|
+
// TODO: Check if this is necessary. It breaks stored queries first load by resetting sort
|
|
1205
|
+
// this.onSelectionChange();
|
|
1206
|
+
}
|
|
1207
|
+
// Emit the form values when changes occur
|
|
1208
|
+
onSelectionChange() {
|
|
1209
|
+
const { sort, order } = this.sortForm.value;
|
|
1210
|
+
this.#drive.setSort(sort, order);
|
|
1211
|
+
this.sortChanged.emit({ sort, order });
|
|
1212
|
+
}
|
|
1213
|
+
#initSortOptions() {
|
|
1214
|
+
const baseData = [];
|
|
1215
|
+
const fields = [FS_PROPERTIES.name, BaseObjectTypeField.CREATION_DATE, BaseObjectTypeField.MODIFICATION_DATE];
|
|
1216
|
+
const contentFields = [ContentStreamField.LENGTH, ContentStreamField.MIME_TYPE];
|
|
1217
|
+
[...fields, ...contentFields].forEach((f) => {
|
|
1218
|
+
baseData.push({
|
|
1219
|
+
label: this.#systemService.getLocalizedLabel(f) || f,
|
|
1220
|
+
value: f,
|
|
1221
|
+
type: 'sort'
|
|
1222
|
+
});
|
|
1223
|
+
});
|
|
1224
|
+
return baseData;
|
|
1225
|
+
}
|
|
1226
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SortComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1227
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: SortComponent, isStandalone: true, selector: "ymd-sort", outputs: { sortChanged: "sortChanged" }, host: { listeners: { "blur": "onBlur()", "keydown": "onKeydown($event)" } }, viewQueries: [{ propertyName: "items", predicate: ListItemDirective, descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
1228
|
+
<button popovertarget="sort" class="sort-button">
|
|
1229
|
+
<yvc-icon [svg]="sortIcon" />
|
|
1230
|
+
</button>
|
|
1231
|
+
|
|
1232
|
+
<dialog popover id="sort" class="sort-menu">
|
|
1233
|
+
<ol class="sort-group" tabindex="0">
|
|
1234
|
+
@for (option of sortFields(); track $index) {
|
|
1235
|
+
@let selected = sortForm.value[option.type] === option.value;
|
|
1236
|
+
<li
|
|
1237
|
+
class="sort-item"
|
|
1238
|
+
[class.selected]="selected"
|
|
1239
|
+
[ngClass]="{ selected: selected, 'sort-group-item': option.type === 'sort', 'order-group-item': option.type === 'order' }"
|
|
1240
|
+
yuvListItem
|
|
1241
|
+
[selected]="selected"
|
|
1242
|
+
(click)="selectSort(option.type, option.value)"
|
|
1243
|
+
>
|
|
1244
|
+
<div class="label">
|
|
1245
|
+
{{ option.label }}
|
|
1246
|
+
</div>
|
|
1247
|
+
</li>
|
|
1248
|
+
@if (sortFields().length - 3 === $index) {
|
|
1249
|
+
<div class="divider"></div>
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
</ol>
|
|
1253
|
+
</dialog>
|
|
1254
|
+
`, isInline: true, styles: ["@charset \"UTF-8\";.sort-button{padding:calc(var(--app-pane-padding) / 4);anchor-name:--sort-button}dialog::backdrop{background-color:#ff69b4;display:none}.sort-menu{display:none;background-color:var(--panel-background);color:var(--text-color-body);border-color:var(--panel-background);position:absolute;position-anchor:--sort-button;position-area:block-end center;margin:0;inset:auto;bottom:anchor(bottom);left:anchor(right);opacity:0;transition:opacity .3s,display .3s,overlay .3s;transition-behavior:allow-discrete;position-try-fallbacks:--left;margin-left:.25rem;box-shadow:0 1px 12px #0000001a;border:1px solid var(--panel-divider-color)}.sort-menu::backdrop{background-color:#ff69b4;display:none;-webkit-backdrop-filter:none;backdrop-filter:none}.sort-menu:popover-open{display:grid;opacity:1}@starting-style{.sort-menu:popover-open{display:grid;opacity:0}}@position-try --left{inset:auto;top:anchor(bottom);right:anchor(right)}.sort-group{list-style-type:none;padding-inline:0;margin-block:0;padding:.5rem}.sort-group [yuvListItem]{padding-left:calc(var(--font-body) + 2px);line-height:1.5em;display:flex;align-items:center;text-decoration:none;white-space:nowrap;border-radius:2px;color:var(--text-color-caption)}.sort-group [yuvListItem][aria-selected=true]:before{content:\"\\2022\";position:absolute;left:var(--font-body);font-size:var(--font-title)}.sort-group [yuvListItem][aria-current=true],.sort-group [yuvListItem]:hover{cursor:pointer;color:var(--text-color-body);background-color:var(--item-focus-background-color);outline:2px solid var(--item-focus-background-color)}.sort-group [yuvListItem][aria-current=true]{outline-color:var(--text-color-caption)}.sort-group [yuvListItem] .label{margin-right:.5rem;padding:.1rem 0}.sort-group .divider{margin:.5rem 0;border-top:1px solid var(--panel-divider-color)}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: YvcIconModule }, { kind: "component", type: i1$1.Icon, selector: "yvc-icon", inputs: ["label", "svg", "svgSrc"] }, { kind: "directive", type: ListItemDirective, selector: "[yuvListItem]", inputs: ["disabled", "active", "selected"] }, { kind: "ngmodule", type: ReactiveFormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1255
|
+
}
|
|
1256
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SortComponent, decorators: [{
|
|
1257
|
+
type: Component,
|
|
1258
|
+
args: [{ selector: 'ymd-sort', standalone: true, imports: [NgClass, YvcIconModule, ListItemDirective, ReactiveFormsModule], template: `
|
|
1259
|
+
<button popovertarget="sort" class="sort-button">
|
|
1260
|
+
<yvc-icon [svg]="sortIcon" />
|
|
1261
|
+
</button>
|
|
1262
|
+
|
|
1263
|
+
<dialog popover id="sort" class="sort-menu">
|
|
1264
|
+
<ol class="sort-group" tabindex="0">
|
|
1265
|
+
@for (option of sortFields(); track $index) {
|
|
1266
|
+
@let selected = sortForm.value[option.type] === option.value;
|
|
1267
|
+
<li
|
|
1268
|
+
class="sort-item"
|
|
1269
|
+
[class.selected]="selected"
|
|
1270
|
+
[ngClass]="{ selected: selected, 'sort-group-item': option.type === 'sort', 'order-group-item': option.type === 'order' }"
|
|
1271
|
+
yuvListItem
|
|
1272
|
+
[selected]="selected"
|
|
1273
|
+
(click)="selectSort(option.type, option.value)"
|
|
1274
|
+
>
|
|
1275
|
+
<div class="label">
|
|
1276
|
+
{{ option.label }}
|
|
1277
|
+
</div>
|
|
1278
|
+
</li>
|
|
1279
|
+
@if (sortFields().length - 3 === $index) {
|
|
1280
|
+
<div class="divider"></div>
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
</ol>
|
|
1284
|
+
</dialog>
|
|
1285
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: ["@charset \"UTF-8\";.sort-button{padding:calc(var(--app-pane-padding) / 4);anchor-name:--sort-button}dialog::backdrop{background-color:#ff69b4;display:none}.sort-menu{display:none;background-color:var(--panel-background);color:var(--text-color-body);border-color:var(--panel-background);position:absolute;position-anchor:--sort-button;position-area:block-end center;margin:0;inset:auto;bottom:anchor(bottom);left:anchor(right);opacity:0;transition:opacity .3s,display .3s,overlay .3s;transition-behavior:allow-discrete;position-try-fallbacks:--left;margin-left:.25rem;box-shadow:0 1px 12px #0000001a;border:1px solid var(--panel-divider-color)}.sort-menu::backdrop{background-color:#ff69b4;display:none;-webkit-backdrop-filter:none;backdrop-filter:none}.sort-menu:popover-open{display:grid;opacity:1}@starting-style{.sort-menu:popover-open{display:grid;opacity:0}}@position-try --left{inset:auto;top:anchor(bottom);right:anchor(right)}.sort-group{list-style-type:none;padding-inline:0;margin-block:0;padding:.5rem}.sort-group [yuvListItem]{padding-left:calc(var(--font-body) + 2px);line-height:1.5em;display:flex;align-items:center;text-decoration:none;white-space:nowrap;border-radius:2px;color:var(--text-color-caption)}.sort-group [yuvListItem][aria-selected=true]:before{content:\"\\2022\";position:absolute;left:var(--font-body);font-size:var(--font-title)}.sort-group [yuvListItem][aria-current=true],.sort-group [yuvListItem]:hover{cursor:pointer;color:var(--text-color-body);background-color:var(--item-focus-background-color);outline:2px solid var(--item-focus-background-color)}.sort-group [yuvListItem][aria-current=true]{outline-color:var(--text-color-caption)}.sort-group [yuvListItem] .label{margin-right:.5rem;padding:.1rem 0}.sort-group .divider{margin:.5rem 0;border-top:1px solid var(--panel-divider-color)}\n"] }]
|
|
1286
|
+
}], propDecorators: { onBlur: [{
|
|
1287
|
+
type: HostListener,
|
|
1288
|
+
args: ['blur']
|
|
1289
|
+
}], onKeydown: [{
|
|
1290
|
+
type: HostListener,
|
|
1291
|
+
args: ['keydown', ['$event']]
|
|
1292
|
+
}] } });
|
|
1293
|
+
|
|
1294
|
+
class BreadcrumbComponent {
|
|
1295
|
+
constructor() {
|
|
1296
|
+
this.#drive = inject(DriveService);
|
|
1297
|
+
this.#router = inject(Router);
|
|
1298
|
+
this.#dir = inject(Directionality);
|
|
1299
|
+
this.route = inject(ActivatedRoute);
|
|
1300
|
+
this.homeIcon = APP_DRIVE_ICONS.home;
|
|
1301
|
+
this.breadcrumb = this.#drive.state$.breadcrumb;
|
|
1302
|
+
this.items = viewChildren(ListItemDirective);
|
|
1303
|
+
this.#itemsEffect = effect(() => {
|
|
1304
|
+
const i = this.items();
|
|
1305
|
+
if (this.#keyManager)
|
|
1306
|
+
this.#keyManager.destroy();
|
|
1307
|
+
this.#keyManager = new ActiveDescendantKeyManager(i).withWrap().withHorizontalOrientation(this.#dir.value);
|
|
1308
|
+
});
|
|
1309
|
+
}
|
|
1310
|
+
#drive;
|
|
1311
|
+
#router;
|
|
1312
|
+
#dir;
|
|
1313
|
+
onBlur() {
|
|
1314
|
+
this.#keyManager.setActiveItem(-1);
|
|
1315
|
+
}
|
|
1316
|
+
onKeydown(event) {
|
|
1317
|
+
if (event.code === 'Space' || event.code === 'Enter') {
|
|
1318
|
+
const aii = this.#keyManager.activeItemIndex !== null ? this.#keyManager.activeItemIndex : -1;
|
|
1319
|
+
if (aii >= 0) {
|
|
1320
|
+
this.navigation(aii === 0 ? DRIVE_ROOT_FOLDER_ID : this.breadcrumb().items[aii - 1].id);
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
else
|
|
1324
|
+
this.#keyManager?.onKeydown(event);
|
|
1325
|
+
}
|
|
1326
|
+
#keyManager;
|
|
1327
|
+
#itemsEffect;
|
|
1328
|
+
navigation(id, event) {
|
|
1329
|
+
event && event.preventDefault();
|
|
1330
|
+
const nav = ['..'];
|
|
1331
|
+
this.#keyManager.setActiveItem(-1);
|
|
1332
|
+
this.#router.navigate([...nav, id], { relativeTo: this.route });
|
|
1333
|
+
}
|
|
1334
|
+
ngOnDestroy() {
|
|
1335
|
+
this.#keyManager?.destroy();
|
|
1336
|
+
}
|
|
1337
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BreadcrumbComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1338
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: BreadcrumbComponent, isStandalone: true, selector: "ymd-breadcrumb", host: { attributes: { "tabindex": "0" }, listeners: { "blur": "onBlur()", "keydown": "onKeydown($event)" }, classAttribute: "breadcrumb" }, viewQueries: [{ propertyName: "items", predicate: ListItemDirective, descendants: true, isSignal: true }], ngImport: i0, template: "@let bread = breadcrumb();\n\n<nav aria-label=\"breadcrumb\">\n <ol>\n @if (bread.items.length) {\n <li>\n <a tabindex=\"-1\" yuvListItem draggable=\"false\" class=\"home\" href=\"\" (click)=\"navigation('root', $event)\">\n <yvc-icon [svg]=\"homeIcon\" title=\"{{ 'yuv.app.drive.folder-tree.mydrive' | translate }}\" />\n </a>\n </li>\n\n <div class=\"spacer\" aria-label=\"hidden\"></div>\n\n @if (bread.partial) {\n <div class=\"partial\" aria-label=\"hidden\"></div>\n <div class=\"spacer\" aria-label=\"hidden\"></div>\n }\n\n <li yvcDragScroll>\n <ol>\n @for (crumb of bread.items; track $index) {\n @if (!$last) {\n <li>\n <a tabindex=\"-1\" yuvListItem draggable=\"false\" href=\"\" (click)=\"navigation(crumb.id, $event)\">\n {{ crumb.name }}\n </a>\n </li>\n } @else {\n <li aria-current=\"location\">{{ crumb.name }}</li>\n }\n @if (!$last) {\n <div class=\"spacer\" aria-label=\"hidden\"></div>\n }\n }\n </ol>\n </li>\n } @else {\n <li aria-current=\"location\"><yvc-icon [svg]=\"homeIcon\" title=\"{{ 'yuv.app.drive.folder-tree.mydrive' | translate }}\" /></li>\n }\n </ol>\n</nav>\n", styles: ["@charset \"UTF-8\";:host{color:var(--text-color-caption)}:host [aria-label=breadcrumb]{overflow:hidden;display:flex;align-items:center}:host [aria-current=location],:host a.home{--icon-size: 18px;display:flex;align-items:center;justify-content:center}:host ol{list-style:none;margin:0;padding:0;align-items:center;display:flex;flex-wrap:nowrap}:host li{align-items:center;display:flex;white-space:nowrap;cursor:default}:host nav>ol{overflow:hidden}:host nav>ol li[yvcDragScroll]{overflow-x:auto;--scrollbar-outer-size: 0px;--scrollbar-inner-size: 0px}:host .spacer:after{content:\"\\bb\";display:block;margin:0 4px}:host .partial:after{content:\"...\";display:block;padding:4px}:host [aria-current=location],:host [yuvListItem]{margin:2px;padding:2px;line-height:1em}:host [yuvListItem]{text-decoration:none;white-space:nowrap;border-radius:2px;color:var(--text-color-caption)}:host [yuvListItem][aria-current=true],:host [yuvListItem]:hover{color:var(--text-color-body);background-color:var(--item-focus-background-color);outline:2px solid var(--item-focus-background-color)}:host [yuvListItem][aria-current=true]{outline-color:var(--text-color-caption)}\n"], dependencies: [{ kind: "ngmodule", type: YvcIconModule }, { kind: "component", type: i1$1.Icon, selector: "yvc-icon", inputs: ["label", "svg", "svgSrc"] }, { kind: "ngmodule", type: YvcDragScrollModule }, { kind: "directive", type: i2$1.DragScrollDirective, selector: "[yvcDragScroll]" }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }, { kind: "directive", type: ListItemDirective, selector: "[yuvListItem]", inputs: ["disabled", "active", "selected"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1339
|
+
}
|
|
1340
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BreadcrumbComponent, decorators: [{
|
|
1341
|
+
type: Component,
|
|
1342
|
+
args: [{ selector: 'ymd-breadcrumb', standalone: true, imports: [YvcIconModule, YvcDragScrollModule, TranslateModule, ListItemDirective], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
1343
|
+
class: 'breadcrumb',
|
|
1344
|
+
tabindex: '0'
|
|
1345
|
+
}, template: "@let bread = breadcrumb();\n\n<nav aria-label=\"breadcrumb\">\n <ol>\n @if (bread.items.length) {\n <li>\n <a tabindex=\"-1\" yuvListItem draggable=\"false\" class=\"home\" href=\"\" (click)=\"navigation('root', $event)\">\n <yvc-icon [svg]=\"homeIcon\" title=\"{{ 'yuv.app.drive.folder-tree.mydrive' | translate }}\" />\n </a>\n </li>\n\n <div class=\"spacer\" aria-label=\"hidden\"></div>\n\n @if (bread.partial) {\n <div class=\"partial\" aria-label=\"hidden\"></div>\n <div class=\"spacer\" aria-label=\"hidden\"></div>\n }\n\n <li yvcDragScroll>\n <ol>\n @for (crumb of bread.items; track $index) {\n @if (!$last) {\n <li>\n <a tabindex=\"-1\" yuvListItem draggable=\"false\" href=\"\" (click)=\"navigation(crumb.id, $event)\">\n {{ crumb.name }}\n </a>\n </li>\n } @else {\n <li aria-current=\"location\">{{ crumb.name }}</li>\n }\n @if (!$last) {\n <div class=\"spacer\" aria-label=\"hidden\"></div>\n }\n }\n </ol>\n </li>\n } @else {\n <li aria-current=\"location\"><yvc-icon [svg]=\"homeIcon\" title=\"{{ 'yuv.app.drive.folder-tree.mydrive' | translate }}\" /></li>\n }\n </ol>\n</nav>\n", styles: ["@charset \"UTF-8\";:host{color:var(--text-color-caption)}:host [aria-label=breadcrumb]{overflow:hidden;display:flex;align-items:center}:host [aria-current=location],:host a.home{--icon-size: 18px;display:flex;align-items:center;justify-content:center}:host ol{list-style:none;margin:0;padding:0;align-items:center;display:flex;flex-wrap:nowrap}:host li{align-items:center;display:flex;white-space:nowrap;cursor:default}:host nav>ol{overflow:hidden}:host nav>ol li[yvcDragScroll]{overflow-x:auto;--scrollbar-outer-size: 0px;--scrollbar-inner-size: 0px}:host .spacer:after{content:\"\\bb\";display:block;margin:0 4px}:host .partial:after{content:\"...\";display:block;padding:4px}:host [aria-current=location],:host [yuvListItem]{margin:2px;padding:2px;line-height:1em}:host [yuvListItem]{text-decoration:none;white-space:nowrap;border-radius:2px;color:var(--text-color-caption)}:host [yuvListItem][aria-current=true],:host [yuvListItem]:hover{color:var(--text-color-body);background-color:var(--item-focus-background-color);outline:2px solid var(--item-focus-background-color)}:host [yuvListItem][aria-current=true]{outline-color:var(--text-color-caption)}\n"] }]
|
|
1346
|
+
}], propDecorators: { onBlur: [{
|
|
1347
|
+
type: HostListener,
|
|
1348
|
+
args: ['blur']
|
|
1349
|
+
}], onKeydown: [{
|
|
1350
|
+
type: HostListener,
|
|
1351
|
+
args: ['keydown', ['$event']]
|
|
1352
|
+
}] } });
|
|
1353
|
+
|
|
1354
|
+
// prefix for stored query ids (every stored query id should start with this prefix)
|
|
1355
|
+
const STORED_QUERY_ID_PREFIX = 'ymsq';
|
|
1356
|
+
// add a tranlation marker for the key the stored query is stored under
|
|
1357
|
+
// this is used to display the stored query title in the UI
|
|
1358
|
+
marker('ymsq.ymd.recent.modified.by.me');
|
|
1359
|
+
marker('ymsq.ymd.recent.added.by.me');
|
|
1360
|
+
// marker('ymsq.ymd.recent.modified');
|
|
1361
|
+
// marker('ymsq.ymd.recent.added');
|
|
1362
|
+
// default stored queries
|
|
1363
|
+
const STORED_QUERIES = {
|
|
1364
|
+
// 'ymsq.ymd.recent.modified': {
|
|
1365
|
+
// query: '{"filters":[{"f":"system:lastModifiedBy","o":"eq","v1":"##me##"}],"sort":[{"field":"system:lastModificationDate","order":"desc"}]}'
|
|
1366
|
+
// },
|
|
1367
|
+
'ymsq.ymd.recent.modified.by.me': {
|
|
1368
|
+
query: '{"filters":[{"f":"system:baseTypeId","o":"eq","v1":"system:document"}, { "f": "system:secondaryObjectTypeIds", "o": "in", "v1": ["appOsdrive:file"] }, {"f":"system:lastModifiedBy","o":"eq","v1":"##me##"}],"sort":[{"field":"system:lastModificationDate","order":"desc"}]}'
|
|
1369
|
+
},
|
|
1370
|
+
// 'ymsq.ymd.recent.added': {
|
|
1371
|
+
// query: '{"sort":[{"field":"system:creationDate","order":"desc"}]}'
|
|
1372
|
+
// },
|
|
1373
|
+
'ymsq.ymd.recent.added.by.me': {
|
|
1374
|
+
query: '{"filters":[{"f":"system:baseTypeId","o":"eq","v1":"system:document"}, { "f": "system:secondaryObjectTypeIds", "o": "in", "v1": ["appOsdrive:file"] }, {"f":"system:lastModifiedBy","o":"eq","v1":"##me##"}],"sort":[{"field":"system:creationDate","order":"desc"}]}'
|
|
1375
|
+
}
|
|
1376
|
+
};
|
|
1377
|
+
|
|
1378
|
+
class FolderTreeComponent {
|
|
1379
|
+
constructor() {
|
|
1380
|
+
this.translate = inject(TranslateService);
|
|
1381
|
+
this.router = inject(Router);
|
|
1382
|
+
this.route = inject(ActivatedRoute);
|
|
1383
|
+
this.treeCmp = viewChild.required(TreeComponent);
|
|
1384
|
+
this.folderTree = {
|
|
1385
|
+
nodes: [
|
|
1386
|
+
{
|
|
1387
|
+
id: 'mydrive',
|
|
1388
|
+
icon: APP_SCHEMA.icon,
|
|
1389
|
+
label: this.translate.instant('yuv.app.drive.folder-tree.mydrive'),
|
|
1390
|
+
selectable: true,
|
|
1391
|
+
children: [
|
|
1392
|
+
// {
|
|
1393
|
+
// id: 'ymsq.ymd.recent.added',
|
|
1394
|
+
// selectable: true,
|
|
1395
|
+
// label: this.translate.instant('ymsq.ymd.recent.added')
|
|
1396
|
+
// },
|
|
1397
|
+
{
|
|
1398
|
+
id: 'ymsq.ymd.recent.added.by.me',
|
|
1399
|
+
selectable: true,
|
|
1400
|
+
label: this.translate.instant('ymsq.ymd.recent.added.by.me')
|
|
1401
|
+
},
|
|
1402
|
+
// {
|
|
1403
|
+
// id: 'ymsq.ymd.recent.modified',
|
|
1404
|
+
// selectable: true,
|
|
1405
|
+
// label: this.translate.instant('ymsq.ymd.recent.modified')
|
|
1406
|
+
// },
|
|
1407
|
+
{
|
|
1408
|
+
id: 'ymsq.ymd.recent.modified.by.me',
|
|
1409
|
+
selectable: true,
|
|
1410
|
+
label: this.translate.instant('ymsq.ymd.recent.modified.by.me')
|
|
1411
|
+
}
|
|
1412
|
+
]
|
|
1413
|
+
}
|
|
1414
|
+
]
|
|
1415
|
+
};
|
|
1416
|
+
}
|
|
1417
|
+
onFocusLeave() {
|
|
1418
|
+
this.treeCmp().selectedNodes = [];
|
|
1419
|
+
}
|
|
1420
|
+
nodeSelected(nodes) {
|
|
1421
|
+
if (nodes.length) {
|
|
1422
|
+
const node = nodes[0];
|
|
1423
|
+
if (node.id.startsWith(STORED_QUERY_ID_PREFIX)) {
|
|
1424
|
+
// stored query
|
|
1425
|
+
this.router.navigate(['..', DRIVE_QUERY_FOLDER_ID], {
|
|
1426
|
+
queryParams: {
|
|
1427
|
+
q: node.id
|
|
1428
|
+
},
|
|
1429
|
+
relativeTo: this.route
|
|
1430
|
+
});
|
|
1431
|
+
}
|
|
1432
|
+
else {
|
|
1433
|
+
switch (node.id) {
|
|
1434
|
+
case 'mydrive': {
|
|
1435
|
+
this.router.navigate(['..', DRIVE_ROOT_FOLDER_ID], {
|
|
1436
|
+
relativeTo: this.route
|
|
1437
|
+
});
|
|
1438
|
+
break;
|
|
1439
|
+
}
|
|
1440
|
+
default: {
|
|
1441
|
+
this.router.navigate(['..', node.id], {
|
|
1442
|
+
relativeTo: this.route
|
|
1443
|
+
});
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FolderTreeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1450
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "18.2.13", type: FolderTreeComponent, isStandalone: true, selector: "ymd-folder-tree", viewQueries: [{ propertyName: "treeCmp", first: true, predicate: TreeComponent, descendants: true, isSignal: true }], ngImport: i0, template: "\n <yuv-tree [tree]=\"folderTree\" yuvFocusWithin (yuvFocusWithinBlur)=\"onFocusLeave()\"\n selectable (selectionChange)=\"nodeSelected($event)\"></yuv-tree>\n", styles: [":host{display:block;padding:var(--app-pane-padding)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: FocusWithinDirective, selector: "[yuvFocusWithin]", outputs: ["yuvFocusWithin", "yuvFocusWithinBlur"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: TreeComponent, selector: "yuv-tree", inputs: ["tree", "multiselect", "selectedNodes"], outputs: ["selectionChange"] }] }); }
|
|
1451
|
+
}
|
|
1452
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FolderTreeComponent, decorators: [{
|
|
1453
|
+
type: Component,
|
|
1454
|
+
args: [{ selector: 'ymd-folder-tree', standalone: true, imports: [CommonModule, RouterModule, FocusWithinDirective, TranslateModule, TreeComponent], template: "\n <yuv-tree [tree]=\"folderTree\" yuvFocusWithin (yuvFocusWithinBlur)=\"onFocusLeave()\"\n selectable (selectionChange)=\"nodeSelected($event)\"></yuv-tree>\n", styles: [":host{display:block;padding:var(--app-pane-padding)}\n"] }]
|
|
1455
|
+
}] });
|
|
1456
|
+
|
|
1457
|
+
class PasteFromClipboardComponent {
|
|
1458
|
+
constructor() {
|
|
1459
|
+
this.overlayRef = inject(YvcOverlayRef);
|
|
1460
|
+
this.drive = inject(DriveService);
|
|
1461
|
+
this.data = this.overlayRef.data;
|
|
1462
|
+
}
|
|
1463
|
+
uploadFromClipboard() {
|
|
1464
|
+
this.drive.checkNamesAndUpload(this.data.files).subscribe();
|
|
1465
|
+
this.overlayRef.close();
|
|
1466
|
+
}
|
|
1467
|
+
cancel() {
|
|
1468
|
+
this.overlayRef.close();
|
|
1469
|
+
}
|
|
1470
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: PasteFromClipboardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1471
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: PasteFromClipboardComponent, isStandalone: true, selector: "ymd-paste-from-clipboard", ngImport: i0, template: "<main>\n <p>{{ 'yuv.app.drive.paste-from-clipboard.message' | translate }}</p>\n <ol>\n @for (f of data.files; track $index) {\n <li>{{ f.name }}</li>\n }\n </ol>\n</main>\n\n<footer>\n <button class=\"primary\" (click)=\"uploadFromClipboard()\">{{ 'yuv.app.drive.paste-from-clipboard.button.paste' | translate }}</button>\n <button class=\"secondary\" (click)=\"cancel()\">{{ 'yuv.app.drive.paste-from-clipboard.button.cancel' | translate }}</button>\n</footer>\n", styles: [":host{display:grid;grid-template-rows:1fr auto;grid-template-areas:\"main\" \"footer\";padding:var(--app-pane-padding)}:host main{grid-area:main;overflow-y:auto}:host footer{grid-area:footer;display:flex;flex-flow:row-reverse;justify-content:space-between;align-items:center}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }] }); }
|
|
1472
|
+
}
|
|
1473
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: PasteFromClipboardComponent, decorators: [{
|
|
1474
|
+
type: Component,
|
|
1475
|
+
args: [{ selector: 'ymd-paste-from-clipboard', standalone: true, imports: [CommonModule, TranslateModule], template: "<main>\n <p>{{ 'yuv.app.drive.paste-from-clipboard.message' | translate }}</p>\n <ol>\n @for (f of data.files; track $index) {\n <li>{{ f.name }}</li>\n }\n </ol>\n</main>\n\n<footer>\n <button class=\"primary\" (click)=\"uploadFromClipboard()\">{{ 'yuv.app.drive.paste-from-clipboard.button.paste' | translate }}</button>\n <button class=\"secondary\" (click)=\"cancel()\">{{ 'yuv.app.drive.paste-from-clipboard.button.cancel' | translate }}</button>\n</footer>\n", styles: [":host{display:grid;grid-template-rows:1fr auto;grid-template-areas:\"main\" \"footer\";padding:var(--app-pane-padding)}:host main{grid-area:main;overflow-y:auto}:host footer{grid-area:footer;display:flex;flex-flow:row-reverse;justify-content:space-between;align-items:center}\n"] }]
|
|
1476
|
+
}] });
|
|
1477
|
+
|
|
1478
|
+
class VersionTileComponent {
|
|
1479
|
+
constructor() {
|
|
1480
|
+
this.tile = input.required();
|
|
1481
|
+
this.rendererInputs = computed(() => ({
|
|
1482
|
+
icon: this.tile().icon,
|
|
1483
|
+
version: this.tile().instanceData?.[BaseObjectTypeField.VERSION_NUMBER],
|
|
1484
|
+
date: this.tile().instanceData?.[BaseObjectTypeField.MODIFICATION_DATE],
|
|
1485
|
+
modified: this.tile().instanceData?.[BaseObjectTypeField.MODIFIED_BY + '_title']
|
|
1486
|
+
}));
|
|
1487
|
+
this.selectedVersion = output();
|
|
1488
|
+
}
|
|
1489
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: VersionTileComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1490
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.2.13", type: VersionTileComponent, isStandalone: true, selector: "ymd-version-tile", inputs: { tile: { classPropertyName: "tile", publicName: "tile", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { selectedVersion: "selectedVersion" }, ngImport: i0, template: `
|
|
1491
|
+
<div
|
|
1492
|
+
class="slots"
|
|
1493
|
+
title="{{
|
|
1494
|
+
'yuv.app.drive.versions.desctiption.label'
|
|
1495
|
+
| translate: { version: rendererInputs().version, modifieer: rendererInputs().modified, date: rendererInputs().date | date: 'medium' }
|
|
1496
|
+
}}"
|
|
1497
|
+
>
|
|
1498
|
+
<div data-slot="version" class="version">
|
|
1499
|
+
<span>{{ 'yuv.app.drive.versions.label' | translate }}: {{ rendererInputs().version }}</span>
|
|
1500
|
+
</div>
|
|
1501
|
+
<div data-slot="date" class="date" title="{{ rendererInputs().date | date: 'medium' }}">
|
|
1502
|
+
{{ rendererInputs().date | date: 'shortDate' }}
|
|
1503
|
+
</div>
|
|
1504
|
+
<div data-slot="modified" class="modified" title="{{ rendererInputs().modified }}">
|
|
1505
|
+
{{ rendererInputs().modified }}
|
|
1506
|
+
</div>
|
|
1507
|
+
</div>
|
|
1508
|
+
`, isInline: true, styles: [":host{--_tile-background: var(--tile-background, transparent);--_tile-icon-fill: var(--tile-icon-fill, currentColor);--_tile-padding: var(--tile-padding, var(--app-pane-padding));--_tile-action-icon-size: var(--tile-action-icon-size);--_tile-icon-size: var(--tile-icon-size);--_transition-duration: var(--transition-duration, .1s);display:flex;align-items:center;background-color:var(--_tile-background);padding:var(--_tile-padding);transition:background-color var(--_transition-duration)}:host .slots{display:grid;grid-template-columns:1fr 2fr;grid-template-rows:repeat(2,1fr);grid-template-areas:\"version version\" \"date modified\";flex:1;gap:calc(var(--_tile-padding) / 2) calc(var(--_tile-padding) * 2)}:host [data-slot]{align-items:center;-webkit-user-select:none;user-select:none;display:grid}:host [data-slot=icon]{--icon-renderer-icon-size: var(--_tile-icon-size);color:var(--_tile-icon-fill);width:0;grid-area:icon;display:grid;align-items:center;justify-content:center}:host [data-slot=version]{font-weight:700;grid-area:version}:host [data-slot=date]{grid-area:date}:host [data-slot=modified]{grid-area:modified;white-space:nowrap;justify-self:end}\n"], dependencies: [{ kind: "pipe", type: DatePipe, name: "date" }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }] }); }
|
|
1509
|
+
}
|
|
1510
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: VersionTileComponent, decorators: [{
|
|
1511
|
+
type: Component,
|
|
1512
|
+
args: [{ selector: 'ymd-version-tile', standalone: true, imports: [DatePipe, TranslateModule], template: `
|
|
1513
|
+
<div
|
|
1514
|
+
class="slots"
|
|
1515
|
+
title="{{
|
|
1516
|
+
'yuv.app.drive.versions.desctiption.label'
|
|
1517
|
+
| translate: { version: rendererInputs().version, modifieer: rendererInputs().modified, date: rendererInputs().date | date: 'medium' }
|
|
1518
|
+
}}"
|
|
1519
|
+
>
|
|
1520
|
+
<div data-slot="version" class="version">
|
|
1521
|
+
<span>{{ 'yuv.app.drive.versions.label' | translate }}: {{ rendererInputs().version }}</span>
|
|
1522
|
+
</div>
|
|
1523
|
+
<div data-slot="date" class="date" title="{{ rendererInputs().date | date: 'medium' }}">
|
|
1524
|
+
{{ rendererInputs().date | date: 'shortDate' }}
|
|
1525
|
+
</div>
|
|
1526
|
+
<div data-slot="modified" class="modified" title="{{ rendererInputs().modified }}">
|
|
1527
|
+
{{ rendererInputs().modified }}
|
|
1528
|
+
</div>
|
|
1529
|
+
</div>
|
|
1530
|
+
`, styles: [":host{--_tile-background: var(--tile-background, transparent);--_tile-icon-fill: var(--tile-icon-fill, currentColor);--_tile-padding: var(--tile-padding, var(--app-pane-padding));--_tile-action-icon-size: var(--tile-action-icon-size);--_tile-icon-size: var(--tile-icon-size);--_transition-duration: var(--transition-duration, .1s);display:flex;align-items:center;background-color:var(--_tile-background);padding:var(--_tile-padding);transition:background-color var(--_transition-duration)}:host .slots{display:grid;grid-template-columns:1fr 2fr;grid-template-rows:repeat(2,1fr);grid-template-areas:\"version version\" \"date modified\";flex:1;gap:calc(var(--_tile-padding) / 2) calc(var(--_tile-padding) * 2)}:host [data-slot]{align-items:center;-webkit-user-select:none;user-select:none;display:grid}:host [data-slot=icon]{--icon-renderer-icon-size: var(--_tile-icon-size);color:var(--_tile-icon-fill);width:0;grid-area:icon;display:grid;align-items:center;justify-content:center}:host [data-slot=version]{font-weight:700;grid-area:version}:host [data-slot=date]{grid-area:date}:host [data-slot=modified]{grid-area:modified;white-space:nowrap;justify-self:end}\n"] }]
|
|
1531
|
+
}] });
|
|
1532
|
+
|
|
1533
|
+
class VersionsListComponent {
|
|
1534
|
+
constructor() {
|
|
1535
|
+
this.#drive = inject(DriveService);
|
|
1536
|
+
this.versionsList = this.#drive.state$.versions.versionsList;
|
|
1537
|
+
this.selectedVersion = this.#drive.state$.versions.selectedVersion;
|
|
1538
|
+
this.selection = computed(() => (this.selectedVersion() || []).map((v) => v.version));
|
|
1539
|
+
this.listItems = viewChildren(ListItemDirective);
|
|
1540
|
+
this.#itemsEffect = effect(() => {
|
|
1541
|
+
const items = this.listItems();
|
|
1542
|
+
if (this.#keyManager)
|
|
1543
|
+
this.#keyManager.destroy();
|
|
1544
|
+
this.#keyManager = new ActiveDescendantKeyManager(items).withWrap();
|
|
1545
|
+
});
|
|
1546
|
+
}
|
|
1547
|
+
#drive;
|
|
1548
|
+
onBlur() {
|
|
1549
|
+
this.#keyManager.setActiveItem(-1);
|
|
1550
|
+
}
|
|
1551
|
+
onKeydown(event) {
|
|
1552
|
+
event.preventDefault();
|
|
1553
|
+
event.code === 'Escape' && this.#keyManager.setActiveItem(-1);
|
|
1554
|
+
event.target instanceof HTMLButtonElement && this.#keyManager.setActiveItem(-1);
|
|
1555
|
+
if (event.code === 'Space' || event.code === 'Enter') {
|
|
1556
|
+
const aii = this.#keyManager.activeItemIndex !== null ? this.#keyManager.activeItemIndex : -1;
|
|
1557
|
+
aii >= 0 && this.selectedVersionByIndex(aii);
|
|
1558
|
+
}
|
|
1559
|
+
else
|
|
1560
|
+
this.#keyManager?.onKeydown(event);
|
|
1561
|
+
}
|
|
1562
|
+
#keyManager;
|
|
1563
|
+
#itemsEffect;
|
|
1564
|
+
selectedVersionAction(event) {
|
|
1565
|
+
this.#drive.setBusy(true);
|
|
1566
|
+
this.#drive
|
|
1567
|
+
.setNewVersion(event.version)
|
|
1568
|
+
.pipe(finalize$1(() => this.#drive.setBusy(false)))
|
|
1569
|
+
.subscribe();
|
|
1570
|
+
}
|
|
1571
|
+
selectedVersionByIndex(index) {
|
|
1572
|
+
this.setSelectedVersion(this.versionsList()[index]);
|
|
1573
|
+
}
|
|
1574
|
+
setSelectedVersion(version) {
|
|
1575
|
+
this.#drive.setSelectedVersion(version).subscribe();
|
|
1576
|
+
}
|
|
1577
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: VersionsListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1578
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: VersionsListComponent, isStandalone: true, selector: "ymd-versions-list", host: { attributes: { "tabindex": "0", "role": "listbox" }, listeners: { "blur": "onBlur()", "keydown": "onKeydown($event)" } }, viewQueries: [{ propertyName: "listItems", predicate: ListItemDirective, descendants: true, isSignal: true }], ngImport: i0, template: ` @let versions = versionsList();
|
|
1579
|
+
@if (versions) {
|
|
1580
|
+
@for (version of versions; track $index) {
|
|
1581
|
+
<ymd-version-tile
|
|
1582
|
+
yuvListItem
|
|
1583
|
+
[tile]="version"
|
|
1584
|
+
[attr.aria-selected]="selection().includes(version.dmsObject.version)"
|
|
1585
|
+
[selected]="selection().includes(version.dmsObject.version)"
|
|
1586
|
+
(click.single)="setSelectedVersion(version)"
|
|
1587
|
+
(selectedVersion)="selectedVersionAction($event)"
|
|
1588
|
+
></ymd-version-tile>
|
|
1589
|
+
}
|
|
1590
|
+
}`, isInline: true, styles: [":host{--_tile-hover-background: var(--tile-hover-background, var(--item-focus-background-color));--_tile-selected-background: var(--tile-selected-background, var(--item-selected-background-color));--_tile-selected-icon-fill: var(--tile-selected-icon-fill, var(--color-accent))}:host ymd-version-tile{cursor:pointer;background-color:var(--tile-background)}:host ymd-version-tile:not(.last){border:var(--tile-border);border-width:var(--tile-border-width);margin-block-end:var(--tile-gap)}:host ymd-version-tile:hover,:host ymd-version-tile[aria-current=true]{--tile-background: var(--_tile-hover-background)}:host ymd-version-tile[aria-selected=true]{--tile-background: var(--_tile-selected-background);--tile-icon-fill: var(--_tile-selected-icon-fill)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: VersionTileComponent, selector: "ymd-version-tile", inputs: ["tile"], outputs: ["selectedVersion"] }, { kind: "directive", type: ListItemDirective, selector: "[yuvListItem]", inputs: ["disabled", "active", "selected"] }, { kind: "directive", type: ClickDoubleDirective, selector: "[click.single],[click.double]", inputs: ["debounceTime"], outputs: ["click.double", "click.single"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1591
|
+
}
|
|
1592
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: VersionsListComponent, decorators: [{
|
|
1593
|
+
type: Component,
|
|
1594
|
+
args: [{ selector: 'ymd-versions-list', standalone: true, imports: [CommonModule, VersionTileComponent, ListItemDirective, ClickDoubleDirective], template: ` @let versions = versionsList();
|
|
1595
|
+
@if (versions) {
|
|
1596
|
+
@for (version of versions; track $index) {
|
|
1597
|
+
<ymd-version-tile
|
|
1598
|
+
yuvListItem
|
|
1599
|
+
[tile]="version"
|
|
1600
|
+
[attr.aria-selected]="selection().includes(version.dmsObject.version)"
|
|
1601
|
+
[selected]="selection().includes(version.dmsObject.version)"
|
|
1602
|
+
(click.single)="setSelectedVersion(version)"
|
|
1603
|
+
(selectedVersion)="selectedVersionAction($event)"
|
|
1604
|
+
></ymd-version-tile>
|
|
1605
|
+
}
|
|
1606
|
+
}`, changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
1607
|
+
tabindex: '0',
|
|
1608
|
+
role: 'listbox'
|
|
1609
|
+
}, styles: [":host{--_tile-hover-background: var(--tile-hover-background, var(--item-focus-background-color));--_tile-selected-background: var(--tile-selected-background, var(--item-selected-background-color));--_tile-selected-icon-fill: var(--tile-selected-icon-fill, var(--color-accent))}:host ymd-version-tile{cursor:pointer;background-color:var(--tile-background)}:host ymd-version-tile:not(.last){border:var(--tile-border);border-width:var(--tile-border-width);margin-block-end:var(--tile-gap)}:host ymd-version-tile:hover,:host ymd-version-tile[aria-current=true]{--tile-background: var(--_tile-hover-background)}:host ymd-version-tile[aria-selected=true]{--tile-background: var(--_tile-selected-background);--tile-icon-fill: var(--_tile-selected-icon-fill)}\n"] }]
|
|
1610
|
+
}], propDecorators: { onBlur: [{
|
|
1611
|
+
type: HostListener,
|
|
1612
|
+
args: ['blur']
|
|
1613
|
+
}], onKeydown: [{
|
|
1614
|
+
type: HostListener,
|
|
1615
|
+
args: ['keydown', ['$event']]
|
|
1616
|
+
}] } });
|
|
1617
|
+
|
|
1618
|
+
const COMPONENTS = [VersionsListComponent, ObjectSummaryDataComponent, ObjectPreviewComponent];
|
|
1619
|
+
const MODULES = [YvcIconModule, YvcTabsModule, YvcSplitViewModule, TranslateModule];
|
|
1620
|
+
class ManageVersionsComponent {
|
|
1621
|
+
constructor() {
|
|
1622
|
+
this.overlayRef = inject(YvcOverlayRef);
|
|
1623
|
+
this.#drive = inject(DriveService);
|
|
1624
|
+
this.#shellService = inject(ShellService);
|
|
1625
|
+
this.versionsList = this.#drive.state$.versions.versionsList;
|
|
1626
|
+
this.selectedVersion = this.#drive.state$.versions.selectedVersion;
|
|
1627
|
+
this.selectedDmsObject = this.#drive.state$.selectedDmsObject;
|
|
1628
|
+
this.isLoading = this.#drive.state$.busy;
|
|
1629
|
+
this.item = this.overlayRef.data;
|
|
1630
|
+
this.layoutSettingIdBase = 'app.drive.versions.';
|
|
1631
|
+
this.dmsObject = computed(() => {
|
|
1632
|
+
const dmsObject = this.selectedDmsObject();
|
|
1633
|
+
return dmsObject
|
|
1634
|
+
? { id: dmsObject.data[BaseObjectTypeField.OBJECT_ID], name: dmsObject.data[FS_PROPERTIES.name] }
|
|
1635
|
+
: { id: null, name: '' };
|
|
1636
|
+
});
|
|
1637
|
+
this.id = computed(() => {
|
|
1638
|
+
const version = this.selectedVersion();
|
|
1639
|
+
return version ? version[0].id : null;
|
|
1640
|
+
});
|
|
1641
|
+
this.flavoredDmsObject = computed(() => {
|
|
1642
|
+
const o = this.selectedVersion();
|
|
1643
|
+
return o
|
|
1644
|
+
? {
|
|
1645
|
+
object: o[0],
|
|
1646
|
+
flavors: [
|
|
1647
|
+
{
|
|
1648
|
+
id: APP_SCHEMA.types['file']['id'],
|
|
1649
|
+
icon: APP_SCHEMA.types['file']['icon'],
|
|
1650
|
+
sot: FS_SOTS.object
|
|
1651
|
+
},
|
|
1652
|
+
...this.#shellService.getAppliedObjectFlavors(o[0]).applied
|
|
1653
|
+
]
|
|
1654
|
+
}
|
|
1655
|
+
: undefined;
|
|
1656
|
+
});
|
|
1657
|
+
this.disabledRestore = computed(() => {
|
|
1658
|
+
const selectedVersion = this.selectedVersion();
|
|
1659
|
+
const list = this.versionsList();
|
|
1660
|
+
return !(selectedVersion && selectedVersion[0].version !== list.length);
|
|
1661
|
+
});
|
|
1662
|
+
this.icons = {
|
|
1663
|
+
refresh: YUV_ICONS.refresh,
|
|
1664
|
+
close: ICONS.clear
|
|
1665
|
+
};
|
|
1666
|
+
}
|
|
1667
|
+
#drive;
|
|
1668
|
+
#shellService;
|
|
1669
|
+
#loadList() {
|
|
1670
|
+
this.#drive.setBusy(true);
|
|
1671
|
+
return forkJoin([
|
|
1672
|
+
this.#drive.getVersions(this.item.id),
|
|
1673
|
+
this.#drive.getSelectedDmsObject(this.item.id)
|
|
1674
|
+
]).pipe(finalize(() => this.#drive.setBusy(false)));
|
|
1675
|
+
}
|
|
1676
|
+
close() {
|
|
1677
|
+
this.overlayRef.close();
|
|
1678
|
+
}
|
|
1679
|
+
reloadList() {
|
|
1680
|
+
this.#loadList().subscribe();
|
|
1681
|
+
}
|
|
1682
|
+
setNewVersion() {
|
|
1683
|
+
this.#drive.setBusy(true);
|
|
1684
|
+
this.#drive
|
|
1685
|
+
.setNewVersion()
|
|
1686
|
+
.pipe(finalize(() => this.#drive.setBusy(false)))
|
|
1687
|
+
.subscribe();
|
|
1688
|
+
}
|
|
1689
|
+
ngOnInit() {
|
|
1690
|
+
this.#loadList().subscribe();
|
|
1691
|
+
}
|
|
1692
|
+
ngOnDestroy() {
|
|
1693
|
+
this.#drive.clearVersions();
|
|
1694
|
+
}
|
|
1695
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ManageVersionsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1696
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: ManageVersionsComponent, isStandalone: true, selector: "ymd-manage-versions", ngImport: i0, template: "@if (isLoading()) {\n <div class=\"yuv-loader-linear loader\"></div>\n}\n<yvc-split-view [gutterSize]=\"1\" [layoutSettingsID]=\"layoutSettingIdBase + 'split'\">\n <!-- Versions -->\n <ng-template yvcSplitArea [size]=\"60\">\n <div class=\"version-details\">\n <header>\n <span>{{ dmsObject().name }}</span>\n </header>\n <div class=\"details\">\n @let selected = selectedVersion();\n @if (selected && selected.length === 1) {\n <yvc-tabs [layoutSettingsID]=\"layoutSettingIdBase + 'tabs'\" class=\"versions-details\">\n <ng-template [yvcTab]=\"{ id: 'content', label: 'yuv.app.drive.object-metadata.tabs.content.title' | translate }\">\n <yuv-object-preview [dmsObject]=\"selected[0]\" [version]=\"selected[0].version\"></yuv-object-preview>\n </ng-template>\n <ng-template [yvcTab]=\"{ id: 'indexdata', label: 'yuv.app.drive.object-metadata.tabs.indexdata.title' | translate }\">\n <yuv-object-summary-data [dmsObject]=\"selected[0]\"></yuv-object-summary-data>\n </ng-template>\n </yvc-tabs>\n }\n </div>\n </div>\n </ng-template>\n <!-- Details -->\n <ng-template yvcSplitArea [size]=\"40\">\n <div class=\"versions\">\n <header>\n <h2>{{ 'yuv.app.drive.versions.header.label' | translate }}</h2>\n <div class=\"actions\">\n <button class=\"refresh\" title=\"refresh\" (click)=\"reloadList()\"><yvc-icon [svg]=\"icons.refresh\"></yvc-icon></button>\n <button class=\"close\" title=\"close\" (click)=\"close()\"><yvc-icon [svg]=\"icons.close\"></yvc-icon></button>\n </div>\n </header>\n <ymd-versions-list\n class=\"staggered\"\n [attr.aria-label]=\"'yuv.app.drive.files.content.aria.label' | translate\"\n [attr.aria-busy]=\"isLoading()\"\n [attr.role]=\"'listbox'\"\n [id]=\"id()\"\n > \n </ymd-versions-list>\n </div>\n </ng-template>\n</yvc-split-view>\n<footer>\n <div class=\"actions\">\n <button class=\"secondary\" [disabled]=\"disabledRestore()\" (click)=\"setNewVersion()\">{{ 'yuv.app.drive.action.set.new.versions.label' | translate }}</button>\n </div>\n</footer>\n", styles: [":host{height:100%;display:grid;grid-auto-columns:1fr;grid-auto-rows:1fr;grid-template-columns:1.7fr;grid-template-rows:.1px 2.7fr .2fr;gap:0px 0px;grid-template-areas:\"loader\" \"content\" \"footer\"}:host .loader{grid-area:loader}:host yvc-split-view{grid-area:content;height:100%}:host header{display:grid;grid-template-columns:2fr max-content;grid-template-rows:1fr max-content;gap:0px 0px;grid-auto-flow:row;grid-template-areas:\"label actions\" \"title title\";padding:var(--app-pane-padding);align-items:center}:host header span{font-size:var(--font-headline);font-weight:var(--font-weight-bold)}:host .versions,:host .version-details{display:flex;flex-flow:column;height:100%}:host .version-details .details{flex:1;overflow-y:hidden}:host .versions header{border-bottom:1px solid var(--panel-divider-color);padding-top:0}:host .versions .label{grid-area:label}:host .versions .actions{grid-area:actions;display:flex;justify-content:center;align-items:center}:host .versions .actions button{padding:0}:host .versions .title{grid-area:title}:host .versions .staggered{flex:1;overflow-y:scroll}:host .versions-details{height:100%}:host footer{grid-area:footer;display:flex;justify-content:flex-end;align-items:center;background:var(--panel-background);border-top:1px solid var(--panel-divider-color);gap:calc(var(--app-pane-padding) / 4);padding:calc(var(--app-pane-padding) / 2)}\n"], dependencies: [{ kind: "ngmodule", type: YvcIconModule }, { kind: "component", type: i1$1.Icon, selector: "yvc-icon", inputs: ["label", "svg", "svgSrc"] }, { kind: "ngmodule", type: YvcTabsModule }, { kind: "component", type: i2$2.Tabs, selector: "yvc-tabs", inputs: ["tabs", "layoutSettingsID", "panelOrder", "panelOrderIncludeUnmentioned", "cacheViews", "tabSplitEnabled", "tabRemoveEnabled"], outputs: ["tabSplit", "tabRemove", "tabChange"] }, { kind: "directive", type: i2$2.YvcTabDirective, selector: "[yvcTab]", inputs: ["yvcTab"] }, { kind: "ngmodule", type: YvcSplitViewModule }, { kind: "component", type: i3.SplitViewComponent, selector: "yvc-split-view", inputs: ["direction", "gutterSize", "restrictMove", "disabled", "gutterDblClickDuration", "layoutSettingsID"], outputs: ["layoutSettingsChange", "dragStart", "dragEnd", "gutterClick", "gutterDblClick"] }, { kind: "directive", type: i3.SplitAreaDirective, selector: "[yvcSplitArea]", inputs: ["size", "order", "minSize", "maxSize", "panelClass", "visible"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }, { kind: "component", type: VersionsListComponent, selector: "ymd-versions-list" }, { kind: "component", type: ObjectSummaryDataComponent, selector: "yuv-object-summary-data", inputs: ["dmsObject"] }, { kind: "component", type: ObjectPreviewComponent, selector: "yuv-object-preview", inputs: ["objectId", "dmsObject", "version"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1697
|
+
}
|
|
1698
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ManageVersionsComponent, decorators: [{
|
|
1699
|
+
type: Component,
|
|
1700
|
+
args: [{ selector: 'ymd-manage-versions', standalone: true, imports: [...MODULES, ...COMPONENTS], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (isLoading()) {\n <div class=\"yuv-loader-linear loader\"></div>\n}\n<yvc-split-view [gutterSize]=\"1\" [layoutSettingsID]=\"layoutSettingIdBase + 'split'\">\n <!-- Versions -->\n <ng-template yvcSplitArea [size]=\"60\">\n <div class=\"version-details\">\n <header>\n <span>{{ dmsObject().name }}</span>\n </header>\n <div class=\"details\">\n @let selected = selectedVersion();\n @if (selected && selected.length === 1) {\n <yvc-tabs [layoutSettingsID]=\"layoutSettingIdBase + 'tabs'\" class=\"versions-details\">\n <ng-template [yvcTab]=\"{ id: 'content', label: 'yuv.app.drive.object-metadata.tabs.content.title' | translate }\">\n <yuv-object-preview [dmsObject]=\"selected[0]\" [version]=\"selected[0].version\"></yuv-object-preview>\n </ng-template>\n <ng-template [yvcTab]=\"{ id: 'indexdata', label: 'yuv.app.drive.object-metadata.tabs.indexdata.title' | translate }\">\n <yuv-object-summary-data [dmsObject]=\"selected[0]\"></yuv-object-summary-data>\n </ng-template>\n </yvc-tabs>\n }\n </div>\n </div>\n </ng-template>\n <!-- Details -->\n <ng-template yvcSplitArea [size]=\"40\">\n <div class=\"versions\">\n <header>\n <h2>{{ 'yuv.app.drive.versions.header.label' | translate }}</h2>\n <div class=\"actions\">\n <button class=\"refresh\" title=\"refresh\" (click)=\"reloadList()\"><yvc-icon [svg]=\"icons.refresh\"></yvc-icon></button>\n <button class=\"close\" title=\"close\" (click)=\"close()\"><yvc-icon [svg]=\"icons.close\"></yvc-icon></button>\n </div>\n </header>\n <ymd-versions-list\n class=\"staggered\"\n [attr.aria-label]=\"'yuv.app.drive.files.content.aria.label' | translate\"\n [attr.aria-busy]=\"isLoading()\"\n [attr.role]=\"'listbox'\"\n [id]=\"id()\"\n > \n </ymd-versions-list>\n </div>\n </ng-template>\n</yvc-split-view>\n<footer>\n <div class=\"actions\">\n <button class=\"secondary\" [disabled]=\"disabledRestore()\" (click)=\"setNewVersion()\">{{ 'yuv.app.drive.action.set.new.versions.label' | translate }}</button>\n </div>\n</footer>\n", styles: [":host{height:100%;display:grid;grid-auto-columns:1fr;grid-auto-rows:1fr;grid-template-columns:1.7fr;grid-template-rows:.1px 2.7fr .2fr;gap:0px 0px;grid-template-areas:\"loader\" \"content\" \"footer\"}:host .loader{grid-area:loader}:host yvc-split-view{grid-area:content;height:100%}:host header{display:grid;grid-template-columns:2fr max-content;grid-template-rows:1fr max-content;gap:0px 0px;grid-auto-flow:row;grid-template-areas:\"label actions\" \"title title\";padding:var(--app-pane-padding);align-items:center}:host header span{font-size:var(--font-headline);font-weight:var(--font-weight-bold)}:host .versions,:host .version-details{display:flex;flex-flow:column;height:100%}:host .version-details .details{flex:1;overflow-y:hidden}:host .versions header{border-bottom:1px solid var(--panel-divider-color);padding-top:0}:host .versions .label{grid-area:label}:host .versions .actions{grid-area:actions;display:flex;justify-content:center;align-items:center}:host .versions .actions button{padding:0}:host .versions .title{grid-area:title}:host .versions .staggered{flex:1;overflow-y:scroll}:host .versions-details{height:100%}:host footer{grid-area:footer;display:flex;justify-content:flex-end;align-items:center;background:var(--panel-background);border-top:1px solid var(--panel-divider-color);gap:calc(var(--app-pane-padding) / 4);padding:calc(var(--app-pane-padding) / 2)}\n"] }]
|
|
1701
|
+
}] });
|
|
1702
|
+
|
|
1703
|
+
class ManageVersionsAction extends AbstractContextAction {
|
|
1704
|
+
constructor() {
|
|
1705
|
+
super(...arguments);
|
|
1706
|
+
this.translate = inject(TranslateService);
|
|
1707
|
+
this.overlay = inject(YvcOverlayService);
|
|
1708
|
+
this.id = 'app.drive.action.manage-versions';
|
|
1709
|
+
this.label = this.translate.instant('yuv.app.drive.action.manage-versions.label');
|
|
1710
|
+
this.description = this.translate.instant('yuv.app.drive.action.manage-versions.description');
|
|
1711
|
+
this.priority = 2;
|
|
1712
|
+
this.icon = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#5f6368" viewBox="0 -960 960 960"><path d="M120-560v-240h80v94q51-64 124.5-99T480-840q150 0 255 105t105 255h-80q0-117-81.5-198.5T480-760q-69 0-129 32t-101 88h110v80H120Zm2 120h82q12 93 76.5 157.5T435-204l48 84q-138 0-242-91.5T122-440Zm412 70-94-94v-216h80v184l56 56-42 70ZM719 0l-12-60q-12-5-22.5-10.5T663-84l-58 18-40-68 46-40q-2-13-2-26t2-26l-46-40 40-68 58 18q11-8 21.5-13.5T707-340l12-60h80l12 60q12 5 23 11.5t21 14.5l58-20 40 70-46 40q2 13 2 25t-2 25l46 40-40 68-58-18q-11 8-21.5 13.5T811-60L799 0h-80Zm40-120q33 0 56.5-23.5T839-200q0-33-23.5-56.5T759-280q-33 0-56.5 23.5T679-200q0 33 23.5 56.5T759-120Z"/></svg>';
|
|
1713
|
+
this.group = 'common';
|
|
1714
|
+
this.range = SelectionRange.SINGLE_SELECT;
|
|
1715
|
+
this.supports = {};
|
|
1716
|
+
}
|
|
1717
|
+
isExecutable(selection) {
|
|
1718
|
+
return of(selection && selection[0] && selection[0].version > 1 && !selection[0].isFolder);
|
|
1719
|
+
}
|
|
1720
|
+
run(selection) {
|
|
1721
|
+
this.overlay.open(ManageVersionsComponent, selection[0], {
|
|
1722
|
+
width: '60vw',
|
|
1723
|
+
maxWidth: '80vw',
|
|
1724
|
+
height: '80vh'
|
|
1725
|
+
});
|
|
1726
|
+
return of(true);
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1730
|
+
class DriveFrameComponent {
|
|
1731
|
+
#router;
|
|
1732
|
+
#route;
|
|
1733
|
+
#drive;
|
|
1734
|
+
#actionsService;
|
|
1735
|
+
#destroyRef;
|
|
1736
|
+
#actions;
|
|
1737
|
+
constructor() {
|
|
1738
|
+
this.#router = inject(Router);
|
|
1739
|
+
this.#route = inject(ActivatedRoute);
|
|
1740
|
+
this.#drive = inject(DriveService);
|
|
1741
|
+
this.#actionsService = inject(ActionsService);
|
|
1742
|
+
this.#destroyRef = inject(DestroyRef);
|
|
1743
|
+
this.query = this.#drive.state$.query;
|
|
1744
|
+
this.currentFolder = this.#drive.state$.currentFolder;
|
|
1745
|
+
this.busy = this.#drive.state$.busy;
|
|
1746
|
+
this.appName = APP_SCHEMA.name;
|
|
1747
|
+
this.appIcon = APP_SCHEMA.icon;
|
|
1748
|
+
this.icons = {
|
|
1749
|
+
...APP_DRIVE_ICONS,
|
|
1750
|
+
search: ICONS.search,
|
|
1751
|
+
add: YUV_ICONS.add
|
|
1752
|
+
};
|
|
1753
|
+
this.headerNavItems = [
|
|
1754
|
+
// TODO: enable again once favorite feature is implemented
|
|
1755
|
+
// {
|
|
1756
|
+
// id: 'favorites',
|
|
1757
|
+
// disabled: true,
|
|
1758
|
+
// label: this.translate.instant('yuv.app.drive.nav.favorites'),
|
|
1759
|
+
// icon: this.icons.favorite,
|
|
1760
|
+
// callback: () => {
|
|
1761
|
+
// this.router.navigate(['favorites'], {relativeTo: this.route})
|
|
1762
|
+
// }
|
|
1763
|
+
// }
|
|
1764
|
+
];
|
|
1765
|
+
this.#actions = [
|
|
1766
|
+
{ id: APP_ACTIONS.rename, action: RenameAction },
|
|
1767
|
+
{ id: APP_ACTIONS.paste, action: PasteAction },
|
|
1768
|
+
{ id: APP_ACTIONS.contentUpdate, action: UpdateContentAction },
|
|
1769
|
+
{ id: APP_ACTIONS.copyLink, action: CopyLinkAction },
|
|
1770
|
+
{ id: APP_ACTIONS.manageVersions, action: ManageVersionsAction }
|
|
1771
|
+
];
|
|
1772
|
+
this.#registerActions();
|
|
1773
|
+
// TODO: make use of global shortcuts
|
|
1774
|
+
// this.shellService.globalShortcuts$.pipe(takeUntilDestroyed()).subscribe((s: GlobalShortcut) => {
|
|
1775
|
+
// if (s === GlobalShortcut.search) this.router.navigate([{ outlets: { modal: ['find'] } }], { relativeTo: this.route });
|
|
1776
|
+
// });
|
|
1777
|
+
}
|
|
1778
|
+
#trackRouteChanges() {
|
|
1779
|
+
// listen to navigation/route changes in order to restore it later on
|
|
1780
|
+
this.#router.events
|
|
1781
|
+
.pipe(takeUntilDestroyed(this.#destroyRef), filter$1((e) => e instanceof NavigationEnd))
|
|
1782
|
+
.subscribe((e) => {
|
|
1783
|
+
this.#drive.lastRouteURL = e.urlAfterRedirects;
|
|
1784
|
+
});
|
|
1785
|
+
}
|
|
1786
|
+
onUploadProgressResultItemClick(uploadRes) {
|
|
1787
|
+
if (uploadRes && uploadRes.objectId) {
|
|
1788
|
+
this.#router.navigate(['object', uploadRes.objectId], { relativeTo: this.#route });
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
1791
|
+
#registerActions() {
|
|
1792
|
+
this.#actionsService.registerActions(this.#actions);
|
|
1793
|
+
}
|
|
1794
|
+
ngOnInit() {
|
|
1795
|
+
if (this.#drive.lastRouteURL)
|
|
1796
|
+
this.#router.navigateByUrl(this.#drive.lastRouteURL).then(() => this.#trackRouteChanges());
|
|
1797
|
+
else
|
|
1798
|
+
this.#trackRouteChanges();
|
|
1799
|
+
}
|
|
1800
|
+
ngOnDestroy() {
|
|
1801
|
+
this.#actions.forEach((a) => this.#actionsService.concealActions([a.id]));
|
|
1802
|
+
}
|
|
1803
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DriveFrameComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1804
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: DriveFrameComponent, isStandalone: true, selector: "ymd-drive", ngImport: i0, template: "<yuv-upload-progress (resultItemClick)=\"onUploadProgressResultItemClick($event)\"></yuv-upload-progress>\n\n<header>\n <yuv-app-logo [label]=\"appName\" routerLink=\"files\"></yuv-app-logo>\n\n <nav [attr.aria-label]=\"'yuv.app.drive.navigation.aria.label' | translate\">\n <yvc-overflow-menu [menuItems]=\"headerNavItems\"></yvc-overflow-menu>\n </nav>\n</header>\n\n<section class=\"drive-main__content\" [attr.aria-label]=\"'yuv.app.drive.content.aria.label' | translate\">\n <router-outlet></router-outlet>\n</section>\n\n<router-outlet name=\"modal\"></router-outlet>\n", styles: [":host{--app-drive-header-background: var(--panel-background);display:flex;flex-flow:column;height:100%}:host header{flex:0 0 auto;display:grid;grid-template-rows:auto;grid-template-columns:auto 1fr auto auto;grid-template-areas:\"logo . . nav\";gap:var(--app-pane-padding);align-items:center;height:var(--client-shell-bar-width);background-color:var(--app-drive-header-background)}:host header yuv-app-logo{--band-icon-size: 50px;--icon-color: var(--app-drive-header-background)}:host header ymd-drive-search{max-width:400px}:host header nav{grid-area:nav}:host header nav yvc-overflow-menu{--menu-item-padding: calc(var(--app-pane-padding) / 4);--menu-item-icon-size: 18px;--menu-item-gap: calc(var(--app-pane-padding) / 4)}:host .drive-main__content{flex:1;overflow-y:hidden}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1$2.RouterOutlet, selector: "router-outlet", inputs: ["name"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "directive", type: i1$2.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: YvcOverflowMenuComponent, selector: "yvc-overflow-menu", inputs: ["overflowIcon", "groupLabels", "menuItems", "hideLabels"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: YvcOverlayModule }, { kind: "ngmodule", type: YvcIconModule }, { kind: "component", type: AppLogoComponent, selector: "yuv-app-logo", inputs: ["icon", "label"] }, { kind: "component", type: UploadProgressComponent, selector: "yuv-upload-progress", outputs: ["resultItemClick"] }] }); }
|
|
1805
|
+
}
|
|
1806
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DriveFrameComponent, decorators: [{
|
|
1807
|
+
type: Component,
|
|
1808
|
+
args: [{ selector: 'ymd-drive', standalone: true, imports: [
|
|
1809
|
+
CommonModule,
|
|
1810
|
+
RouterModule,
|
|
1811
|
+
YvcOverflowMenuComponent,
|
|
1812
|
+
ReactiveFormsModule,
|
|
1813
|
+
TranslateModule,
|
|
1814
|
+
YvcOverlayModule,
|
|
1815
|
+
YvcIconModule,
|
|
1816
|
+
AppLogoComponent,
|
|
1817
|
+
UploadProgressComponent
|
|
1818
|
+
], template: "<yuv-upload-progress (resultItemClick)=\"onUploadProgressResultItemClick($event)\"></yuv-upload-progress>\n\n<header>\n <yuv-app-logo [label]=\"appName\" routerLink=\"files\"></yuv-app-logo>\n\n <nav [attr.aria-label]=\"'yuv.app.drive.navigation.aria.label' | translate\">\n <yvc-overflow-menu [menuItems]=\"headerNavItems\"></yvc-overflow-menu>\n </nav>\n</header>\n\n<section class=\"drive-main__content\" [attr.aria-label]=\"'yuv.app.drive.content.aria.label' | translate\">\n <router-outlet></router-outlet>\n</section>\n\n<router-outlet name=\"modal\"></router-outlet>\n", styles: [":host{--app-drive-header-background: var(--panel-background);display:flex;flex-flow:column;height:100%}:host header{flex:0 0 auto;display:grid;grid-template-rows:auto;grid-template-columns:auto 1fr auto auto;grid-template-areas:\"logo . . nav\";gap:var(--app-pane-padding);align-items:center;height:var(--client-shell-bar-width);background-color:var(--app-drive-header-background)}:host header yuv-app-logo{--band-icon-size: 50px;--icon-color: var(--app-drive-header-background)}:host header ymd-drive-search{max-width:400px}:host header nav{grid-area:nav}:host header nav yvc-overflow-menu{--menu-item-padding: calc(var(--app-pane-padding) / 4);--menu-item-icon-size: 18px;--menu-item-gap: calc(var(--app-pane-padding) / 4)}:host .drive-main__content{flex:1;overflow-y:hidden}\n"] }]
|
|
1819
|
+
}], ctorParameters: () => [] });
|
|
1820
|
+
|
|
1821
|
+
class RibbonComponent {
|
|
1822
|
+
#drive;
|
|
1823
|
+
#clipboard;
|
|
1824
|
+
#actionsService;
|
|
1825
|
+
#objectsEffect;
|
|
1826
|
+
constructor() {
|
|
1827
|
+
this.primarySlot = contentChild('primaryActions');
|
|
1828
|
+
this.secondarySlot = contentChild('secondaryActions');
|
|
1829
|
+
this.#drive = inject(DriveService);
|
|
1830
|
+
this.#clipboard = inject(ClipboardService);
|
|
1831
|
+
this.#actionsService = inject(ActionsService);
|
|
1832
|
+
this._defaultMenuItems = this.#drive.getDefaultRibbonActions().map((a) => ({
|
|
1833
|
+
id: a.id,
|
|
1834
|
+
icon: a.icon,
|
|
1835
|
+
label: a.label,
|
|
1836
|
+
disabled: true,
|
|
1837
|
+
group: 'default',
|
|
1838
|
+
callback: () => this.executeAction(a)
|
|
1839
|
+
}));
|
|
1840
|
+
this.clipboardBucket = APP_ID;
|
|
1841
|
+
this.busy = input(false);
|
|
1842
|
+
this.enableClipboard = input(false);
|
|
1843
|
+
this.menuItems = this._defaultMenuItems;
|
|
1844
|
+
this.objects = input();
|
|
1845
|
+
this.#objectsEffect = effect(() => {
|
|
1846
|
+
this.menuItems = this._defaultMenuItems;
|
|
1847
|
+
this.#getActionsAndSetupItems(this.objects() || []);
|
|
1848
|
+
});
|
|
1849
|
+
this.excludeActions = input();
|
|
1850
|
+
this.#clipboard
|
|
1851
|
+
.clipboard$(this.clipboardBucket)
|
|
1852
|
+
.pipe(takeUntilDestroyed())
|
|
1853
|
+
.subscribe({
|
|
1854
|
+
next: () => this.#getActionsAndSetupItems(this.objects() || [])
|
|
1855
|
+
});
|
|
1856
|
+
}
|
|
1857
|
+
#getActionsAndSetupItems(objects) {
|
|
1858
|
+
this.#actionsService
|
|
1859
|
+
.getActions(objects, {
|
|
1860
|
+
context: ACTION_CONTEXT,
|
|
1861
|
+
exclude: this.excludeActions()
|
|
1862
|
+
})
|
|
1863
|
+
.subscribe({ next: (res) => this._setupMenuItems(res) });
|
|
1864
|
+
}
|
|
1865
|
+
executeAction(a) {
|
|
1866
|
+
const o = this.objects();
|
|
1867
|
+
if (o && this._isAction(a))
|
|
1868
|
+
a.run(o);
|
|
1869
|
+
}
|
|
1870
|
+
onClipboardPaste() {
|
|
1871
|
+
this.#drive.setBusy(true);
|
|
1872
|
+
this.#drive
|
|
1873
|
+
.pasteFromClipboard()
|
|
1874
|
+
.pipe(finalize(() => this.#drive.setBusy(false)))
|
|
1875
|
+
.subscribe({
|
|
1876
|
+
next: () => this.#clipboard.clear(this.clipboardBucket)
|
|
1877
|
+
});
|
|
1878
|
+
}
|
|
1879
|
+
_isAction(a) {
|
|
1880
|
+
return !!a['run'];
|
|
1881
|
+
}
|
|
1882
|
+
_setupMenuItems(actions) {
|
|
1883
|
+
// en-/disable default actions
|
|
1884
|
+
this._defaultMenuItems.forEach((mi) => {
|
|
1885
|
+
mi.disabled = !actions.find((a) => a.id === mi.id);
|
|
1886
|
+
});
|
|
1887
|
+
const defaultActionIds = this._defaultMenuItems.map((mi) => mi.id);
|
|
1888
|
+
this.menuItems = [
|
|
1889
|
+
...this._defaultMenuItems,
|
|
1890
|
+
...actions
|
|
1891
|
+
.filter((a) => !defaultActionIds.includes(a.id))
|
|
1892
|
+
.map((a) => ({
|
|
1893
|
+
id: a.id,
|
|
1894
|
+
icon: a.icon,
|
|
1895
|
+
label: a.label,
|
|
1896
|
+
group: 'aside',
|
|
1897
|
+
callback: () => this.executeAction(a)
|
|
1898
|
+
}))
|
|
1899
|
+
];
|
|
1900
|
+
}
|
|
1901
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RibbonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1902
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: RibbonComponent, isStandalone: true, selector: "ymd-ribbon", inputs: { busy: { classPropertyName: "busy", publicName: "busy", isSignal: true, isRequired: false, transformFunction: null }, enableClipboard: { classPropertyName: "enableClipboard", publicName: "enableClipboard", isSignal: true, isRequired: false, transformFunction: null }, objects: { classPropertyName: "objects", publicName: "objects", isSignal: true, isRequired: false, transformFunction: null }, excludeActions: { classPropertyName: "excludeActions", publicName: "excludeActions", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "ymd-ribbon" }, queries: [{ propertyName: "primarySlot", first: true, predicate: ["primaryActions"], descendants: true, isSignal: true }, { propertyName: "secondarySlot", first: true, predicate: ["secondaryActions"], descendants: true, isSignal: true }], ngImport: i0, template: "@let primary = primarySlot();\n@let secondary = secondarySlot();\n\n@if (primary) {\n <div class=\"primary-actions\">\n <ng-container [ngTemplateOutlet]=\"primary\"></ng-container>\n </div>\n}\n\n<div class=\"object-actions\">\n @if (enableClipboard()) {\n <yuv-clipboard class=\"dark\" [bucket]=\"clipboardBucket\" [enablePaste]=\"true\" (paste)=\"onClipboardPaste()\"></yuv-clipboard>\n }\n <yvc-overflow-menu [hideLabels]=\"true\" [menuItems]=\"menuItems\"></yvc-overflow-menu>\n</div>\n\n@if (secondary) {\n <div class=\"secondary-actions\">\n <ng-container [ngTemplateOutlet]=\"secondary\"></ng-container>\n </div>\n}\n\n@if (busy()) {\n <div class=\"yuv-loader-linear\"></div>\n}\n", styles: ["ymd-ribbon{--ribbon-button-padding: calc(var(--app-pane-padding) / 4);--ribbon-button-border-radius: 2px;--ribbon-button-gap: calc(var(--app-pane-padding) / 4);--ribbon-icon-size: 20px;flex:0 0 auto;display:grid;grid-template-columns:auto 1fr auto;grid-template-areas:\"primary actions sort secondary\";align-items:center;gap:calc(var(--app-pane-padding) / 2);border-block-end:1px solid var(--panel-divider-color);position:relative;padding:calc(var(--app-pane-padding) / 4) calc(var(--app-pane-padding) / 2)}ymd-ribbon .primary-actions{grid-area:primary;overflow-x:auto}ymd-ribbon .secondary-actions{grid-area:secondary;overflow-x:auto}ymd-ribbon .object-actions{grid-area:actions;align-self:stretch;overflow-x:auto;border-color:var(--panel-divider-color);border-width:0 1px 0 1px;border-style:solid;display:grid;grid-template-rows:1fr;grid-template-columns:1fr;align-items:center}ymd-ribbon .object-actions yvc-overflow-menu{--menu-item-padding: var(--ribbon-button-padding);--menu-item-icon-size: var(--ribbon-icon-size);--menu-item-gap: var(--ribbon-button-gap);--menu-item-max-label-width: 10ch;grid-row:1;grid-column:1}ymd-ribbon .object-actions yuv-clipboard{--clipboard-background-color: var(--panel-divider-color);margin-inline:calc(var(--app-pane-padding) / 2);height:100%;grid-row:1;grid-column:1;z-index:1}ymd-ribbon .object-actions ymd-sort{grid-row:1;grid-column:1}ymd-ribbon .sort-column{grid-area:sort;display:flex;align-items:center;gap:var(--ribbon-button-gap);padding:0 var(--ribbon-button-padding)}ymd-ribbon .yuv-loader-linear{position:absolute;bottom:-2px;left:0;right:0;width:auto;height:2px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ClipboardComponent, selector: "yuv-clipboard", inputs: ["enablePaste", "bucket"], outputs: ["paste"] }, { kind: "component", type: YvcOverflowMenuComponent, selector: "yvc-overflow-menu", inputs: ["overflowIcon", "groupLabels", "menuItems", "hideLabels"] }], encapsulation: i0.ViewEncapsulation.None }); }
|
|
1903
|
+
}
|
|
1904
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RibbonComponent, decorators: [{
|
|
1905
|
+
type: Component,
|
|
1906
|
+
args: [{ selector: 'ymd-ribbon', standalone: true, imports: [CommonModule, ClipboardComponent, YvcOverflowMenuComponent], encapsulation: ViewEncapsulation.None, host: {
|
|
1907
|
+
class: 'ymd-ribbon'
|
|
1908
|
+
}, template: "@let primary = primarySlot();\n@let secondary = secondarySlot();\n\n@if (primary) {\n <div class=\"primary-actions\">\n <ng-container [ngTemplateOutlet]=\"primary\"></ng-container>\n </div>\n}\n\n<div class=\"object-actions\">\n @if (enableClipboard()) {\n <yuv-clipboard class=\"dark\" [bucket]=\"clipboardBucket\" [enablePaste]=\"true\" (paste)=\"onClipboardPaste()\"></yuv-clipboard>\n }\n <yvc-overflow-menu [hideLabels]=\"true\" [menuItems]=\"menuItems\"></yvc-overflow-menu>\n</div>\n\n@if (secondary) {\n <div class=\"secondary-actions\">\n <ng-container [ngTemplateOutlet]=\"secondary\"></ng-container>\n </div>\n}\n\n@if (busy()) {\n <div class=\"yuv-loader-linear\"></div>\n}\n", styles: ["ymd-ribbon{--ribbon-button-padding: calc(var(--app-pane-padding) / 4);--ribbon-button-border-radius: 2px;--ribbon-button-gap: calc(var(--app-pane-padding) / 4);--ribbon-icon-size: 20px;flex:0 0 auto;display:grid;grid-template-columns:auto 1fr auto;grid-template-areas:\"primary actions sort secondary\";align-items:center;gap:calc(var(--app-pane-padding) / 2);border-block-end:1px solid var(--panel-divider-color);position:relative;padding:calc(var(--app-pane-padding) / 4) calc(var(--app-pane-padding) / 2)}ymd-ribbon .primary-actions{grid-area:primary;overflow-x:auto}ymd-ribbon .secondary-actions{grid-area:secondary;overflow-x:auto}ymd-ribbon .object-actions{grid-area:actions;align-self:stretch;overflow-x:auto;border-color:var(--panel-divider-color);border-width:0 1px 0 1px;border-style:solid;display:grid;grid-template-rows:1fr;grid-template-columns:1fr;align-items:center}ymd-ribbon .object-actions yvc-overflow-menu{--menu-item-padding: var(--ribbon-button-padding);--menu-item-icon-size: var(--ribbon-icon-size);--menu-item-gap: var(--ribbon-button-gap);--menu-item-max-label-width: 10ch;grid-row:1;grid-column:1}ymd-ribbon .object-actions yuv-clipboard{--clipboard-background-color: var(--panel-divider-color);margin-inline:calc(var(--app-pane-padding) / 2);height:100%;grid-row:1;grid-column:1;z-index:1}ymd-ribbon .object-actions ymd-sort{grid-row:1;grid-column:1}ymd-ribbon .sort-column{grid-area:sort;display:flex;align-items:center;gap:var(--ribbon-button-gap);padding:0 var(--ribbon-button-padding)}ymd-ribbon .yuv-loader-linear{position:absolute;bottom:-2px;left:0;right:0;width:auto;height:2px}\n"] }]
|
|
1909
|
+
}], ctorParameters: () => [] });
|
|
1910
|
+
|
|
1911
|
+
class StoredQueryService {
|
|
1912
|
+
constructor() {
|
|
1913
|
+
this.userService = inject(UserService);
|
|
1914
|
+
this.translate = inject(TranslateService);
|
|
1915
|
+
}
|
|
1916
|
+
getStoredQuery(id) {
|
|
1917
|
+
const q = STORED_QUERIES[id];
|
|
1918
|
+
if (!q)
|
|
1919
|
+
return undefined;
|
|
1920
|
+
try {
|
|
1921
|
+
// if query has no label try to resolve from language resources
|
|
1922
|
+
return {
|
|
1923
|
+
label: q.label || this.translate.instant(id),
|
|
1924
|
+
query: JSON.parse(this._replaceVars(q.query))
|
|
1925
|
+
};
|
|
1926
|
+
}
|
|
1927
|
+
catch (e) {
|
|
1928
|
+
return undefined;
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
_replaceVars(str) {
|
|
1932
|
+
const vars = [{ placeholder: '##me##', replace: this.userService.getCurrentUser().id }];
|
|
1933
|
+
vars.forEach((v) => {
|
|
1934
|
+
str = str.replaceAll(v.placeholder, v.replace);
|
|
1935
|
+
});
|
|
1936
|
+
return str;
|
|
1937
|
+
}
|
|
1938
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StoredQueryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1939
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StoredQueryService, providedIn: 'root' }); }
|
|
1940
|
+
}
|
|
1941
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StoredQueryService, decorators: [{
|
|
1942
|
+
type: Injectable,
|
|
1943
|
+
args: [{
|
|
1944
|
+
providedIn: 'root'
|
|
1945
|
+
}]
|
|
1946
|
+
}] });
|
|
1947
|
+
|
|
1948
|
+
class DateRangePickerComponent {
|
|
1949
|
+
constructor() {
|
|
1950
|
+
this.#oRef = inject(YvcOverlayRef);
|
|
1951
|
+
this.#fb = inject(FormBuilder);
|
|
1952
|
+
this.form = this.#fb.group({
|
|
1953
|
+
range: this.#fb.control(undefined, Validators.required)
|
|
1954
|
+
});
|
|
1955
|
+
this.range = input(this.#oRef.data.range);
|
|
1956
|
+
this.rangeChange = output();
|
|
1957
|
+
this.#rangeEffect = effect(() => {
|
|
1958
|
+
const range = this.range();
|
|
1959
|
+
this.form.patchValue({ range });
|
|
1960
|
+
});
|
|
1961
|
+
}
|
|
1962
|
+
#oRef;
|
|
1963
|
+
#fb;
|
|
1964
|
+
#rangeEffect;
|
|
1965
|
+
apply() {
|
|
1966
|
+
this.rangeChange.emit(this.form.value.range || undefined);
|
|
1967
|
+
this.#oRef?.close(this.form.value.range);
|
|
1968
|
+
}
|
|
1969
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DateRangePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1970
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.2.13", type: DateRangePickerComponent, isStandalone: true, selector: "ymd-date-range-picker", inputs: { range: { classPropertyName: "range", publicName: "range", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { rangeChange: "rangeChange" }, ngImport: i0, template: "<form [formGroup]=\"form\" (ngSubmit)=\"apply()\">\n <h2>{{ 'yuv.app.drive.search.filter.option.date.custom.overlay.title' | translate }}</h2>\n <yuv-datetime-range [withTime]=\"false\" formControlName=\"range\"></yuv-datetime-range>\n <button class=\"primary\" [disabled]=\"form.invalid\">{{ 'yuv.app.drive.search.filter.option.date.custom.overlay.button.apply' | translate }}</button>\n</form>\n", styles: [":host{--form-element-border-color: transparent;--yvc-form-element-border-color: transparent}:host form{display:grid;grid-template-columns:1fr auto;grid-template-rows:repeat(3,auto);grid-template-areas:\"title title\" \"input input\" \". button\";gap:var(--app-pane-padding);padding:var(--app-pane-padding)}:host form h2{grid-area:title;margin:0}:host form yuv-datetime-range{grid-area:input;border:1px solid var(--text-color-hint);padding:1px 2px;border-radius:2px}:host form button{grid-area:button}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }, { kind: "component", type: DatetimeRangeComponent, selector: "yuv-datetime-range", inputs: ["withTime", "readonly", "operator"] }] }); }
|
|
1971
|
+
}
|
|
1972
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DateRangePickerComponent, decorators: [{
|
|
1973
|
+
type: Component,
|
|
1974
|
+
args: [{ selector: 'ymd-date-range-picker', standalone: true, imports: [CommonModule, ReactiveFormsModule, TranslateModule, DatetimeRangeComponent], template: "<form [formGroup]=\"form\" (ngSubmit)=\"apply()\">\n <h2>{{ 'yuv.app.drive.search.filter.option.date.custom.overlay.title' | translate }}</h2>\n <yuv-datetime-range [withTime]=\"false\" formControlName=\"range\"></yuv-datetime-range>\n <button class=\"primary\" [disabled]=\"form.invalid\">{{ 'yuv.app.drive.search.filter.option.date.custom.overlay.button.apply' | translate }}</button>\n</form>\n", styles: [":host{--form-element-border-color: transparent;--yvc-form-element-border-color: transparent}:host form{display:grid;grid-template-columns:1fr auto;grid-template-rows:repeat(3,auto);grid-template-areas:\"title title\" \"input input\" \". button\";gap:var(--app-pane-padding);padding:var(--app-pane-padding)}:host form h2{grid-area:title;margin:0}:host form yuv-datetime-range{grid-area:input;border:1px solid var(--text-color-hint);padding:1px 2px;border-radius:2px}:host form button{grid-area:button}\n"] }]
|
|
1975
|
+
}] });
|
|
1976
|
+
|
|
1977
|
+
class SearchFilterComponent {
|
|
1978
|
+
#shell;
|
|
1979
|
+
#fb;
|
|
1980
|
+
#overlay;
|
|
1981
|
+
#CREATED_CUSTOM;
|
|
1982
|
+
#flavors;
|
|
1983
|
+
#customDateRange;
|
|
1984
|
+
constructor() {
|
|
1985
|
+
this.#shell = inject(ShellService);
|
|
1986
|
+
this.#fb = inject(FormBuilder);
|
|
1987
|
+
this.#overlay = inject(YvcOverlayService);
|
|
1988
|
+
this.#CREATED_CUSTOM = 'custom';
|
|
1989
|
+
this.translate = inject(TranslateService$1);
|
|
1990
|
+
this.ANY_OPTION = 'any';
|
|
1991
|
+
this.#flavors = this.#shell.getObjectFlavors();
|
|
1992
|
+
this.typeOptions = signal([]);
|
|
1993
|
+
this.dateOptions = signal([]);
|
|
1994
|
+
this.sizeOptions = signal([]);
|
|
1995
|
+
this.query = input(null);
|
|
1996
|
+
this.queryChange = output();
|
|
1997
|
+
this.filtersActive = signal(false);
|
|
1998
|
+
this.filterForm = this.#fb.nonNullable.group({
|
|
1999
|
+
type: [this.ANY_OPTION],
|
|
2000
|
+
size: [this.ANY_OPTION],
|
|
2001
|
+
created: [this.ANY_OPTION]
|
|
2002
|
+
});
|
|
2003
|
+
this.translate.onLangChange.pipe(takeUntilDestroyed()).subscribe((_) => this.#setupOptions());
|
|
2004
|
+
this.#setupOptions();
|
|
2005
|
+
this.filterForm.valueChanges.pipe(takeUntilDestroyed()).subscribe((v) => this.#onFormValueChange(v));
|
|
2006
|
+
// listen to created filter changes to catch custom date range
|
|
2007
|
+
this.filterForm
|
|
2008
|
+
.get('created')
|
|
2009
|
+
?.valueChanges.pipe(takeUntilDestroyed())
|
|
2010
|
+
.subscribe((v) => {
|
|
2011
|
+
if (v === this.#CREATED_CUSTOM) {
|
|
2012
|
+
// open date range picker
|
|
2013
|
+
console.log(this.#customDateRange);
|
|
2014
|
+
const o = this.#overlay.open(DateRangePickerComponent, {
|
|
2015
|
+
range: this.#customDateRange
|
|
2016
|
+
});
|
|
2017
|
+
o.afterClosed$.subscribe((res) => {
|
|
2018
|
+
this.#customDateRange = res.data;
|
|
2019
|
+
if (!res.data) {
|
|
2020
|
+
this.filterForm.get('created')?.patchValue(this.ANY_OPTION);
|
|
2021
|
+
this.#setupDateOptions();
|
|
2022
|
+
}
|
|
2023
|
+
else {
|
|
2024
|
+
this.#onFormValueChange(this.filterForm.value);
|
|
2025
|
+
this.#setupDateOptions(this.#customDateRangeToString());
|
|
2026
|
+
setTimeout(() => {
|
|
2027
|
+
this.filterForm.patchValue({
|
|
2028
|
+
created: this.#CREATED_CUSTOM
|
|
2029
|
+
}, {
|
|
2030
|
+
emitEvent: false
|
|
2031
|
+
});
|
|
2032
|
+
});
|
|
2033
|
+
}
|
|
2034
|
+
});
|
|
2035
|
+
}
|
|
2036
|
+
});
|
|
2037
|
+
}
|
|
2038
|
+
#customDateRangeToString() {
|
|
2039
|
+
if (!this.#customDateRange)
|
|
2040
|
+
return undefined;
|
|
2041
|
+
const dp = new LocaleDatePipe(this.translate);
|
|
2042
|
+
switch (this.#customDateRange.operator) {
|
|
2043
|
+
case Operator.EQUAL: {
|
|
2044
|
+
return dp.transform(this.#customDateRange.firstValue, 'shortDate');
|
|
2045
|
+
}
|
|
2046
|
+
case Operator.GREATER_OR_EQUAL: {
|
|
2047
|
+
return `${OperatorLabel.GREATER_OR_EQUAL} ${dp.transform(this.#customDateRange.firstValue, 'shortDate')}`;
|
|
2048
|
+
}
|
|
2049
|
+
case Operator.LESS_OR_EQUAL: {
|
|
2050
|
+
return `${OperatorLabel.LESS_OR_EQUAL} ${dp.transform(this.#customDateRange.firstValue, 'shortDate')}`;
|
|
2051
|
+
}
|
|
2052
|
+
case Operator.INTERVAL_INCLUDE_BOTH: {
|
|
2053
|
+
return `${dp.transform(this.#customDateRange.firstValue, 'shortDate')} ${OperatorLabel.INTERVAL_INCLUDE_BOTH} ${dp.transform(this.#customDateRange.secondValue, 'shortDate')}`;
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
return undefined;
|
|
2057
|
+
}
|
|
2058
|
+
reset() {
|
|
2059
|
+
const q = this.query();
|
|
2060
|
+
if (q) {
|
|
2061
|
+
this.queryChange.emit(q);
|
|
2062
|
+
this.filterForm.reset();
|
|
2063
|
+
}
|
|
2064
|
+
}
|
|
2065
|
+
#onFormValueChange(v) {
|
|
2066
|
+
// do not create a new query if custom date range is selected but not set
|
|
2067
|
+
if (v.created === this.#CREATED_CUSTOM && !this.#customDateRange)
|
|
2068
|
+
return;
|
|
2069
|
+
if (v.created !== this.#CREATED_CUSTOM) {
|
|
2070
|
+
this.#customDateRange = undefined;
|
|
2071
|
+
this.#setupDateOptions();
|
|
2072
|
+
}
|
|
2073
|
+
const updatedQuery = this.#applyFilters(v);
|
|
2074
|
+
this.queryChange.emit(updatedQuery);
|
|
2075
|
+
this.filtersActive.set(!!updatedQuery.filters && updatedQuery.filters.length > 0);
|
|
2076
|
+
}
|
|
2077
|
+
#applyFilters(v) {
|
|
2078
|
+
const updatedQuery = {
|
|
2079
|
+
...(this.query() || {}),
|
|
2080
|
+
filters: []
|
|
2081
|
+
};
|
|
2082
|
+
updatedQuery.filters = [];
|
|
2083
|
+
// file size filter
|
|
2084
|
+
const typeFilter = this.#toTypeFilter(v.type);
|
|
2085
|
+
if (typeFilter)
|
|
2086
|
+
updatedQuery.filters.push(typeFilter);
|
|
2087
|
+
// file size filter
|
|
2088
|
+
const sizeFilter = this.#toSizeFilter(v.size);
|
|
2089
|
+
if (sizeFilter)
|
|
2090
|
+
updatedQuery.filters.push(sizeFilter);
|
|
2091
|
+
// creation date filter
|
|
2092
|
+
const dateFilter = this.#toDateFilter(v.created);
|
|
2093
|
+
if (dateFilter)
|
|
2094
|
+
updatedQuery.filters.push(dateFilter);
|
|
2095
|
+
return updatedQuery;
|
|
2096
|
+
}
|
|
2097
|
+
#setupOptions() {
|
|
2098
|
+
this.#setupTypeOptions();
|
|
2099
|
+
this.#setupDateOptions();
|
|
2100
|
+
this.#setupSizeOptions();
|
|
2101
|
+
}
|
|
2102
|
+
#setupTypeOptions() {
|
|
2103
|
+
this.typeOptions.set([
|
|
2104
|
+
{
|
|
2105
|
+
label: this.translate.instant('yuv.app.drive.search.filter.option.any'),
|
|
2106
|
+
value: this.ANY_OPTION
|
|
2107
|
+
},
|
|
2108
|
+
...this.#flavors.map((f) => ({
|
|
2109
|
+
label: this.translate.instant(f.id),
|
|
2110
|
+
value: f.sot
|
|
2111
|
+
}))
|
|
2112
|
+
]);
|
|
2113
|
+
}
|
|
2114
|
+
#setupDateOptions(custom) {
|
|
2115
|
+
this.dateOptions.set([
|
|
2116
|
+
...[
|
|
2117
|
+
{
|
|
2118
|
+
label: this.translate.instant('yuv.app.drive.search.filter.option.date.any'),
|
|
2119
|
+
value: this.ANY_OPTION
|
|
2120
|
+
},
|
|
2121
|
+
{
|
|
2122
|
+
label: this.translate.instant('yuv.app.drive.search.filter.option.date.today'),
|
|
2123
|
+
value: 'today'
|
|
2124
|
+
},
|
|
2125
|
+
{
|
|
2126
|
+
label: this.translate.instant('yuv.app.drive.search.filter.option.date.yesterday'),
|
|
2127
|
+
value: 'yesterday'
|
|
2128
|
+
},
|
|
2129
|
+
{
|
|
2130
|
+
label: this.translate.instant('yuv.app.drive.search.filter.option.date.thisweek'),
|
|
2131
|
+
value: 'thisweek'
|
|
2132
|
+
},
|
|
2133
|
+
// {
|
|
2134
|
+
// label: this.translate.instant('yuv.app.drive.search.filter.option.date.lastweek'),
|
|
2135
|
+
// value: 'lastweek'
|
|
2136
|
+
// },
|
|
2137
|
+
{
|
|
2138
|
+
label: this.translate.instant('yuv.app.drive.search.filter.option.date.thismonth'),
|
|
2139
|
+
value: 'thismonth'
|
|
2140
|
+
},
|
|
2141
|
+
// {
|
|
2142
|
+
// label: this.translate.instant('yuv.app.drive.search.filter.option.date.lastmonth'),
|
|
2143
|
+
// value: 'lastmonth'
|
|
2144
|
+
// },
|
|
2145
|
+
{
|
|
2146
|
+
label: this.translate.instant('yuv.app.drive.search.filter.option.date.thisyear'),
|
|
2147
|
+
value: 'thisyear'
|
|
2148
|
+
},
|
|
2149
|
+
// {
|
|
2150
|
+
// label: this.translate.instant('yuv.app.drive.search.filter.option.date.lastyear'),
|
|
2151
|
+
// value: 'lastyear'
|
|
2152
|
+
// },
|
|
2153
|
+
{
|
|
2154
|
+
label: custom || this.translate.instant('yuv.app.drive.search.filter.option.date.custom'),
|
|
2155
|
+
value: this.#CREATED_CUSTOM
|
|
2156
|
+
}
|
|
2157
|
+
]
|
|
2158
|
+
]);
|
|
2159
|
+
}
|
|
2160
|
+
#setupSizeOptions() {
|
|
2161
|
+
this.sizeOptions.set([
|
|
2162
|
+
{
|
|
2163
|
+
label: this.translate.instant('yuv.app.drive.search.filter.option.size.any'),
|
|
2164
|
+
value: this.ANY_OPTION
|
|
2165
|
+
},
|
|
2166
|
+
{
|
|
2167
|
+
label: this.translate.instant('yuv.app.drive.search.filter.option.size.small'),
|
|
2168
|
+
value: 's'
|
|
2169
|
+
},
|
|
2170
|
+
{
|
|
2171
|
+
label: this.translate.instant('yuv.app.drive.search.filter.option.size.medium'),
|
|
2172
|
+
value: 'm'
|
|
2173
|
+
},
|
|
2174
|
+
{
|
|
2175
|
+
label: this.translate.instant('yuv.app.drive.search.filter.option.size.large'),
|
|
2176
|
+
value: 'l'
|
|
2177
|
+
},
|
|
2178
|
+
{
|
|
2179
|
+
label: this.translate.instant('yuv.app.drive.search.filter.option.size.verylarge'),
|
|
2180
|
+
value: 'xl'
|
|
2181
|
+
}
|
|
2182
|
+
]);
|
|
2183
|
+
}
|
|
2184
|
+
#toDateFilter(value) {
|
|
2185
|
+
let dateFilter = undefined;
|
|
2186
|
+
switch (value) {
|
|
2187
|
+
case 'today': {
|
|
2188
|
+
dateFilter = {
|
|
2189
|
+
f: BaseObjectTypeField.CREATION_DATE,
|
|
2190
|
+
o: Operator.INTERVAL_INCLUDE_BOTH,
|
|
2191
|
+
v1: new Date().toISOString().split('T')[0] + 'T00:00:00.000',
|
|
2192
|
+
v2: new Date().toISOString().split('T')[0] + 'T23:59:59.000'
|
|
2193
|
+
};
|
|
2194
|
+
break;
|
|
2195
|
+
}
|
|
2196
|
+
case 'yesterday': {
|
|
2197
|
+
const yesterday = new Date();
|
|
2198
|
+
yesterday.setDate(yesterday.getDate() - 1);
|
|
2199
|
+
dateFilter = {
|
|
2200
|
+
f: BaseObjectTypeField.CREATION_DATE,
|
|
2201
|
+
o: Operator.INTERVAL_INCLUDE_BOTH,
|
|
2202
|
+
v1: yesterday.toISOString().split('T')[0] + 'T00:00:00.000',
|
|
2203
|
+
v2: yesterday.toISOString().split('T')[0] + 'T23:59:59.000'
|
|
2204
|
+
};
|
|
2205
|
+
break;
|
|
2206
|
+
}
|
|
2207
|
+
case 'thisweek': {
|
|
2208
|
+
const firstDay = new Date();
|
|
2209
|
+
firstDay.setDate(firstDay.getDate() - firstDay.getDay());
|
|
2210
|
+
dateFilter = {
|
|
2211
|
+
f: BaseObjectTypeField.CREATION_DATE,
|
|
2212
|
+
o: Operator.INTERVAL_INCLUDE_BOTH,
|
|
2213
|
+
v1: firstDay.toISOString().split('T')[0] + 'T00:00:00.000',
|
|
2214
|
+
v2: new Date().toISOString().split('T')[0] + 'T23:59:59.000'
|
|
2215
|
+
};
|
|
2216
|
+
break;
|
|
2217
|
+
}
|
|
2218
|
+
// case 'lastweek': {
|
|
2219
|
+
// const firstDay = new Date();
|
|
2220
|
+
// firstDay.setDate(firstDay.getDate() - firstDay.getDay() - 7);
|
|
2221
|
+
// const lastDay = new Date();
|
|
2222
|
+
// lastDay.setDate(lastDay.getDate() - lastDay.getDay() - 1);
|
|
2223
|
+
// dateFilter = {
|
|
2224
|
+
// f: BaseObjectTypeField.CREATION_DATE,
|
|
2225
|
+
// o: Operator.INTERVAL_INCLUDE_BOTH,
|
|
2226
|
+
// v1: firstDay.toISOString().split('T')[0] + 'T00:00:00.000',
|
|
2227
|
+
// v2: lastDay.toISOString().split('T')[0] + 'T23:59:59.000'
|
|
2228
|
+
// };
|
|
2229
|
+
// break;
|
|
2230
|
+
// }
|
|
2231
|
+
case 'thismonth': {
|
|
2232
|
+
const firstDay = new Date();
|
|
2233
|
+
firstDay.setDate(1);
|
|
2234
|
+
dateFilter = {
|
|
2235
|
+
f: BaseObjectTypeField.CREATION_DATE,
|
|
2236
|
+
o: Operator.INTERVAL_INCLUDE_BOTH,
|
|
2237
|
+
v1: firstDay.toISOString().split('T')[0] + 'T00:00:00.000',
|
|
2238
|
+
v2: new Date().toISOString().split('T')[0] + 'T23:59:59.000'
|
|
2239
|
+
};
|
|
2240
|
+
break;
|
|
2241
|
+
}
|
|
2242
|
+
// case 'lastmonth': {
|
|
2243
|
+
// const firstDay = new Date();
|
|
2244
|
+
// firstDay.setDate(1);
|
|
2245
|
+
// firstDay.setMonth(firstDay.getMonth() - 1);
|
|
2246
|
+
// const lastDay = new Date();
|
|
2247
|
+
// lastDay.setDate(0);
|
|
2248
|
+
// dateFilter = {
|
|
2249
|
+
// f: BaseObjectTypeField.CREATION_DATE,
|
|
2250
|
+
// o: Operator.INTERVAL_INCLUDE_BOTH,
|
|
2251
|
+
// v1: firstDay.toISOString().split('T')[0] + 'T00:00:00.000',
|
|
2252
|
+
// v2: lastDay.toISOString().split('T')[0] + 'T23:59:59.000'
|
|
2253
|
+
// };
|
|
2254
|
+
// break;
|
|
2255
|
+
// }
|
|
2256
|
+
case 'thisyear': {
|
|
2257
|
+
const firstDay = new Date();
|
|
2258
|
+
firstDay.setMonth(0);
|
|
2259
|
+
firstDay.setDate(1);
|
|
2260
|
+
dateFilter = {
|
|
2261
|
+
f: BaseObjectTypeField.CREATION_DATE,
|
|
2262
|
+
o: Operator.INTERVAL_INCLUDE_BOTH,
|
|
2263
|
+
v1: firstDay.toISOString().split('T')[0] + 'T00:00:00.000',
|
|
2264
|
+
v2: new Date().toISOString().split('T')[0] + 'T23:59:59.000'
|
|
2265
|
+
};
|
|
2266
|
+
break;
|
|
2267
|
+
}
|
|
2268
|
+
// case 'lastyear': {
|
|
2269
|
+
// const firstDay = new Date();
|
|
2270
|
+
// firstDay.setFullYear(firstDay.getFullYear() - 1);
|
|
2271
|
+
// firstDay.setMonth(0);
|
|
2272
|
+
// firstDay.setDate(1);
|
|
2273
|
+
// const lastDay = new Date();
|
|
2274
|
+
// lastDay.setFullYear(lastDay.getFullYear() - 1);
|
|
2275
|
+
// lastDay.setMonth(11);
|
|
2276
|
+
// lastDay.setDate(31);
|
|
2277
|
+
// dateFilter = {
|
|
2278
|
+
// f: BaseObjectTypeField.CREATION_DATE,
|
|
2279
|
+
// o: Operator.INTERVAL_INCLUDE_BOTH,
|
|
2280
|
+
// v1: firstDay.toISOString().split('T')[0] + 'T00:00:00.000',
|
|
2281
|
+
// v2: lastDay.toISOString().split('T')[0] + 'T23:59:59.000'
|
|
2282
|
+
// };
|
|
2283
|
+
// break;
|
|
2284
|
+
// }
|
|
2285
|
+
case this.#CREATED_CUSTOM: {
|
|
2286
|
+
if (this.#customDateRange)
|
|
2287
|
+
dateFilter = this.#customRangeToFilter(this.#customDateRange);
|
|
2288
|
+
else
|
|
2289
|
+
this.filterForm.get('created')?.patchValue(this.ANY_OPTION);
|
|
2290
|
+
break;
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
return dateFilter;
|
|
2294
|
+
}
|
|
2295
|
+
#customRangeToFilter(rv) {
|
|
2296
|
+
const v1 = rv.firstValue.toISOString();
|
|
2297
|
+
const v2 = rv.secondValue ? rv.secondValue.toISOString() : undefined;
|
|
2298
|
+
let filter;
|
|
2299
|
+
switch (rv.operator) {
|
|
2300
|
+
case Operator.EQUAL: {
|
|
2301
|
+
filter = {
|
|
2302
|
+
f: BaseObjectTypeField.CREATION_DATE,
|
|
2303
|
+
o: Operator.INTERVAL_INCLUDE_BOTH,
|
|
2304
|
+
v1: v1.split('T')[0] + 'T00:00:00.000',
|
|
2305
|
+
v2: v1.split('T')[0] + 'T23:59:59.000'
|
|
2306
|
+
};
|
|
2307
|
+
break;
|
|
2308
|
+
}
|
|
2309
|
+
case Operator.GREATER_OR_EQUAL: {
|
|
2310
|
+
filter = {
|
|
2311
|
+
f: BaseObjectTypeField.CREATION_DATE,
|
|
2312
|
+
o: rv.operator,
|
|
2313
|
+
v1: v1.split('T')[0] + 'T00:00:00.000'
|
|
2314
|
+
};
|
|
2315
|
+
break;
|
|
2316
|
+
}
|
|
2317
|
+
case Operator.LESS_OR_EQUAL: {
|
|
2318
|
+
filter = {
|
|
2319
|
+
f: BaseObjectTypeField.CREATION_DATE,
|
|
2320
|
+
o: rv.operator,
|
|
2321
|
+
v1: v1.split('T')[0] + 'T23:59:59.000'
|
|
2322
|
+
};
|
|
2323
|
+
break;
|
|
2324
|
+
}
|
|
2325
|
+
case Operator.INTERVAL_INCLUDE_BOTH: {
|
|
2326
|
+
filter = {
|
|
2327
|
+
f: BaseObjectTypeField.CREATION_DATE,
|
|
2328
|
+
o: rv.operator,
|
|
2329
|
+
v1: v1.split('T')[0] + 'T00:00:00.000',
|
|
2330
|
+
v2: v2.split('T')[0] + 'T23:59:59.000'
|
|
2331
|
+
};
|
|
2332
|
+
break;
|
|
2333
|
+
}
|
|
2334
|
+
}
|
|
2335
|
+
return filter;
|
|
2336
|
+
}
|
|
2337
|
+
#toSizeFilter(value) {
|
|
2338
|
+
let sizeFilter = undefined;
|
|
2339
|
+
switch (value) {
|
|
2340
|
+
case 's':
|
|
2341
|
+
sizeFilter = {
|
|
2342
|
+
f: ContentStreamField.LENGTH,
|
|
2343
|
+
o: Operator.LESS_THAN,
|
|
2344
|
+
v1: 1024 * 1024
|
|
2345
|
+
};
|
|
2346
|
+
break;
|
|
2347
|
+
case 'm':
|
|
2348
|
+
sizeFilter = {
|
|
2349
|
+
f: ContentStreamField.LENGTH,
|
|
2350
|
+
o: Operator.INTERVAL_INCLUDE_BOTH,
|
|
2351
|
+
v1: 1024 * 1024,
|
|
2352
|
+
v2: 1024 * 1024 * 10
|
|
2353
|
+
};
|
|
2354
|
+
break;
|
|
2355
|
+
case 'l':
|
|
2356
|
+
sizeFilter = {
|
|
2357
|
+
f: ContentStreamField.LENGTH,
|
|
2358
|
+
o: Operator.INTERVAL_INCLUDE_BOTH,
|
|
2359
|
+
v1: 1024 * 1024 * 10,
|
|
2360
|
+
v2: 1024 * 1024 * 100
|
|
2361
|
+
};
|
|
2362
|
+
break;
|
|
2363
|
+
case 'xl':
|
|
2364
|
+
sizeFilter = {
|
|
2365
|
+
f: ContentStreamField.LENGTH,
|
|
2366
|
+
o: Operator.GREATER_THAN,
|
|
2367
|
+
v1: 1024 * 1024 * 100
|
|
2368
|
+
};
|
|
2369
|
+
break;
|
|
2370
|
+
}
|
|
2371
|
+
return sizeFilter;
|
|
2372
|
+
}
|
|
2373
|
+
#toTypeFilter(value) {
|
|
2374
|
+
return value === this.ANY_OPTION
|
|
2375
|
+
? undefined
|
|
2376
|
+
: {
|
|
2377
|
+
f: BaseObjectTypeField.SECONDARY_OBJECT_TYPE_IDS,
|
|
2378
|
+
o: Operator.IN,
|
|
2379
|
+
v1: [value]
|
|
2380
|
+
};
|
|
2381
|
+
}
|
|
2382
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SearchFilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2383
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: SearchFilterComponent, isStandalone: true, selector: "ymd-search-filter", inputs: { query: { classPropertyName: "query", publicName: "query", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { queryChange: "queryChange" }, ngImport: i0, template: "<form [formGroup]=\"filterForm\" yvcDragScroll>\n <yvc-dropdown formControlName=\"type\" [options]=\"typeOptions()\" [disableClearButton]=\"true\"></yvc-dropdown>\n <yvc-dropdown formControlName=\"size\" [options]=\"sizeOptions()\" [disableClearButton]=\"true\"></yvc-dropdown>\n <yvc-dropdown formControlName=\"created\" [options]=\"dateOptions()\" [disableClearButton]=\"true\"></yvc-dropdown>\n\n @if (filtersActive()) {\n <button class=\"secondary\" (click)=\"reset()\">{{ 'yuv.app.drive.search.filter.button.reset' | translate }}</button>\n }\n</form>\n", styles: [":host form{display:flex;gap:2px;overflow-x:auto;--scrollbar-outer-size: 0;margin-block:calc(var(--app-pane-padding) / 2)}:host form yvc-dropdown{--icon-size: 18px;font-size:var(--font-caption);color:var(--text-color-caption);border:0;outline-offset:-2px;cursor:pointer;flex:0 0 auto;padding:0}:host form button{padding:.15em .5em;line-height:1em;margin-inline-start:1em;border-radius:.25em;font-size:var(--font-caption)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: YvcDropdownModule }, { kind: "component", type: i1$4.Dropdown, selector: "yvc-dropdown", inputs: ["options", "filter", "disabled", "multiple", "disableClearButton"], outputs: ["onDropdownOptionsClose"] }, { kind: "ngmodule", type: TranslateModule$1 }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: YvcDragScrollModule }, { kind: "directive", type: i2$1.DragScrollDirective, selector: "[yvcDragScroll]" }] }); }
|
|
2384
|
+
}
|
|
2385
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SearchFilterComponent, decorators: [{
|
|
2386
|
+
type: Component,
|
|
2387
|
+
args: [{ selector: 'ymd-search-filter', standalone: true, imports: [CommonModule, YvcDropdownModule, TranslateModule$1, ReactiveFormsModule, YvcDragScrollModule], template: "<form [formGroup]=\"filterForm\" yvcDragScroll>\n <yvc-dropdown formControlName=\"type\" [options]=\"typeOptions()\" [disableClearButton]=\"true\"></yvc-dropdown>\n <yvc-dropdown formControlName=\"size\" [options]=\"sizeOptions()\" [disableClearButton]=\"true\"></yvc-dropdown>\n <yvc-dropdown formControlName=\"created\" [options]=\"dateOptions()\" [disableClearButton]=\"true\"></yvc-dropdown>\n\n @if (filtersActive()) {\n <button class=\"secondary\" (click)=\"reset()\">{{ 'yuv.app.drive.search.filter.button.reset' | translate }}</button>\n }\n</form>\n", styles: [":host form{display:flex;gap:2px;overflow-x:auto;--scrollbar-outer-size: 0;margin-block:calc(var(--app-pane-padding) / 2)}:host form yvc-dropdown{--icon-size: 18px;font-size:var(--font-caption);color:var(--text-color-caption);border:0;outline-offset:-2px;cursor:pointer;flex:0 0 auto;padding:0}:host form button{padding:.15em .5em;line-height:1em;margin-inline-start:1em;border-radius:.25em;font-size:var(--font-caption)}\n"] }]
|
|
2388
|
+
}], ctorParameters: () => [] });
|
|
2389
|
+
|
|
2390
|
+
const components = [
|
|
2391
|
+
TileListComponent,
|
|
2392
|
+
BreadcrumbComponent,
|
|
2393
|
+
FolderTreeComponent,
|
|
2394
|
+
ObjectSummaryComponent,
|
|
2395
|
+
TileConfigTriggerComponent,
|
|
2396
|
+
RibbonComponent,
|
|
2397
|
+
AddButtonComponent,
|
|
2398
|
+
SimpleSearchComponent,
|
|
2399
|
+
MultiObjectSummaryComponent,
|
|
2400
|
+
SortComponent,
|
|
2401
|
+
SearchFilterComponent
|
|
2402
|
+
];
|
|
2403
|
+
const module = [YvcIconModule, TranslateModule, RouterModule, YvcSplitViewModule];
|
|
2404
|
+
class FilesPageComponent {
|
|
2405
|
+
#LAYOUT_SETTINGS_STORAGE_KEY;
|
|
2406
|
+
#objectConfigService;
|
|
2407
|
+
#device;
|
|
2408
|
+
#eventService;
|
|
2409
|
+
#appCache;
|
|
2410
|
+
#highlightStyles;
|
|
2411
|
+
#routeIdEffect;
|
|
2412
|
+
constructor() {
|
|
2413
|
+
this.tileList = viewChild('tileList');
|
|
2414
|
+
this.#LAYOUT_SETTINGS_STORAGE_KEY = 'yuv.app.drive.files.layout';
|
|
2415
|
+
this.shellService = inject(ShellService);
|
|
2416
|
+
this.dmsService = inject(DmsService);
|
|
2417
|
+
this.drive = inject(DriveService);
|
|
2418
|
+
this.route = inject(ActivatedRoute);
|
|
2419
|
+
this.router = inject(Router);
|
|
2420
|
+
this.translate = inject(TranslateService);
|
|
2421
|
+
this.storedQueryService = inject(StoredQueryService);
|
|
2422
|
+
this.clipboard = inject(ClipboardService);
|
|
2423
|
+
this.actionsService = inject(ActionsService);
|
|
2424
|
+
this.#objectConfigService = inject(ObjectConfigService);
|
|
2425
|
+
this.#device = inject(DeviceService);
|
|
2426
|
+
this.#eventService = inject(EventService);
|
|
2427
|
+
this.ERROR_CODE = {
|
|
2428
|
+
NOT_FOUND: '404',
|
|
2429
|
+
// pattern: {HTTP_STATUS_CODE}-{SERVICE_ERROR_CODE}
|
|
2430
|
+
INVALID_ID: '422-2912'
|
|
2431
|
+
};
|
|
2432
|
+
this.#appCache = inject(AppCacheService);
|
|
2433
|
+
this.objectConfigBucket = APP_SCHEMA.id;
|
|
2434
|
+
this.splitViewCmp = viewChild.required(SplitViewComponent);
|
|
2435
|
+
this.selected = signal(undefined);
|
|
2436
|
+
this.fileDropSummaryDisabled = computed(() => !this.selected()?.permissions?.writeContent);
|
|
2437
|
+
this.disableCreate = false;
|
|
2438
|
+
this.actions = this.drive.state$.actions;
|
|
2439
|
+
this.selection = this.drive.state$.selection;
|
|
2440
|
+
this.busy = this.drive.state$.busy;
|
|
2441
|
+
this.flavorChips = this.shellService.getObjectFlavors();
|
|
2442
|
+
this.selectionActions = computed(() => ({ selection: this.selection(), actions: this.actions() }));
|
|
2443
|
+
this.emptyMode = signal(null);
|
|
2444
|
+
// error code when loading the object failed. This will be used
|
|
2445
|
+
// to determine a proper error message to display
|
|
2446
|
+
this.error = signal(undefined);
|
|
2447
|
+
this.configTypeOptions = {
|
|
2448
|
+
folder: { bucket: APP_ID, type: APP_SCHEMA.types['folder'] },
|
|
2449
|
+
file: { bucket: APP_ID, type: APP_SCHEMA.types['file'] }
|
|
2450
|
+
};
|
|
2451
|
+
this.searchFocused = false;
|
|
2452
|
+
this.enableDetails = signal(true);
|
|
2453
|
+
this.enableTree = signal(true);
|
|
2454
|
+
this.tileConfigBucketLabel = this.translate.instant('yuv.app.drive.tile-config.bucket');
|
|
2455
|
+
this.smallScreenLayout = signal(false);
|
|
2456
|
+
this.sortOptionsAvailable = signal(true);
|
|
2457
|
+
this.id = input(null);
|
|
2458
|
+
this.highlightStyles$ = this.clipboard.clipboard$(APP_ID).pipe(takeUntilDestroyed(), map((c) => {
|
|
2459
|
+
return c && c.mode && c.objects?.length
|
|
2460
|
+
? [
|
|
2461
|
+
{
|
|
2462
|
+
cssStyles: this.#highlightStyles[c?.mode],
|
|
2463
|
+
ids: c.objects.map((o) => o.id)
|
|
2464
|
+
}
|
|
2465
|
+
]
|
|
2466
|
+
: [];
|
|
2467
|
+
}));
|
|
2468
|
+
this.#highlightStyles = {
|
|
2469
|
+
cut: { opacity: 0.5 }
|
|
2470
|
+
};
|
|
2471
|
+
this.#routeIdEffect = effect(() => {
|
|
2472
|
+
const param = this.id() || undefined;
|
|
2473
|
+
untracked(async () => {
|
|
2474
|
+
if (param === DRIVE_QUERY_FOLDER_ID) {
|
|
2475
|
+
this.emptyMode.set(DRIVE_QUERY_FOLDER_ID);
|
|
2476
|
+
return;
|
|
2477
|
+
}
|
|
2478
|
+
this.emptyMode.set(param === DRIVE_ROOT_FOLDER_ID ? DRIVE_ROOT_FOLDER_ID : null);
|
|
2479
|
+
this.error.set(undefined);
|
|
2480
|
+
this.disableCreate = false;
|
|
2481
|
+
this.currentFolderID = param;
|
|
2482
|
+
this.drive.updateCurrentFolder(this.currentFolderID);
|
|
2483
|
+
this.selected.set(undefined);
|
|
2484
|
+
this.currentFolder = undefined;
|
|
2485
|
+
if (this.currentFolderID === DRIVE_ROOT_FOLDER_ID)
|
|
2486
|
+
this.currentFolderID = undefined;
|
|
2487
|
+
if (this.currentFolderID) {
|
|
2488
|
+
this.dmsService.getDmsObject(this.currentFolderID).subscribe({
|
|
2489
|
+
next: (o) => {
|
|
2490
|
+
this.currentFolder = o;
|
|
2491
|
+
this._setFolderQuery(this.#getTitle(o));
|
|
2492
|
+
},
|
|
2493
|
+
error: (e) => {
|
|
2494
|
+
console.error('Error getting folder', e);
|
|
2495
|
+
this.#processLoadError(e);
|
|
2496
|
+
}
|
|
2497
|
+
});
|
|
2498
|
+
}
|
|
2499
|
+
else
|
|
2500
|
+
this._setFolderQuery(this.translate.instant('yuv.app.drive.folder-tree.mydrive'));
|
|
2501
|
+
});
|
|
2502
|
+
});
|
|
2503
|
+
this.tileListOptions = {
|
|
2504
|
+
actionContext: ACTION_CONTEXT,
|
|
2505
|
+
configTypes: Object.values(APP_SCHEMA.types),
|
|
2506
|
+
configFlavors: [...this.shellService.getObjectFlavors(), ...APP_SCHEMA.flavors.filter((f) => !f.applicableTo).map((f) => ({ ...f, app: APP_ID }))]
|
|
2507
|
+
};
|
|
2508
|
+
this.query = this.drive.state$.query;
|
|
2509
|
+
this.queryTitle = this.drive.state$.queryTitle;
|
|
2510
|
+
this.icons = {
|
|
2511
|
+
...APP_DRIVE_ICONS,
|
|
2512
|
+
sort: APP_DRIVE_ICONS.sort,
|
|
2513
|
+
back: YUV_ICONS.back,
|
|
2514
|
+
attention: YUV_ICONS.attention,
|
|
2515
|
+
refresh: YUV_ICONS.refresh,
|
|
2516
|
+
clear: ICONS.clear
|
|
2517
|
+
};
|
|
2518
|
+
this.drive.events$.pipe(takeUntilDestroyed()).subscribe({
|
|
2519
|
+
next: (e) => {
|
|
2520
|
+
if (e === DRIVE_EVENT.refresh) {
|
|
2521
|
+
this.refresh();
|
|
2522
|
+
}
|
|
2523
|
+
}
|
|
2524
|
+
});
|
|
2525
|
+
this.#device.screenChange$.pipe(takeUntilDestroyed()).subscribe({
|
|
2526
|
+
next: (s) => {
|
|
2527
|
+
this.smallScreenLayout.set(s.size === 's' && s.orientation === 'portrait');
|
|
2528
|
+
this.enableDetails.set(!this.smallScreenLayout());
|
|
2529
|
+
}
|
|
2530
|
+
});
|
|
2531
|
+
toObservable(this.drive.state$.selection)
|
|
2532
|
+
.pipe(takeUntilDestroyed())
|
|
2533
|
+
.subscribe({
|
|
2534
|
+
next: (sel) => {
|
|
2535
|
+
if (sel?.length === 0) {
|
|
2536
|
+
this.tileList()?.clearSelection(true);
|
|
2537
|
+
this.selected.set(undefined);
|
|
2538
|
+
}
|
|
2539
|
+
}
|
|
2540
|
+
});
|
|
2541
|
+
this.route.queryParamMap.pipe(takeUntilDestroyed()).subscribe({
|
|
2542
|
+
next: (p) => {
|
|
2543
|
+
this.sortOptionsAvailable.set(true);
|
|
2544
|
+
if (this.route.snapshot.params['id'] === DRIVE_QUERY_FOLDER_ID) {
|
|
2545
|
+
const q = p.get('q');
|
|
2546
|
+
this.disableCreate = true;
|
|
2547
|
+
// check if the query is a stored query
|
|
2548
|
+
if (q?.startsWith(STORED_QUERY_ID_PREFIX)) {
|
|
2549
|
+
const sq = this.storedQueryService.getStoredQuery(q);
|
|
2550
|
+
if (sq) {
|
|
2551
|
+
this.drive.updateQuery(sq.query, sq.label);
|
|
2552
|
+
this.sortOptionsAvailable.set(false);
|
|
2553
|
+
return;
|
|
2554
|
+
}
|
|
2555
|
+
}
|
|
2556
|
+
else if (q) {
|
|
2557
|
+
this.sortOptionsAvailable.set(true);
|
|
2558
|
+
try {
|
|
2559
|
+
const sq = JSON.parse(decodeURIComponent(q));
|
|
2560
|
+
sq.filters = (sq.filters || []).filter((f) => f.f !== BaseObjectTypeField.PARENT_ID);
|
|
2561
|
+
this.drive.updateQuery(sq, this.translate.instant('yuv.app.drive.files.search.result.title'));
|
|
2562
|
+
return;
|
|
2563
|
+
}
|
|
2564
|
+
catch (e) {
|
|
2565
|
+
console.error('Error parsing query', e);
|
|
2566
|
+
}
|
|
2567
|
+
}
|
|
2568
|
+
}
|
|
2569
|
+
}
|
|
2570
|
+
});
|
|
2571
|
+
this.#eventService
|
|
2572
|
+
.on(YuvEventType.DMS_OBJECT_UPDATED)
|
|
2573
|
+
.pipe(takeUntilDestroyed(), tap((e) => {
|
|
2574
|
+
this.tileList()?.updateTileList([e.data]);
|
|
2575
|
+
e.data.id === this.selected()?.id && this.selected.set(e.data);
|
|
2576
|
+
}))
|
|
2577
|
+
.subscribe();
|
|
2578
|
+
}
|
|
2579
|
+
onFilterQueryChange(q) {
|
|
2580
|
+
this.drive.updateQuery(q, this.translate.instant('yuv.app.drive.files.search.result.title'));
|
|
2581
|
+
this.drive.setSelection([]);
|
|
2582
|
+
}
|
|
2583
|
+
#processLoadError(e) {
|
|
2584
|
+
if (`${e.status}` !== this.ERROR_CODE.NOT_FOUND) {
|
|
2585
|
+
this.error.set(`${e.status}-${e.error?.serviceErrorCode || ''}`);
|
|
2586
|
+
}
|
|
2587
|
+
else
|
|
2588
|
+
this.error.set(this.ERROR_CODE.NOT_FOUND);
|
|
2589
|
+
}
|
|
2590
|
+
#getTitle(o) {
|
|
2591
|
+
const cfgType = o.isFolder ? this.configTypeOptions['folder'] : this.configTypeOptions['file'];
|
|
2592
|
+
const oc = this.#objectConfigService.getResolvedObjectConfig(o.data, cfgType.type, cfgType.bucket, true);
|
|
2593
|
+
return oc.title.value;
|
|
2594
|
+
}
|
|
2595
|
+
onDelete() {
|
|
2596
|
+
const deleteAction = this.actions().find((a) => a.id === BASE_ACTION.delete);
|
|
2597
|
+
if (deleteAction)
|
|
2598
|
+
deleteAction.run(this.drive.state$.selection());
|
|
2599
|
+
}
|
|
2600
|
+
_setFolderQuery(queryTitle) {
|
|
2601
|
+
this.drive.updateQuery({
|
|
2602
|
+
filters: [{ f: BaseObjectTypeField.PARENT_ID, o: Operator.EQUAL, v1: this.currentFolderID || null }]
|
|
2603
|
+
}, queryTitle);
|
|
2604
|
+
}
|
|
2605
|
+
onContextmenu({ event }) {
|
|
2606
|
+
event.preventDefault();
|
|
2607
|
+
this.actionsService.openContextMenu(this.actions, (a) => a.run(this.selection()), { x: event.x, y: event.y });
|
|
2608
|
+
}
|
|
2609
|
+
onFileDrop(files) {
|
|
2610
|
+
this.drive.setBusy(true);
|
|
2611
|
+
this.drive.checkNamesAndUpload(files).subscribe({ complete: () => this.drive.setBusy(false) });
|
|
2612
|
+
}
|
|
2613
|
+
onFileUpdateDrop(file) {
|
|
2614
|
+
const dmsObject = this.selected();
|
|
2615
|
+
if (dmsObject) {
|
|
2616
|
+
this.drive.setBusy(true);
|
|
2617
|
+
this.drive
|
|
2618
|
+
.uploadContent(dmsObject.id, file[0])
|
|
2619
|
+
.pipe(finalize(() => this.drive.setBusy(false)))
|
|
2620
|
+
.subscribe();
|
|
2621
|
+
}
|
|
2622
|
+
}
|
|
2623
|
+
itemFocused(tile) {
|
|
2624
|
+
// console.log(tile);
|
|
2625
|
+
}
|
|
2626
|
+
itemClicked(tile) {
|
|
2627
|
+
if (this.smallScreenLayout())
|
|
2628
|
+
this.itemDoubleClicked(tile);
|
|
2629
|
+
}
|
|
2630
|
+
onCopy(tiles) {
|
|
2631
|
+
this.clipboard.addObjects(tiles.map((t) => t.dmsObject), 'copy', APP_ID);
|
|
2632
|
+
}
|
|
2633
|
+
onCut(tiles) {
|
|
2634
|
+
this.clipboard.addObjects(tiles.map((t) => t.dmsObject), 'cut', APP_ID);
|
|
2635
|
+
}
|
|
2636
|
+
onQuerySubmit(q) {
|
|
2637
|
+
// in order to keep the query in the url as short as
|
|
2638
|
+
// possible we'll get rid of the fields because they could be
|
|
2639
|
+
// re-applied later on
|
|
2640
|
+
q.fields = undefined;
|
|
2641
|
+
this.router.navigate(['..', 'query'], {
|
|
2642
|
+
queryParams: { q: encodeURIComponent(JSON.stringify(q)) },
|
|
2643
|
+
relativeTo: this.route
|
|
2644
|
+
});
|
|
2645
|
+
}
|
|
2646
|
+
selectionChanged(tiles) {
|
|
2647
|
+
if (tiles.length === 1)
|
|
2648
|
+
this.loadDetails(tiles[0].id);
|
|
2649
|
+
else {
|
|
2650
|
+
this.selected.set(undefined);
|
|
2651
|
+
if (tiles.length === 0) {
|
|
2652
|
+
this.drive.setSelection([]);
|
|
2653
|
+
}
|
|
2654
|
+
else {
|
|
2655
|
+
this.drive.setBusy(true);
|
|
2656
|
+
this.dmsService.getDmsObjects(tiles.map((i) => i.id)).subscribe({
|
|
2657
|
+
next: (o) => {
|
|
2658
|
+
this.drive.setBusy(false);
|
|
2659
|
+
this.drive.setSelection(o);
|
|
2660
|
+
}
|
|
2661
|
+
});
|
|
2662
|
+
}
|
|
2663
|
+
}
|
|
2664
|
+
}
|
|
2665
|
+
itemDoubleClicked(tile) {
|
|
2666
|
+
if (tile.instanceData) {
|
|
2667
|
+
this.drive.setBusy(true);
|
|
2668
|
+
const nav = tile.instanceData[BaseObjectTypeField.BASE_TYPE_ID] === SystemType.FOLDER ? ['..'] : ['../..', 'object'];
|
|
2669
|
+
this.router.navigate([...nav, tile.instanceData[BaseObjectTypeField.OBJECT_ID]], { relativeTo: this.route }).then(() => this.drive.setBusy(false));
|
|
2670
|
+
}
|
|
2671
|
+
}
|
|
2672
|
+
loadDetails(id) {
|
|
2673
|
+
this.shellService.addBusy();
|
|
2674
|
+
// load the dms object
|
|
2675
|
+
this.dmsService.getDmsObject(id).subscribe({
|
|
2676
|
+
next: (o) => {
|
|
2677
|
+
this.selected.set(o);
|
|
2678
|
+
this.shellService.removeBusy();
|
|
2679
|
+
this.drive.setSelection([o]);
|
|
2680
|
+
}
|
|
2681
|
+
});
|
|
2682
|
+
}
|
|
2683
|
+
clearSelection() {
|
|
2684
|
+
this.drive.setSelection([]);
|
|
2685
|
+
}
|
|
2686
|
+
openParent() {
|
|
2687
|
+
if (this.currentFolder) {
|
|
2688
|
+
this.drive.setBusy(true);
|
|
2689
|
+
this.router
|
|
2690
|
+
.navigate(['..', this.currentFolder.data[BaseObjectTypeField.PARENT_ID] || DRIVE_ROOT_FOLDER_ID], {
|
|
2691
|
+
relativeTo: this.route,
|
|
2692
|
+
replaceUrl: true
|
|
2693
|
+
})
|
|
2694
|
+
.then(() => this.drive.setBusy(false));
|
|
2695
|
+
}
|
|
2696
|
+
}
|
|
2697
|
+
setBusy(busy) {
|
|
2698
|
+
this.drive.setBusy(busy);
|
|
2699
|
+
}
|
|
2700
|
+
refresh() {
|
|
2701
|
+
this.tileList()?.refresh();
|
|
2702
|
+
this.drive.setSelection([]);
|
|
2703
|
+
}
|
|
2704
|
+
onLayoutSettingsChange(e) {
|
|
2705
|
+
this.#appCache.setItem(this.#LAYOUT_SETTINGS_STORAGE_KEY, e).subscribe();
|
|
2706
|
+
}
|
|
2707
|
+
#applyLayoutSettings(settings) {
|
|
2708
|
+
this.splitViewCmp().applyLayoutSettings(settings);
|
|
2709
|
+
}
|
|
2710
|
+
ngAfterViewInit() {
|
|
2711
|
+
this.#appCache.getItem(this.#LAYOUT_SETTINGS_STORAGE_KEY).subscribe({
|
|
2712
|
+
next: (ls) => {
|
|
2713
|
+
if (ls) {
|
|
2714
|
+
this.enableDetails.set(ls.areas[2]?.visible);
|
|
2715
|
+
this.enableTree.set(ls.areas[0]?.visible);
|
|
2716
|
+
this.#applyLayoutSettings(ls);
|
|
2717
|
+
}
|
|
2718
|
+
}
|
|
2719
|
+
});
|
|
2720
|
+
}
|
|
2721
|
+
ngOnDestroy() {
|
|
2722
|
+
this.clipboard.clear(APP_ID);
|
|
2723
|
+
}
|
|
2724
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FilesPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2725
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: FilesPageComponent, isStandalone: true, selector: "ymd-files", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.smallScreen": "smallScreenLayout()", "class.searchFocused": "this.searchFocused" } }, viewQueries: [{ propertyName: "tileList", first: true, predicate: ["tileList"], descendants: true, isSignal: true }, { propertyName: "splitViewCmp", first: true, predicate: SplitViewComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<header>\n <!-- navigation bar -->\n <nav [attr.aria-label]=\"'yuv.app.drive.files.naviagtion.aria.label' | translate\">\n <div class=\"nav\">\n <button class=\"back\" [disabled]=\"!currentFolder\" title=\"{{ 'yuv.app.drive.files.nav.back.tooltip' | translate }}\" (click)=\"openParent()\">\n <yvc-icon [svg]=\"icons.back\"></yvc-icon>\n </button>\n <button class=\"refresh\" title=\"{{ 'yuv.app.drive.files.nav.refresh.tooltip' | translate }}\" (click)=\"refresh()\">\n <yvc-icon [svg]=\"icons.refresh\"></yvc-icon>\n </button>\n </div>\n\n @if (!query()?.term) {\n <ymd-breadcrumb></ymd-breadcrumb>\n } @else {\n <div class=\"breadcrumb\"></div>\n }\n <div class=\"search\">\n <yuv-simple-search [query]=\"query()\" (querySubmit)=\"onQuerySubmit($event)\"></yuv-simple-search>\n <!-- TODO: enable again once drive search needs to be a little bit more sophisticated -->\n <!-- <ymd-drive-search (focused)=\"searchFocused = $event\"></ymd-drive-search> -->\n </div>\n </nav>\n\n <!-- ribbon with actions and options -->\n <ymd-ribbon [objects]=\"selection()\" [busy]=\"busy()\" [enableClipboard]=\"true\">\n <ng-template #primaryActions>\n <ymd-add-button [disabled]=\"disableCreate\"></ymd-add-button>\n </ng-template>\n\n <ng-template #secondaryActions>\n <div class=\"options\">\n @if (!smallScreenLayout()) {\n <button\n class=\"toggle-tree toggle\"\n [ngClass]=\"{ enabled: enableTree() }\"\n title=\"{{ 'yuv.app.drive.files.toggletree.tooltip' | translate }}\"\n (click)=\"enableTree.set(!enableTree())\"\n >\n <yvc-icon [svg]=\"icons.toggleLeft\"></yvc-icon>\n </button>\n <button\n class=\"toggle-details toggle\"\n [ngClass]=\"{ enabled: enableDetails() }\"\n title=\"{{ 'yuv.app.drive.files.toggledetails.tooltip' | translate }}\"\n (click)=\"enableDetails.set(!enableDetails())\"\n >\n <yvc-icon [svg]=\"icons.toggleRight\"></yvc-icon>\n </button>\n }\n <yuv-tile-config-trigger\n [icon]=\"icons.settings\"\n [bucket]=\"objectConfigBucket\"\n [bucketLabel]=\"tileConfigBucketLabel\"\n [options]=\"tileListOptions\"\n ></yuv-tile-config-trigger>\n </div>\n </ng-template>\n </ymd-ribbon>\n</header>\n\n<yvc-split-view [gutterSize]=\"1\" (layoutSettingsChange)=\"onLayoutSettingsChange($event)\">\n <!-- folder tree -->\n <ng-template yvcSplitArea [size]=\"20\" [visible]=\"enableTree() && !smallScreenLayout()\">\n <ymd-folder-tree yuvFocusable=\"Tree\"></ymd-folder-tree>\n </ng-template>\n\n <!-- files -->\n <ng-template yvcSplitArea [size]=\"60\">\n @let err = error();\n @if (err) {\n <div class=\"error\">\n <p>\n <yvc-icon [svg]=\"icons.attention\"></yvc-icon>\n @switch (err) {\n @case (ERROR_CODE.NOT_FOUND) {\n {{ 'yuv.app.drive.files.error.load.not-found' | translate }}\n }\n @case (ERROR_CODE.INVALID_ID) {\n {{ 'yuv.app.drive.files.error.load.invalid-id' | translate }}\n }\n @default {\n {{ 'yuv.app.drive.files.error.load' | translate }}\n }\n }\n </p>\n </div>\n } @else {\n <div class=\"files\" [yuvFileDropZone]=\"{ label: 'yuv.app.drive.files.dropzone.label' | translate }\" (fileDrop)=\"onFileDrop($event)\">\n <header class=\"files-header\">\n <h1>{{ queryTitle() }}</h1>\n @if (query()?.term) {\n <ymd-search-filter [query]=\"query()\" (queryChange)=\"onFilterQueryChange($event)\"></ymd-search-filter>\n }\n @if (sortOptionsAvailable()) {\n <ymd-sort />\n }\n <div class=\"flavors\">\n <!-- TODO: enable again once flavors/aspects are supported -->\n <!-- @for (f of flavorChips; track f.id) {\n <yuv-flavor-chip [ngClass]=\"{ active: f.id === appliedFlavor?.id }\" [flavor]=\"f\" (click)=\"appliedFlavor = f\"></yuv-flavor-chip>\n }-->\n </div>\n </header>\n\n <yuv-tile-list\n #tileList\n class=\"staggered\"\n [attr.aria-label]=\"'yuv.app.drive.files.content.aria.label' | translate\"\n [attr.aria-busy]=\"busy()\"\n [attr.role]=\"'listbox'\"\n (keydown.delete)=\"onDelete()\"\n [bucket]=\"objectConfigBucket\"\n [multiselect]=\"true\"\n [query]=\"query()\"\n [flavor]=\"appliedFlavor\"\n [options]=\"tileListOptions\"\n (itemDblClick)=\"itemDoubleClicked($event)\"\n (itemSelect)=\"itemClicked($event)\"\n (selectionChange)=\"selectionChanged($event)\"\n (copy)=\"onCopy($event)\"\n (cut)=\"onCut($event)\"\n (busy)=\"setBusy($event)\"\n (ctxMenu)=\"onContextmenu($event)\"\n [highlights]=\"highlightStyles$ | async\"\n >\n <div #empty>\n @if (emptyMode() === 'root') {\n <p class=\"empty\">{{ 'yuv.app.drive.files.content.empty.root.list' | translate }}</p>\n } @else if (emptyMode() === 'query') {\n <p class=\"empty\">{{ 'yuv.app.drive.files.content.empty.query.list' | translate }}</p>\n } @else {\n <p class=\"empty\">{{ 'yuv.app.drive.files.content.empty.list' | translate }}</p>\n }\n </div>\n </yuv-tile-list>\n </div>\n }\n </ng-template>\n\n <!-- details -->\n <ng-template yvcSplitArea [size]=\"20\" [visible]=\"enableDetails()\">\n @let selectedItem = selected();\n @if (enableDetails() && selectedItem) {\n @if (selectedItem?.isFolder) {\n <yuv-object-summary [configType]=\"configTypeOptions['folder']\" [dmsObject]=\"selectedItem\"></yuv-object-summary>\n } @else {\n <yuv-object-summary\n [configType]=\"configTypeOptions['file']\"\n [dmsObject]=\"selectedItem\"\n [yuvFileDropZone]=\"{ label: 'yuv.app.drive.files.dropzone.content.replace.label' | translate }\"\n [fileDropDisabled]=\"fileDropSummaryDisabled()\"\n (fileDrop)=\"onFileUpdateDrop($event)\"\n ></yuv-object-summary>\n }\n } @else {\n @let sel = selection();\n @if (sel && sel.length > 0) {\n <yuv-multi-object-summary [headline]=\"'yuv.app.drive.multiselected.details' | translate: { count: selection().length }\"></yuv-multi-object-summary>\n } @else if (tileList()?.items?.length === 0) {\n <!-- TODO: CHOULD HAVE A DIFFERENT MESSAGE FOR EMPTY RESULTS EMPTY FOR NOW -->\n <div class=\"message\">{{ 'yuv.app.drive.empty.results.details.message' | translate }}</div>\n } @else {\n <div class=\"message\">{{ 'yuv.app.drive.unselected.details' | translate }}</div>\n }\n }\n </ng-template>\n</yvc-split-view>\n", styles: [":host{--files-button-padding: calc(var(--app-pane-padding) / 4);--files-button-border-radius: 2px;--files-button-gap: calc(var(--app-pane-padding) / 4);--files-icon-size: 20px;height:100%;overflow:hidden;display:flex;flex-flow:column}:host.searchFocused header>nav .search{grid-column:-1/-3}:host header{flex:0 0 auto}:host header>nav{background-color:var(--app-drive-header-background);border-block-end:1px solid var(--panel-divider-color);display:grid;grid-template-columns:auto 1fr 1fr auto;align-items:center;gap:calc(var(--app-pane-padding) / 2);padding:calc(var(--app-pane-padding) / 4) calc(var(--app-pane-padding) / 2)}:host header>nav .nav{grid-column:1/2;grid-row:1;display:flex;align-items:center;gap:var(--files-button-gap)}:host header>nav .nav button{padding:var(--files-button-padding);border-radius:var(--files-button-border-radius)}:host header>nav .nav button yvc-icon{--icon-size: var(--files-icon-size)}:host header>nav .breadcrumb{grid-column:2/4;grid-row:1;align-self:stretch;display:flex;align-items:center;border-radius:var(--files-button-border-radius);padding:0 .5em;border:1px solid var(--panel-divider-color)}:host header>nav .search{grid-column:-1/-2;grid-row:1;z-index:1}:host yvc-split-view{flex:1;animation:fade-in .3s ease-in-out}:host ymd-ribbon{--ribbon-button-padding: var(--files-button-padding);--ribbon-button-border-radius: var(--files-button-border-radius);--ribbon-button-gap: var(--files-button-gap);--ribbon-icon-size: var(--files-icon-size)}:host ymd-ribbon .options{grid-area:options;display:flex;gap:var(--files-button-gap);align-items:center}:host ymd-ribbon .options yuv-tile-config-trigger{--icon-size: var(--files-icon-size);--button-padding: var(--files-button-padding)}:host ymd-ribbon .options button{padding:var(--files-button-padding);border-radius:var(--files-button-border-radius)}:host ymd-ribbon .options button yvc-icon{--icon-size: var(--files-icon-size)}:host ymd-ribbon .options button.toggle.enabled{background-color:var(--item-focus-background-color)}:host main{height:100%;overflow:hidden;display:flex;flex-flow:column}:host main yvc-master-details{flex:1;overflow:hidden;box-sizing:border-box}:host .error{display:grid;justify-items:center;align-items:center;height:100%;padding:0 2rem;text-align:center;color:var(--text-color-caption)}:host .error p{max-width:31ch;line-height:1.5em;display:grid;justify-items:center}:host .error p yvc-icon{--icon-size: 48px;display:block;margin-block-end:1rem}:host .files{display:flex;flex-flow:column;overflow:hidden;height:100%}:host .files header{flex:0 0 auto;padding:var(--app-pane-padding);display:grid;grid-template-columns:2fr max-content;grid-template-rows:auto auto 1fr;gap:0;grid-auto-flow:row;grid-template-areas:\"title sort\" \"searchfilter searchfilter\" \"flavours flavours\"}:host .files header h1{grid-area:title;margin:0;padding:0;font-size:var(--font-title);font-weight:400;text-overflow:ellipsis;overflow:hidden}:host .files header .flavors{grid-area:flavors;display:flex;gap:2px;justify-content:flex-end;padding:calc(var(--app-pane-padding) / 4)}:host .files header .flavors yuv-flavor-chip{font-size:var(--font-hint);cursor:pointer;--flavor-background: var(--panel-background);--flavor-icon-size: 16px}:host .files header .flavors yuv-flavor-chip:hover{--flavor-border-color: var(--color-accent)}:host .files header ymd-sort{grid-area:sort}:host .files header ymd-search-filter{grid-area:searchfilter}:host .files yuv-tile-list{flex:1;overflow:hidden}:host .message{display:grid;justify-items:center;align-items:center;height:100%;padding:0 2rem;text-align:center;color:var(--text-color-caption)}:host .message p{max-width:31ch;line-height:1.5em}:host yvc-split-view{height:100%;box-sizing:border-box}:host ymd-folder-tree,:host yuv-object-summary{height:100%;overflow-y:auto;box-sizing:border-box}:host yuv-tile-list{--tile-border: 1px solid var(--panel-divider-color);--tile-border-width: 0 0 1px 0;--tile-padding: calc(var(--app-pane-padding) / 2);--tile-icon-size: 18px;--tile-action-icon-size: 18px;--paging-background: var(--panel-background-lightgrey)}:host p.empty{color:var(--text-color-caption)}:host .details{height:100%}:host .details yuv-object-details{height:100%}:host.smallScreen yuv-tile-list{--tile-padding: var(--app-pane-padding) !important}@keyframes fade-in{0%{opacity:0}}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "ngmodule", type: YvcIconModule }, { kind: "component", type: i1$1.Icon, selector: "yvc-icon", inputs: ["label", "svg", "svgSrc"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: RouterModule }, { kind: "ngmodule", type: YvcSplitViewModule }, { kind: "component", type: i3.SplitViewComponent, selector: "yvc-split-view", inputs: ["direction", "gutterSize", "restrictMove", "disabled", "gutterDblClickDuration", "layoutSettingsID"], outputs: ["layoutSettingsChange", "dragStart", "dragEnd", "gutterClick", "gutterDblClick"] }, { kind: "directive", type: i3.SplitAreaDirective, selector: "[yvcSplitArea]", inputs: ["size", "order", "minSize", "maxSize", "panelClass", "visible"] }, { kind: "component", type: TileListComponent, selector: "yuv-tile-list", inputs: ["bucket", "multiselect", "options", "flavor", "query", "preselect", "highlights"], outputs: ["itemSelect", "copy", "cut", "busy", "queryResult", "selectionChange", "itemDblClick", "ctxMenu"] }, { kind: "component", type: BreadcrumbComponent, selector: "ymd-breadcrumb" }, { kind: "component", type: FolderTreeComponent, selector: "ymd-folder-tree" }, { kind: "component", type: ObjectSummaryComponent, selector: "yuv-object-summary", inputs: ["actions", "dmsObject", "objectId", "configType"] }, { kind: "component", type: TileConfigTriggerComponent, selector: "yuv-tile-config-trigger", inputs: ["icon", "bucket", "bucketLabel", "options"] }, { kind: "component", type: RibbonComponent, selector: "ymd-ribbon", inputs: ["busy", "enableClipboard", "objects", "excludeActions"] }, { kind: "component", type: AddButtonComponent, selector: "ymd-add-button", inputs: ["disabled"] }, { kind: "component", type: SimpleSearchComponent, selector: "yuv-simple-search", inputs: ["targets", "query"], outputs: ["querySubmit", "targetSelectionChanged", "queryChange", "typeAggregation"] }, { kind: "component", type: MultiObjectSummaryComponent, selector: "yuv-multi-object-summary", inputs: ["headline"] }, { kind: "component", type: SortComponent, selector: "ymd-sort", outputs: ["sortChanged"] }, { kind: "component", type: SearchFilterComponent, selector: "ymd-search-filter", inputs: ["query"], outputs: ["queryChange"] }, { kind: "directive", type: FileDropZoneDirective, selector: "[yuvFileDropZone]", inputs: ["yuvFileDropZone", "fileDropDisabled"], outputs: ["fileDrop", "fileDropOver"] }] }); }
|
|
2726
|
+
}
|
|
2727
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FilesPageComponent, decorators: [{
|
|
2728
|
+
type: Component,
|
|
2729
|
+
args: [{ selector: 'ymd-files', standalone: true, imports: [NgClass, AsyncPipe, ...module, ...components, FileDropZoneDirective], host: {
|
|
2730
|
+
'[class.smallScreen]': 'smallScreenLayout()'
|
|
2731
|
+
}, template: "<header>\n <!-- navigation bar -->\n <nav [attr.aria-label]=\"'yuv.app.drive.files.naviagtion.aria.label' | translate\">\n <div class=\"nav\">\n <button class=\"back\" [disabled]=\"!currentFolder\" title=\"{{ 'yuv.app.drive.files.nav.back.tooltip' | translate }}\" (click)=\"openParent()\">\n <yvc-icon [svg]=\"icons.back\"></yvc-icon>\n </button>\n <button class=\"refresh\" title=\"{{ 'yuv.app.drive.files.nav.refresh.tooltip' | translate }}\" (click)=\"refresh()\">\n <yvc-icon [svg]=\"icons.refresh\"></yvc-icon>\n </button>\n </div>\n\n @if (!query()?.term) {\n <ymd-breadcrumb></ymd-breadcrumb>\n } @else {\n <div class=\"breadcrumb\"></div>\n }\n <div class=\"search\">\n <yuv-simple-search [query]=\"query()\" (querySubmit)=\"onQuerySubmit($event)\"></yuv-simple-search>\n <!-- TODO: enable again once drive search needs to be a little bit more sophisticated -->\n <!-- <ymd-drive-search (focused)=\"searchFocused = $event\"></ymd-drive-search> -->\n </div>\n </nav>\n\n <!-- ribbon with actions and options -->\n <ymd-ribbon [objects]=\"selection()\" [busy]=\"busy()\" [enableClipboard]=\"true\">\n <ng-template #primaryActions>\n <ymd-add-button [disabled]=\"disableCreate\"></ymd-add-button>\n </ng-template>\n\n <ng-template #secondaryActions>\n <div class=\"options\">\n @if (!smallScreenLayout()) {\n <button\n class=\"toggle-tree toggle\"\n [ngClass]=\"{ enabled: enableTree() }\"\n title=\"{{ 'yuv.app.drive.files.toggletree.tooltip' | translate }}\"\n (click)=\"enableTree.set(!enableTree())\"\n >\n <yvc-icon [svg]=\"icons.toggleLeft\"></yvc-icon>\n </button>\n <button\n class=\"toggle-details toggle\"\n [ngClass]=\"{ enabled: enableDetails() }\"\n title=\"{{ 'yuv.app.drive.files.toggledetails.tooltip' | translate }}\"\n (click)=\"enableDetails.set(!enableDetails())\"\n >\n <yvc-icon [svg]=\"icons.toggleRight\"></yvc-icon>\n </button>\n }\n <yuv-tile-config-trigger\n [icon]=\"icons.settings\"\n [bucket]=\"objectConfigBucket\"\n [bucketLabel]=\"tileConfigBucketLabel\"\n [options]=\"tileListOptions\"\n ></yuv-tile-config-trigger>\n </div>\n </ng-template>\n </ymd-ribbon>\n</header>\n\n<yvc-split-view [gutterSize]=\"1\" (layoutSettingsChange)=\"onLayoutSettingsChange($event)\">\n <!-- folder tree -->\n <ng-template yvcSplitArea [size]=\"20\" [visible]=\"enableTree() && !smallScreenLayout()\">\n <ymd-folder-tree yuvFocusable=\"Tree\"></ymd-folder-tree>\n </ng-template>\n\n <!-- files -->\n <ng-template yvcSplitArea [size]=\"60\">\n @let err = error();\n @if (err) {\n <div class=\"error\">\n <p>\n <yvc-icon [svg]=\"icons.attention\"></yvc-icon>\n @switch (err) {\n @case (ERROR_CODE.NOT_FOUND) {\n {{ 'yuv.app.drive.files.error.load.not-found' | translate }}\n }\n @case (ERROR_CODE.INVALID_ID) {\n {{ 'yuv.app.drive.files.error.load.invalid-id' | translate }}\n }\n @default {\n {{ 'yuv.app.drive.files.error.load' | translate }}\n }\n }\n </p>\n </div>\n } @else {\n <div class=\"files\" [yuvFileDropZone]=\"{ label: 'yuv.app.drive.files.dropzone.label' | translate }\" (fileDrop)=\"onFileDrop($event)\">\n <header class=\"files-header\">\n <h1>{{ queryTitle() }}</h1>\n @if (query()?.term) {\n <ymd-search-filter [query]=\"query()\" (queryChange)=\"onFilterQueryChange($event)\"></ymd-search-filter>\n }\n @if (sortOptionsAvailable()) {\n <ymd-sort />\n }\n <div class=\"flavors\">\n <!-- TODO: enable again once flavors/aspects are supported -->\n <!-- @for (f of flavorChips; track f.id) {\n <yuv-flavor-chip [ngClass]=\"{ active: f.id === appliedFlavor?.id }\" [flavor]=\"f\" (click)=\"appliedFlavor = f\"></yuv-flavor-chip>\n }-->\n </div>\n </header>\n\n <yuv-tile-list\n #tileList\n class=\"staggered\"\n [attr.aria-label]=\"'yuv.app.drive.files.content.aria.label' | translate\"\n [attr.aria-busy]=\"busy()\"\n [attr.role]=\"'listbox'\"\n (keydown.delete)=\"onDelete()\"\n [bucket]=\"objectConfigBucket\"\n [multiselect]=\"true\"\n [query]=\"query()\"\n [flavor]=\"appliedFlavor\"\n [options]=\"tileListOptions\"\n (itemDblClick)=\"itemDoubleClicked($event)\"\n (itemSelect)=\"itemClicked($event)\"\n (selectionChange)=\"selectionChanged($event)\"\n (copy)=\"onCopy($event)\"\n (cut)=\"onCut($event)\"\n (busy)=\"setBusy($event)\"\n (ctxMenu)=\"onContextmenu($event)\"\n [highlights]=\"highlightStyles$ | async\"\n >\n <div #empty>\n @if (emptyMode() === 'root') {\n <p class=\"empty\">{{ 'yuv.app.drive.files.content.empty.root.list' | translate }}</p>\n } @else if (emptyMode() === 'query') {\n <p class=\"empty\">{{ 'yuv.app.drive.files.content.empty.query.list' | translate }}</p>\n } @else {\n <p class=\"empty\">{{ 'yuv.app.drive.files.content.empty.list' | translate }}</p>\n }\n </div>\n </yuv-tile-list>\n </div>\n }\n </ng-template>\n\n <!-- details -->\n <ng-template yvcSplitArea [size]=\"20\" [visible]=\"enableDetails()\">\n @let selectedItem = selected();\n @if (enableDetails() && selectedItem) {\n @if (selectedItem?.isFolder) {\n <yuv-object-summary [configType]=\"configTypeOptions['folder']\" [dmsObject]=\"selectedItem\"></yuv-object-summary>\n } @else {\n <yuv-object-summary\n [configType]=\"configTypeOptions['file']\"\n [dmsObject]=\"selectedItem\"\n [yuvFileDropZone]=\"{ label: 'yuv.app.drive.files.dropzone.content.replace.label' | translate }\"\n [fileDropDisabled]=\"fileDropSummaryDisabled()\"\n (fileDrop)=\"onFileUpdateDrop($event)\"\n ></yuv-object-summary>\n }\n } @else {\n @let sel = selection();\n @if (sel && sel.length > 0) {\n <yuv-multi-object-summary [headline]=\"'yuv.app.drive.multiselected.details' | translate: { count: selection().length }\"></yuv-multi-object-summary>\n } @else if (tileList()?.items?.length === 0) {\n <!-- TODO: CHOULD HAVE A DIFFERENT MESSAGE FOR EMPTY RESULTS EMPTY FOR NOW -->\n <div class=\"message\">{{ 'yuv.app.drive.empty.results.details.message' | translate }}</div>\n } @else {\n <div class=\"message\">{{ 'yuv.app.drive.unselected.details' | translate }}</div>\n }\n }\n </ng-template>\n</yvc-split-view>\n", styles: [":host{--files-button-padding: calc(var(--app-pane-padding) / 4);--files-button-border-radius: 2px;--files-button-gap: calc(var(--app-pane-padding) / 4);--files-icon-size: 20px;height:100%;overflow:hidden;display:flex;flex-flow:column}:host.searchFocused header>nav .search{grid-column:-1/-3}:host header{flex:0 0 auto}:host header>nav{background-color:var(--app-drive-header-background);border-block-end:1px solid var(--panel-divider-color);display:grid;grid-template-columns:auto 1fr 1fr auto;align-items:center;gap:calc(var(--app-pane-padding) / 2);padding:calc(var(--app-pane-padding) / 4) calc(var(--app-pane-padding) / 2)}:host header>nav .nav{grid-column:1/2;grid-row:1;display:flex;align-items:center;gap:var(--files-button-gap)}:host header>nav .nav button{padding:var(--files-button-padding);border-radius:var(--files-button-border-radius)}:host header>nav .nav button yvc-icon{--icon-size: var(--files-icon-size)}:host header>nav .breadcrumb{grid-column:2/4;grid-row:1;align-self:stretch;display:flex;align-items:center;border-radius:var(--files-button-border-radius);padding:0 .5em;border:1px solid var(--panel-divider-color)}:host header>nav .search{grid-column:-1/-2;grid-row:1;z-index:1}:host yvc-split-view{flex:1;animation:fade-in .3s ease-in-out}:host ymd-ribbon{--ribbon-button-padding: var(--files-button-padding);--ribbon-button-border-radius: var(--files-button-border-radius);--ribbon-button-gap: var(--files-button-gap);--ribbon-icon-size: var(--files-icon-size)}:host ymd-ribbon .options{grid-area:options;display:flex;gap:var(--files-button-gap);align-items:center}:host ymd-ribbon .options yuv-tile-config-trigger{--icon-size: var(--files-icon-size);--button-padding: var(--files-button-padding)}:host ymd-ribbon .options button{padding:var(--files-button-padding);border-radius:var(--files-button-border-radius)}:host ymd-ribbon .options button yvc-icon{--icon-size: var(--files-icon-size)}:host ymd-ribbon .options button.toggle.enabled{background-color:var(--item-focus-background-color)}:host main{height:100%;overflow:hidden;display:flex;flex-flow:column}:host main yvc-master-details{flex:1;overflow:hidden;box-sizing:border-box}:host .error{display:grid;justify-items:center;align-items:center;height:100%;padding:0 2rem;text-align:center;color:var(--text-color-caption)}:host .error p{max-width:31ch;line-height:1.5em;display:grid;justify-items:center}:host .error p yvc-icon{--icon-size: 48px;display:block;margin-block-end:1rem}:host .files{display:flex;flex-flow:column;overflow:hidden;height:100%}:host .files header{flex:0 0 auto;padding:var(--app-pane-padding);display:grid;grid-template-columns:2fr max-content;grid-template-rows:auto auto 1fr;gap:0;grid-auto-flow:row;grid-template-areas:\"title sort\" \"searchfilter searchfilter\" \"flavours flavours\"}:host .files header h1{grid-area:title;margin:0;padding:0;font-size:var(--font-title);font-weight:400;text-overflow:ellipsis;overflow:hidden}:host .files header .flavors{grid-area:flavors;display:flex;gap:2px;justify-content:flex-end;padding:calc(var(--app-pane-padding) / 4)}:host .files header .flavors yuv-flavor-chip{font-size:var(--font-hint);cursor:pointer;--flavor-background: var(--panel-background);--flavor-icon-size: 16px}:host .files header .flavors yuv-flavor-chip:hover{--flavor-border-color: var(--color-accent)}:host .files header ymd-sort{grid-area:sort}:host .files header ymd-search-filter{grid-area:searchfilter}:host .files yuv-tile-list{flex:1;overflow:hidden}:host .message{display:grid;justify-items:center;align-items:center;height:100%;padding:0 2rem;text-align:center;color:var(--text-color-caption)}:host .message p{max-width:31ch;line-height:1.5em}:host yvc-split-view{height:100%;box-sizing:border-box}:host ymd-folder-tree,:host yuv-object-summary{height:100%;overflow-y:auto;box-sizing:border-box}:host yuv-tile-list{--tile-border: 1px solid var(--panel-divider-color);--tile-border-width: 0 0 1px 0;--tile-padding: calc(var(--app-pane-padding) / 2);--tile-icon-size: 18px;--tile-action-icon-size: 18px;--paging-background: var(--panel-background-lightgrey)}:host p.empty{color:var(--text-color-caption)}:host .details{height:100%}:host .details yuv-object-details{height:100%}:host.smallScreen yuv-tile-list{--tile-padding: var(--app-pane-padding) !important}@keyframes fade-in{0%{opacity:0}}\n"] }]
|
|
2732
|
+
}], ctorParameters: () => [], propDecorators: { searchFocused: [{
|
|
2733
|
+
type: HostBinding,
|
|
2734
|
+
args: ['class.searchFocused']
|
|
2735
|
+
}] } });
|
|
2736
|
+
|
|
2737
|
+
class ObjectPageComponent {
|
|
2738
|
+
#dmsService;
|
|
2739
|
+
#eventService;
|
|
2740
|
+
#shellService;
|
|
2741
|
+
#route;
|
|
2742
|
+
#router;
|
|
2743
|
+
#objectConfig;
|
|
2744
|
+
#drive;
|
|
2745
|
+
#device;
|
|
2746
|
+
#dmsObjectEffect;
|
|
2747
|
+
constructor() {
|
|
2748
|
+
this.#dmsService = inject(DmsService);
|
|
2749
|
+
this.#eventService = inject(EventService);
|
|
2750
|
+
this.#shellService = inject(ShellService);
|
|
2751
|
+
this.#route = inject(ActivatedRoute);
|
|
2752
|
+
this.#router = inject(Router);
|
|
2753
|
+
this.#objectConfig = inject(ObjectConfigService);
|
|
2754
|
+
this.translate = inject(TranslateService);
|
|
2755
|
+
this.#drive = inject(DriveService);
|
|
2756
|
+
this.#device = inject(DeviceService);
|
|
2757
|
+
this.busy = this.#drive.state$.busy;
|
|
2758
|
+
this.smallScreenLayout = signal(false);
|
|
2759
|
+
this.dmsObject = signal(undefined);
|
|
2760
|
+
this.#dmsObjectEffect = effect(() => this.#setHeaderData());
|
|
2761
|
+
this.fileDropReplaceDisabled = computed(() => !this.dmsObject()?.permissions?.writeContent);
|
|
2762
|
+
this.flavoredDmsObject = computed(() => {
|
|
2763
|
+
const o = this.dmsObject();
|
|
2764
|
+
return o
|
|
2765
|
+
? {
|
|
2766
|
+
object: o,
|
|
2767
|
+
flavors: [
|
|
2768
|
+
// {
|
|
2769
|
+
// id: APP_SCHEMA.types['file']['id'],
|
|
2770
|
+
// icon: APP_SCHEMA.types['file']['icon'],
|
|
2771
|
+
// sot: FS_SOTS.object
|
|
2772
|
+
// },
|
|
2773
|
+
...this.#shellService.getAppliedObjectFlavors(o).applied
|
|
2774
|
+
]
|
|
2775
|
+
}
|
|
2776
|
+
: undefined;
|
|
2777
|
+
});
|
|
2778
|
+
this.versionsLink = computed(() => {
|
|
2779
|
+
const o = this.dmsObject();
|
|
2780
|
+
return o ? `../../versions/${o.id}` : '';
|
|
2781
|
+
});
|
|
2782
|
+
this.icons = {
|
|
2783
|
+
back: YUV_ICONS.back,
|
|
2784
|
+
error: YUV_ICONS.attention,
|
|
2785
|
+
refresh: YUV_ICONS.refresh
|
|
2786
|
+
};
|
|
2787
|
+
this.layoutSettingIdBase = 'app.drive.object.';
|
|
2788
|
+
this.excludeActions = [APP_ACTIONS.paste, APP_ACTIONS.contentUpdate, BASE_ACTION.copy, BASE_ACTION.cut];
|
|
2789
|
+
this.#route.paramMap.pipe(takeUntilDestroyed()).subscribe((p) => {
|
|
2790
|
+
this._loadDetails(p.get('id'));
|
|
2791
|
+
});
|
|
2792
|
+
this.#device.screenChange$.pipe(takeUntilDestroyed()).subscribe({
|
|
2793
|
+
next: (s) => {
|
|
2794
|
+
const ssl = s.size === 's' && s.orientation === 'portrait';
|
|
2795
|
+
this.smallScreenLayout.set(ssl);
|
|
2796
|
+
}
|
|
2797
|
+
});
|
|
2798
|
+
this.#eventService
|
|
2799
|
+
.on(YuvEventType.DMS_OBJECT_UPDATED)
|
|
2800
|
+
.pipe(takeUntilDestroyed())
|
|
2801
|
+
.subscribe((e) => {
|
|
2802
|
+
if (e.data.id === this.dmsObject()?.id)
|
|
2803
|
+
this.dmsObject.set(e.data);
|
|
2804
|
+
});
|
|
2805
|
+
this.#eventService
|
|
2806
|
+
.on(YuvEventType.DMS_OBJECT_DELETED)
|
|
2807
|
+
.pipe(takeUntilDestroyed())
|
|
2808
|
+
.subscribe((e) => {
|
|
2809
|
+
if (e.data.id === this.dmsObject()?.id)
|
|
2810
|
+
if (e.data.id === this.dmsObject()?.id)
|
|
2811
|
+
// navigate to parent folder
|
|
2812
|
+
this.openParent();
|
|
2813
|
+
});
|
|
2814
|
+
}
|
|
2815
|
+
refresh() {
|
|
2816
|
+
const o = this.dmsObject();
|
|
2817
|
+
if (o)
|
|
2818
|
+
this.#dmsService.getDmsObject(o.id).subscribe((o) => {
|
|
2819
|
+
this.dmsObject.set(o);
|
|
2820
|
+
});
|
|
2821
|
+
if (o)
|
|
2822
|
+
this.#dmsService.getDmsObject(o.id).subscribe((o) => {
|
|
2823
|
+
this.dmsObject.set(o);
|
|
2824
|
+
});
|
|
2825
|
+
}
|
|
2826
|
+
openParent() {
|
|
2827
|
+
const pid = this.dmsObject()?.parentId || DRIVE_ROOT_FOLDER_ID;
|
|
2828
|
+
this.#router.navigate(['../..', 'files', pid], {
|
|
2829
|
+
relativeTo: this.#route
|
|
2830
|
+
});
|
|
2831
|
+
}
|
|
2832
|
+
onIndexdataSaved(updatedObject) {
|
|
2833
|
+
this.dmsObject.set(updatedObject);
|
|
2834
|
+
}
|
|
2835
|
+
#setHeaderData() {
|
|
2836
|
+
const o = this.dmsObject();
|
|
2837
|
+
if (!o) {
|
|
2838
|
+
this.headerData = undefined;
|
|
2839
|
+
}
|
|
2840
|
+
else {
|
|
2841
|
+
const roc = this.#objectConfig.getResolvedObjectConfig(o.data, APP_SCHEMA.types['file'], APP_ID);
|
|
2842
|
+
this.headerData = {
|
|
2843
|
+
title: roc.title,
|
|
2844
|
+
description: roc.description,
|
|
2845
|
+
icon: roc.icon?.value
|
|
2846
|
+
};
|
|
2847
|
+
}
|
|
2848
|
+
}
|
|
2849
|
+
onFileDrop(file) {
|
|
2850
|
+
this.#drive.setBusy(true);
|
|
2851
|
+
const dmsObject = this.dmsObject();
|
|
2852
|
+
dmsObject &&
|
|
2853
|
+
this.#drive
|
|
2854
|
+
.uploadContent(dmsObject.id, file[0])
|
|
2855
|
+
.pipe(finalize(() => this.#drive.setBusy(false)))
|
|
2856
|
+
.subscribe();
|
|
2857
|
+
}
|
|
2858
|
+
versionSelected(version) {
|
|
2859
|
+
const dmsObject = this.dmsObject();
|
|
2860
|
+
dmsObject && this.#router.navigate(['../..', 'versions', dmsObject.id], { queryParams: { version }, relativeTo: this.#route });
|
|
2861
|
+
}
|
|
2862
|
+
_loadDetails(id) {
|
|
2863
|
+
if (!id) {
|
|
2864
|
+
this.dmsObject.set(undefined);
|
|
2865
|
+
this.headerData = undefined;
|
|
2866
|
+
}
|
|
2867
|
+
else {
|
|
2868
|
+
this.#shellService.addBusy();
|
|
2869
|
+
// load the dms object
|
|
2870
|
+
this.#dmsService.getDmsObject(id).subscribe({
|
|
2871
|
+
next: (o) => {
|
|
2872
|
+
this.dmsObject.set(o);
|
|
2873
|
+
},
|
|
2874
|
+
error: (e) => {
|
|
2875
|
+
this.dmsObject.set(undefined);
|
|
2876
|
+
switch (e.status) {
|
|
2877
|
+
case 404:
|
|
2878
|
+
this.errorMessage = this.translate.instant('yuv.app.drive.page.object.error.404');
|
|
2879
|
+
break;
|
|
2880
|
+
default:
|
|
2881
|
+
this.errorMessage = this.translate.instant('yuv.app.drive.page.object.error.default');
|
|
2882
|
+
}
|
|
2883
|
+
},
|
|
2884
|
+
complete: () => this.#shellService.removeBusy()
|
|
2885
|
+
});
|
|
2886
|
+
}
|
|
2887
|
+
}
|
|
2888
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ObjectPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2889
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: ObjectPageComponent, isStandalone: true, selector: "ymd-object", host: { attributes: { "class.smallScreenLayout": "smallScreenLayout()" } }, ngImport: i0, template: "@let object = dmsObject();\n@if (object) {\n <div\n class=\"object\"\n yuvContainerSize\n [yuvFileDropZone]=\"{ label: 'yuv.app.drive.files.dropzone.content.replace.label' | translate }\"\n [fileDropDisabled]=\"fileDropReplaceDisabled()\"\n (fileDrop)=\"onFileDrop($event)\"\n >\n <ymd-ribbon [objects]=\"[object]\" [excludeActions]=\"excludeActions\">\n <ng-template #primaryActions>\n <div class=\"nav\">\n <button class=\"back\" (click)=\"openParent()\">\n <yvc-icon [svg]=\"icons.back\"></yvc-icon>\n </button>\n <button class=\"refresh\" title=\"{{ 'yuv.app.drive.page.object.refresh.tooltip' | translate }}\" (click)=\"refresh()\">\n <yvc-icon [svg]=\"icons.refresh\"></yvc-icon>\n </button>\n </div>\n </ng-template>\n <!-- <ng-template #secondaryActions></ng-template> -->\n </ymd-ribbon>\n\n @let ssl = smallScreenLayout();\n @if (ssl) {\n <yvc-tabs [layoutSettingsID]=\"layoutSettingIdBase + 'tabs.small'\" [cacheViews]=\"false\">\n <ng-template [yvcTab]=\"{ id: 'content_s', label: 'yuv.app.drive.object-metadata.tabs.content.title' | translate }\">\n @if (object && object?.content) {\n <yuv-object-preview [dmsObject]=\"object\"></yuv-object-preview>\n }\n </ng-template>\n <ng-template [yvcTab]=\"{ id: 'indexdata_s', label: 'yuv.app.drive.object-metadata.tabs.indexdata.title' | translate }\">\n <yuv-object-metadata [flavoredDmsObject]=\"flavoredDmsObject()\" (indexDataSaved)=\"onIndexdataSaved($event)\"> </yuv-object-metadata>\n </ng-template>\n <ng-template [yvcTab]=\"{ id: 'history_s', label: 'yuv.app.drive.object-metadata.tabs.history.title' | translate }\">\n <yuv-object-audit [dmsObject]=\"object\"></yuv-object-audit>\n </ng-template>\n </yvc-tabs>\n } @else {\n <yvc-split-view [layoutSettingsID]=\"layoutSettingIdBase + 'splitview'\" [gutterSize]=\"1\">\n <ng-template yvcSplitArea [size]=\"40\">\n <section class=\"meta\">\n <header>\n <yuv-object-flavor disableSelection=\"true\" [dmsObject]=\"object\"></yuv-object-flavor>\n\n @if (headerData) {\n <yvc-icon class=\"object-icon\" [svg]=\"headerData.icon\"></yvc-icon>\n <h1><ng-container *yuvRenderer=\"headerData.title\"></ng-container></h1>\n <div class=\"description\"><ng-container *yuvRenderer=\"headerData.description\"></ng-container></div>\n }\n </header>\n\n <yvc-tabs [layoutSettingsID]=\"layoutSettingIdBase + 'tabs'\">\n <ng-template [yvcTab]=\"{ id: 'indexdata', label: 'yuv.app.drive.object-metadata.tabs.indexdata.title' | translate }\">\n <yuv-object-metadata [flavoredDmsObject]=\"flavoredDmsObject()\" (indexDataSaved)=\"onIndexdataSaved($event)\"> </yuv-object-metadata>\n </ng-template>\n <ng-template [yvcTab]=\"{ id: 'history', label: 'yuv.app.drive.object-metadata.tabs.history.title' | translate }\">\n <yuv-object-audit [dmsObject]=\"object\" [versionsLink]=\"versionsLink()\"></yuv-object-audit>\n </ng-template>\n </yvc-tabs>\n </section>\n </ng-template>\n <ng-template yvcSplitArea [size]=\"60\">\n @if (object && object?.content) {\n <yuv-object-preview [dmsObject]=\"object\"></yuv-object-preview>\n }\n </ng-template>\n </yvc-split-view>\n }\n </div>\n} @else if (errorMessage) {\n <!-- object could not be loaded -->\n <div class=\"error state\">\n <yvc-icon [svg]=\"icons.error\"></yvc-icon>\n <p>{{ errorMessage }}</p>\n </div>\n} @else {\n <!-- object is loading -->\n <div class=\"loading state\">\n <div class=\"yuv-loader\"></div>\n </div>\n}\n", styles: [":host{--button-gap: calc(var(--app-pane-padding) / 4);display:flex;flex-flow:column;height:100%;overflow:hidden}:host .state{display:flex;flex-flow:column;height:100%;align-items:center;justify-content:center;border-block-start:1px solid var(--panel-divider-color)}:host .error yvc-icon{--icon-size: 48px;color:rgb(from var(--text-color-body) r g b/.1)}:host .error p{margin:var(--app-pane-padding);max-width:35ch;color:var(--text-color-caption)}:host .state,:host .object{animation:fade-in .3s ease-in-out}:host .object{height:100%;display:flex;flex-flow:column}:host .object ymd-ribbon{background-color:var(--app-drive-header-background);border-block-end:1px solid var(--panel-divider-color);flex:0 0 auto}:host .object ymd-ribbon button{padding:var(--ribbon-button-padding);border-radius:var(--ribbon-button-border-radius)}:host .object ymd-ribbon button yvc-icon{--icon-size: var(--ribbon-icon-size)}:host .object ymd-ribbon .nav{display:flex;align-items:center;gap:var(--button-gap)}:host .object yvc-tabs{flex:1;background-color:var(--app-drive-header-background)}:host .object yvc-split-view{flex:1}:host .meta{background-color:var(--panel-background);display:flex;flex-flow:column;height:100%}:host .meta header{flex:0 0 auto;display:grid;grid-template-rows:auto calc(var(--app-pane-padding) / 2) auto auto var(--app-pane-padding);grid-template-columns:calc(var(--app-pane-padding) / 2) auto 1fr auto calc(var(--app-pane-padding) / 2);grid-template-areas:\"flavor flavor flavor flavor flavor\" \". . . . .\" \". icon title actions .\" \". . description description .\" \". . . . .\";gap:calc(var(--app-pane-padding) / 2)}:host .meta header yuv-object-flavor{grid-area:flavor;border-block-end:1px solid var(--panel-divider-color)}:host .meta header yvc-icon.object-icon{color:var(--text-color-caption);grid-area:icon}:host .meta header h1{grid-area:title;margin:0;padding:0;font-size:var(--font-title);font-weight:400}:host .meta header .description{grid-area:description}:host .meta yvc-tabs{flex:1}@keyframes fade-in{0%{opacity:0}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: ObjectMetadataComponent, selector: "yuv-object-metadata", inputs: ["situation", "formDisabled", "dmsObject", "flavoredDmsObject"], outputs: ["indexDataSaved", "statusChanged"] }, { kind: "component", type: ObjectAuditComponent, selector: "yuv-object-audit", inputs: ["dmsObject", "skipActions", "allActions", "versionsLink"] }, { kind: "component", type: ObjectFlavorComponent, selector: "yuv-object-flavor", inputs: ["dmsObject"], outputs: ["flavorClick"] }, { kind: "ngmodule", type: YvcIconModule }, { kind: "component", type: i1$1.Icon, selector: "yvc-icon", inputs: ["label", "svg", "svgSrc"] }, { kind: "ngmodule", type: YvcSplitViewModule }, { kind: "component", type: i3.SplitViewComponent, selector: "yvc-split-view", inputs: ["direction", "gutterSize", "restrictMove", "disabled", "gutterDblClickDuration", "layoutSettingsID"], outputs: ["layoutSettingsChange", "dragStart", "dragEnd", "gutterClick", "gutterDblClick"] }, { kind: "directive", type: i3.SplitAreaDirective, selector: "[yvcSplitArea]", inputs: ["size", "order", "minSize", "maxSize", "panelClass", "visible"] }, { kind: "directive", type: RendererDirective, selector: "[yuvRenderer]", inputs: ["yuvRenderer"] }, { kind: "directive", type: ContainerSizeDirective, selector: "[yuvContainerSize]", outputs: ["containerHeight", "containerWidth"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }, { kind: "component", type: RibbonComponent, selector: "ymd-ribbon", inputs: ["busy", "enableClipboard", "objects", "excludeActions"] }, { kind: "ngmodule", type: YvcTabsModule }, { kind: "component", type: i2$2.Tabs, selector: "yvc-tabs", inputs: ["tabs", "layoutSettingsID", "panelOrder", "panelOrderIncludeUnmentioned", "cacheViews", "tabSplitEnabled", "tabRemoveEnabled"], outputs: ["tabSplit", "tabRemove", "tabChange"] }, { kind: "directive", type: i2$2.YvcTabDirective, selector: "[yvcTab]", inputs: ["yvcTab"] }, { kind: "component", type: ObjectPreviewComponent, selector: "yuv-object-preview", inputs: ["objectId", "dmsObject", "version"] }, { kind: "directive", type: FileDropZoneDirective, selector: "[yuvFileDropZone]", inputs: ["yuvFileDropZone", "fileDropDisabled"], outputs: ["fileDrop", "fileDropOver"] }] }); }
|
|
2890
|
+
}
|
|
2891
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ObjectPageComponent, decorators: [{
|
|
2892
|
+
type: Component,
|
|
2893
|
+
args: [{ selector: 'ymd-object', standalone: true, imports: [
|
|
2894
|
+
CommonModule,
|
|
2895
|
+
ObjectMetadataComponent,
|
|
2896
|
+
ObjectAuditComponent,
|
|
2897
|
+
ObjectFlavorComponent,
|
|
2898
|
+
YvcIconModule,
|
|
2899
|
+
YvcSplitViewModule,
|
|
2900
|
+
RendererDirective,
|
|
2901
|
+
ContainerSizeDirective,
|
|
2902
|
+
TranslateModule,
|
|
2903
|
+
RibbonComponent,
|
|
2904
|
+
YvcTabsModule,
|
|
2905
|
+
ObjectPreviewComponent,
|
|
2906
|
+
FileDropZoneDirective
|
|
2907
|
+
], host: {
|
|
2908
|
+
['class.smallScreenLayout']: 'smallScreenLayout()'
|
|
2909
|
+
}, template: "@let object = dmsObject();\n@if (object) {\n <div\n class=\"object\"\n yuvContainerSize\n [yuvFileDropZone]=\"{ label: 'yuv.app.drive.files.dropzone.content.replace.label' | translate }\"\n [fileDropDisabled]=\"fileDropReplaceDisabled()\"\n (fileDrop)=\"onFileDrop($event)\"\n >\n <ymd-ribbon [objects]=\"[object]\" [excludeActions]=\"excludeActions\">\n <ng-template #primaryActions>\n <div class=\"nav\">\n <button class=\"back\" (click)=\"openParent()\">\n <yvc-icon [svg]=\"icons.back\"></yvc-icon>\n </button>\n <button class=\"refresh\" title=\"{{ 'yuv.app.drive.page.object.refresh.tooltip' | translate }}\" (click)=\"refresh()\">\n <yvc-icon [svg]=\"icons.refresh\"></yvc-icon>\n </button>\n </div>\n </ng-template>\n <!-- <ng-template #secondaryActions></ng-template> -->\n </ymd-ribbon>\n\n @let ssl = smallScreenLayout();\n @if (ssl) {\n <yvc-tabs [layoutSettingsID]=\"layoutSettingIdBase + 'tabs.small'\" [cacheViews]=\"false\">\n <ng-template [yvcTab]=\"{ id: 'content_s', label: 'yuv.app.drive.object-metadata.tabs.content.title' | translate }\">\n @if (object && object?.content) {\n <yuv-object-preview [dmsObject]=\"object\"></yuv-object-preview>\n }\n </ng-template>\n <ng-template [yvcTab]=\"{ id: 'indexdata_s', label: 'yuv.app.drive.object-metadata.tabs.indexdata.title' | translate }\">\n <yuv-object-metadata [flavoredDmsObject]=\"flavoredDmsObject()\" (indexDataSaved)=\"onIndexdataSaved($event)\"> </yuv-object-metadata>\n </ng-template>\n <ng-template [yvcTab]=\"{ id: 'history_s', label: 'yuv.app.drive.object-metadata.tabs.history.title' | translate }\">\n <yuv-object-audit [dmsObject]=\"object\"></yuv-object-audit>\n </ng-template>\n </yvc-tabs>\n } @else {\n <yvc-split-view [layoutSettingsID]=\"layoutSettingIdBase + 'splitview'\" [gutterSize]=\"1\">\n <ng-template yvcSplitArea [size]=\"40\">\n <section class=\"meta\">\n <header>\n <yuv-object-flavor disableSelection=\"true\" [dmsObject]=\"object\"></yuv-object-flavor>\n\n @if (headerData) {\n <yvc-icon class=\"object-icon\" [svg]=\"headerData.icon\"></yvc-icon>\n <h1><ng-container *yuvRenderer=\"headerData.title\"></ng-container></h1>\n <div class=\"description\"><ng-container *yuvRenderer=\"headerData.description\"></ng-container></div>\n }\n </header>\n\n <yvc-tabs [layoutSettingsID]=\"layoutSettingIdBase + 'tabs'\">\n <ng-template [yvcTab]=\"{ id: 'indexdata', label: 'yuv.app.drive.object-metadata.tabs.indexdata.title' | translate }\">\n <yuv-object-metadata [flavoredDmsObject]=\"flavoredDmsObject()\" (indexDataSaved)=\"onIndexdataSaved($event)\"> </yuv-object-metadata>\n </ng-template>\n <ng-template [yvcTab]=\"{ id: 'history', label: 'yuv.app.drive.object-metadata.tabs.history.title' | translate }\">\n <yuv-object-audit [dmsObject]=\"object\" [versionsLink]=\"versionsLink()\"></yuv-object-audit>\n </ng-template>\n </yvc-tabs>\n </section>\n </ng-template>\n <ng-template yvcSplitArea [size]=\"60\">\n @if (object && object?.content) {\n <yuv-object-preview [dmsObject]=\"object\"></yuv-object-preview>\n }\n </ng-template>\n </yvc-split-view>\n }\n </div>\n} @else if (errorMessage) {\n <!-- object could not be loaded -->\n <div class=\"error state\">\n <yvc-icon [svg]=\"icons.error\"></yvc-icon>\n <p>{{ errorMessage }}</p>\n </div>\n} @else {\n <!-- object is loading -->\n <div class=\"loading state\">\n <div class=\"yuv-loader\"></div>\n </div>\n}\n", styles: [":host{--button-gap: calc(var(--app-pane-padding) / 4);display:flex;flex-flow:column;height:100%;overflow:hidden}:host .state{display:flex;flex-flow:column;height:100%;align-items:center;justify-content:center;border-block-start:1px solid var(--panel-divider-color)}:host .error yvc-icon{--icon-size: 48px;color:rgb(from var(--text-color-body) r g b/.1)}:host .error p{margin:var(--app-pane-padding);max-width:35ch;color:var(--text-color-caption)}:host .state,:host .object{animation:fade-in .3s ease-in-out}:host .object{height:100%;display:flex;flex-flow:column}:host .object ymd-ribbon{background-color:var(--app-drive-header-background);border-block-end:1px solid var(--panel-divider-color);flex:0 0 auto}:host .object ymd-ribbon button{padding:var(--ribbon-button-padding);border-radius:var(--ribbon-button-border-radius)}:host .object ymd-ribbon button yvc-icon{--icon-size: var(--ribbon-icon-size)}:host .object ymd-ribbon .nav{display:flex;align-items:center;gap:var(--button-gap)}:host .object yvc-tabs{flex:1;background-color:var(--app-drive-header-background)}:host .object yvc-split-view{flex:1}:host .meta{background-color:var(--panel-background);display:flex;flex-flow:column;height:100%}:host .meta header{flex:0 0 auto;display:grid;grid-template-rows:auto calc(var(--app-pane-padding) / 2) auto auto var(--app-pane-padding);grid-template-columns:calc(var(--app-pane-padding) / 2) auto 1fr auto calc(var(--app-pane-padding) / 2);grid-template-areas:\"flavor flavor flavor flavor flavor\" \". . . . .\" \". icon title actions .\" \". . description description .\" \". . . . .\";gap:calc(var(--app-pane-padding) / 2)}:host .meta header yuv-object-flavor{grid-area:flavor;border-block-end:1px solid var(--panel-divider-color)}:host .meta header yvc-icon.object-icon{color:var(--text-color-caption);grid-area:icon}:host .meta header h1{grid-area:title;margin:0;padding:0;font-size:var(--font-title);font-weight:400}:host .meta header .description{grid-area:description}:host .meta yvc-tabs{flex:1}@keyframes fade-in{0%{opacity:0}}\n"] }]
|
|
2910
|
+
}], ctorParameters: () => [] });
|
|
2911
|
+
|
|
2912
|
+
const filesResolver = (route) => {
|
|
2913
|
+
const id = route.params['id'];
|
|
2914
|
+
const driveStore = inject(DriveService);
|
|
2915
|
+
if (id !== DRIVE_QUERY_FOLDER_ID)
|
|
2916
|
+
driveStore.resolveFilesState(id).subscribe(console.log);
|
|
2917
|
+
return of(true);
|
|
2918
|
+
};
|
|
2919
|
+
|
|
2920
|
+
const versionsResolver = (route) => {
|
|
2921
|
+
const id = route.params['id'];
|
|
2922
|
+
const driveStore = inject(DriveService);
|
|
2923
|
+
forkJoin([driveStore.getVersions(id), driveStore.getSelectedDmsObject(id)]).subscribe();
|
|
2924
|
+
return of(true);
|
|
2925
|
+
};
|
|
2926
|
+
|
|
2927
|
+
const YuuvisDriveRoutes = [
|
|
2928
|
+
{
|
|
2929
|
+
path: '',
|
|
2930
|
+
component: DriveFrameComponent,
|
|
2931
|
+
children: [
|
|
2932
|
+
{ path: 'files', redirectTo: 'files/root' },
|
|
2933
|
+
{ path: 'files/:id', component: FilesPageComponent, resolve: { filesResolver } },
|
|
2934
|
+
{ path: 'object/:id', component: ObjectPageComponent },
|
|
2935
|
+
{ path: '', redirectTo: 'files/root', pathMatch: 'full' }
|
|
2936
|
+
]
|
|
2937
|
+
}
|
|
2938
|
+
];
|
|
2939
|
+
|
|
2940
|
+
/**
|
|
2941
|
+
* Generated bundle index. Do not edit.
|
|
2942
|
+
*/
|
|
2943
|
+
|
|
2944
|
+
export { ACTION_CONTEXT, APP_ACTIONS, APP_ID, APP_PREFIX, APP_SCHEMA, FS_PROPERTIES, FS_SOTS, SearchFilterComponent, YuuvisDriveRoutes, provideDrive };
|
|
2945
|
+
//# sourceMappingURL=yuuvis-app-drive.mjs.map
|