@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.
Files changed (107) hide show
  1. package/README.md +47 -0
  2. package/esm2022/extensions/index.mjs +2 -0
  3. package/esm2022/extensions/lib/extensions.module.mjs +35 -0
  4. package/esm2022/extensions/lib/extensions.service.mjs +44 -0
  5. package/esm2022/extensions/lib/object-config.defaults.mjs +19 -0
  6. package/esm2022/extensions/yuuvis-app-drive-extensions.mjs +5 -0
  7. package/esm2022/index.mjs +5 -0
  8. package/esm2022/lib/actions/copy-link/copy-link.action.mjs +40 -0
  9. package/esm2022/lib/actions/index.mjs +7 -0
  10. package/esm2022/lib/actions/manage-versions/manage-versions.action.mjs +33 -0
  11. package/esm2022/lib/actions/manage-versions/manage-versions.component.mjs +105 -0
  12. package/esm2022/lib/actions/paste/paste.action.mjs +41 -0
  13. package/esm2022/lib/actions/rename/rename.action.mjs +31 -0
  14. package/esm2022/lib/actions/rename/rename.component.mjs +42 -0
  15. package/esm2022/lib/actions/rename/rename.validator.mjs +23 -0
  16. package/esm2022/lib/actions/updateContent/update.content.action.mjs +52 -0
  17. package/esm2022/lib/components/add-button/add-button-overlay/add-button-overlay.component.mjs +109 -0
  18. package/esm2022/lib/components/add-button/add-button.component.mjs +39 -0
  19. package/esm2022/lib/components/breadcrumb/breadcrumb.component.mjs +74 -0
  20. package/esm2022/lib/components/folder-tree/folder-tree.component.mjs +89 -0
  21. package/esm2022/lib/components/index.mjs +10 -0
  22. package/esm2022/lib/components/object-name/object-name.component.mjs +60 -0
  23. package/esm2022/lib/components/overlay/create-folder/create-folder.component.mjs +48 -0
  24. package/esm2022/lib/components/paste-from-clipboard/paste-from-clipboard.component.mjs +28 -0
  25. package/esm2022/lib/components/ribbon/ribbon.component.mjs +102 -0
  26. package/esm2022/lib/components/search-filter/date-range-picker/date-range-picker.component.mjs +38 -0
  27. package/esm2022/lib/components/search-filter/search-filter.component.mjs +429 -0
  28. package/esm2022/lib/components/sort/sort.component.mjs +156 -0
  29. package/esm2022/lib/components/versions-list/tile/tile.component.mjs +60 -0
  30. package/esm2022/lib/components/versions-list/versions-list.component.mjs +94 -0
  31. package/esm2022/lib/container/drive/drive.component.mjs +116 -0
  32. package/esm2022/lib/drive.icons.mjs +16 -0
  33. package/esm2022/lib/drive.schema.mjs +49 -0
  34. package/esm2022/lib/lib.routes.mjs +17 -0
  35. package/esm2022/lib/pages/files/files.component.mjs +377 -0
  36. package/esm2022/lib/pages/object/object.component.mjs +200 -0
  37. package/esm2022/lib/services/drive/drive.interface.mjs +14 -0
  38. package/esm2022/lib/services/drive/drive.service.mjs +437 -0
  39. package/esm2022/lib/services/drive/resolve-name-conflicts/resolve-name-conflicts.component.mjs +158 -0
  40. package/esm2022/lib/services/drive/resolve-name-conflicts/resolve-name-conflicts.interface.mjs +2 -0
  41. package/esm2022/lib/services/drive/versions/versions.mapping.mjs +42 -0
  42. package/esm2022/lib/services/index.mjs +5 -0
  43. package/esm2022/lib/services/providers/drive.providers.mjs +10 -0
  44. package/esm2022/lib/services/resolver/files.resolver.mjs +12 -0
  45. package/esm2022/lib/services/resolver/index.mjs +3 -0
  46. package/esm2022/lib/services/resolver/versions.route.resolver.mjs +10 -0
  47. package/esm2022/lib/services/stored-query/stored-query.data.mjs +25 -0
  48. package/esm2022/lib/services/stored-query/stored-query.interface.mjs +2 -0
  49. package/esm2022/lib/services/stored-query/stored-query.service.mjs +41 -0
  50. package/esm2022/lib/services/tokens/breadcrumb-max-depth.token.mjs +3 -0
  51. package/esm2022/lib/services/tokens/index.mjs +2 -0
  52. package/esm2022/yuuvis-app-drive.mjs +5 -0
  53. package/extensions/README.md +3 -0
  54. package/extensions/index.d.ts +1 -0
  55. package/extensions/lib/extensions.module.d.ts +6 -0
  56. package/extensions/lib/extensions.service.d.ts +7 -0
  57. package/extensions/lib/object-config.defaults.d.ts +2 -0
  58. package/fesm2022/yuuvis-app-drive-extensions.mjs +99 -0
  59. package/fesm2022/yuuvis-app-drive-extensions.mjs.map +1 -0
  60. package/fesm2022/yuuvis-app-drive.mjs +2945 -0
  61. package/fesm2022/yuuvis-app-drive.mjs.map +1 -0
  62. package/index.d.ts +4 -0
  63. package/lib/actions/copy-link/copy-link.action.d.ts +18 -0
  64. package/lib/actions/index.d.ts +6 -0
  65. package/lib/actions/manage-versions/manage-versions.action.d.ts +17 -0
  66. package/lib/actions/manage-versions/manage-versions.component.d.ts +32 -0
  67. package/lib/actions/paste/paste.action.d.ts +17 -0
  68. package/lib/actions/rename/rename.action.d.ts +17 -0
  69. package/lib/actions/rename/rename.component.d.ts +12 -0
  70. package/lib/actions/rename/rename.validator.d.ts +5 -0
  71. package/lib/actions/updateContent/update.content.action.d.ts +18 -0
  72. package/lib/components/add-button/add-button-overlay/add-button-overlay.component.d.ts +26 -0
  73. package/lib/components/add-button/add-button.component.d.ts +12 -0
  74. package/lib/components/breadcrumb/breadcrumb.component.d.ts +25 -0
  75. package/lib/components/folder-tree/folder-tree.component.d.ts +13 -0
  76. package/lib/components/index.d.ts +8 -0
  77. package/lib/components/object-name/object-name.component.d.ts +21 -0
  78. package/lib/components/overlay/create-folder/create-folder.component.d.ts +12 -0
  79. package/lib/components/paste-from-clipboard/paste-from-clipboard.component.d.ts +13 -0
  80. package/lib/components/ribbon/ribbon.component.d.ts +24 -0
  81. package/lib/components/search-filter/date-range-picker/date-range-picker.component.d.ts +13 -0
  82. package/lib/components/search-filter/search-filter.component.d.ts +23 -0
  83. package/lib/components/sort/sort.component.d.ts +31 -0
  84. package/lib/components/versions-list/tile/tile.component.d.ts +14 -0
  85. package/lib/components/versions-list/versions-list.component.d.ts +17 -0
  86. package/lib/container/drive/drive.component.d.ts +36 -0
  87. package/lib/drive.icons.d.ts +15 -0
  88. package/lib/drive.schema.d.ts +23 -0
  89. package/lib/lib.routes.d.ts +2 -0
  90. package/lib/pages/files/files.component.d.ts +101 -0
  91. package/lib/pages/object/object.component.d.ts +35 -0
  92. package/lib/services/drive/drive.interface.d.ts +62 -0
  93. package/lib/services/drive/drive.service.d.ts +64 -0
  94. package/lib/services/drive/resolve-name-conflicts/resolve-name-conflicts.component.d.ts +31 -0
  95. package/lib/services/drive/resolve-name-conflicts/resolve-name-conflicts.interface.d.ts +8 -0
  96. package/lib/services/drive/versions/versions.mapping.d.ts +2 -0
  97. package/lib/services/index.d.ts +4 -0
  98. package/lib/services/providers/drive.providers.d.ts +7 -0
  99. package/lib/services/resolver/files.resolver.d.ts +2 -0
  100. package/lib/services/resolver/index.d.ts +2 -0
  101. package/lib/services/resolver/versions.route.resolver.d.ts +2 -0
  102. package/lib/services/stored-query/stored-query.data.d.ts +5 -0
  103. package/lib/services/stored-query/stored-query.interface.d.ts +5 -0
  104. package/lib/services/stored-query/stored-query.service.d.ts +10 -0
  105. package/lib/services/tokens/breadcrumb-max-depth.token.d.ts +2 -0
  106. package/lib/services/tokens/index.d.ts +1 -0
  107. 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