From 54536f3266c2c2d317918d125846703379b07cfd Mon Sep 17 00:00:00 2001 From: alexcibotari Date: Sat, 11 Jan 2025 15:48:29 +0100 Subject: [PATCH 01/10] Asset View --- .../spaces/assets/assets.component.html | 370 +++++++++++------- .../spaces/assets/assets.component.scss | 25 ++ .../spaces/assets/assets.component.ts | 24 +- .../edit-file-dialog.component.html | 1 + .../edit-file-dialog.model.ts | 4 +- .../edit-folder-dialog.model.ts | 4 +- src/app/shared/stores/local-settings.store.ts | 8 + src/assets/icons/audio_file.svg | 1 + src/assets/icons/description.svg | 1 + src/assets/icons/file_present.svg | 1 + src/assets/icons/folder.svg | 1 + src/assets/icons/font_download.svg | 1 + src/assets/icons/image.svg | 1 + src/assets/icons/video_file.svg | 1 + 14 files changed, 289 insertions(+), 154 deletions(-) create mode 100644 src/assets/icons/audio_file.svg create mode 100644 src/assets/icons/description.svg create mode 100644 src/assets/icons/file_present.svg create mode 100644 src/assets/icons/folder.svg create mode 100644 src/assets/icons/font_download.svg create mode 100644 src/assets/icons/image.svg create mode 100644 src/assets/icons/video_file.svg diff --git a/src/app/features/spaces/assets/assets.component.html b/src/app/features/spaces/assets/assets.component.html index b8819d24..22b6e293 100644 --- a/src/app/features/spaces/assets/assets.component.html +++ b/src/app/features/spaces/assets/assets.component.html @@ -5,6 +5,17 @@ help + + + view_list + + + grid_view + + @if ('ASSET_CREATE' | canUserPerform | async) { - @if ('ASSET_UPDATE' | canUserPerform | async) { - - } - @if ('ASSET_UPDATE' | canUserPerform | async) { - - } - @if ('ASSET_DELETE' | canUserPerform | async) { + } + + + + + Size + {{ element.size | digitalStore }} + + + Type + {{ element.type }} + + + Created At + + {{ element.createdAt?.toDate() | date: 'mediumDate' }} + + + + Updated At + + {{ element.updatedAt?.toDate() | date: 'mediumDate' }} + + + + Actions + - } - - + @if ('ASSET_UPDATE' | canUserPerform | async) { + + } + @if ('ASSET_UPDATE' | canUserPerform | async) { + + } + @if ('ASSET_DELETE' | canUserPerform | async) { + + } + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - @if (!isLoading()) { - -
-
-
- Drag and Drop a file here or use the "Upload Asset" button -
-
-
-
- } - + + + + @if (!isLoading()) { + +
+
+
+ Drag and Drop a file here or use the "Upload Asset" button +
+
+
+
+ } + + } @else { +
+ @for (item of dataSource.filteredData; track item.id) { + + @if (item.inProgress) { +
+ +
+ } @else if (item.kind === 'FILE' && filePreview(item.type)) { + thumbnail + } @else if (item.kind === 'FILE') { + File + } @else { + Folder + } + + {{ item.name }}{{ item.extension }} + + + @if (item.kind === 'FILE') { + @if (item.metadata; as metadata) { + @if (metadata.width && metadata.height) { + W{{ metadata.width }} x H{{ metadata.height }} + } + } + @if (item.size; as size) { +

{{ size | digitalStore }}

+ } + } +

+ {{ item.updatedAt?.toDate() | date: 'mediumDate' }} +

+
+ + + + @if ('ASSET_UPDATE' | canUserPerform | async) { + + } + @if ('ASSET_UPDATE' | canUserPerform | async) { + + } + @if ('ASSET_DELETE' | canUserPerform | async) { + + } + +
+ } +
+ } @if (fileUploadQueue.length > 0) {
diff --git a/src/app/features/spaces/assets/assets.component.scss b/src/app/features/spaces/assets/assets.component.scss index 81ceaac4..762fbc88 100644 --- a/src/app/features/spaces/assets/assets.component.scss +++ b/src/app/features/spaces/assets/assets.component.scss @@ -4,6 +4,31 @@ table { width: 100%; } +.digital-asset-card { + max-width: 240px; + min-width: 240px; + img { + min-width: 240px; + min-height: 240px; + max-width: 240px; + max-height: 240px; + border-top-left-radius: inherit; + border-top-right-radius: inherit; + border-bottom-width: var(--mdc-outlined-card-outline-width); + border-bottom-color: var(--mdc-outlined-card-outline-color, var(--mat-app-outline-variant)); + } + .progress { + min-width: 240px; + min-height: 240px; + max-width: 240px; + max-height: 240px; + align-content: center; + padding-left: 60px; + } + +} + + //mat-header-cell { // &.mat-column-actions { // text-align: center; diff --git a/src/app/features/spaces/assets/assets.component.ts b/src/app/features/spaces/assets/assets.component.ts index 751aac8f..e26b311a 100644 --- a/src/app/features/spaces/assets/assets.component.ts +++ b/src/app/features/spaces/assets/assets.component.ts @@ -11,7 +11,15 @@ import { ConfirmationDialogModel } from '@shared/components/confirmation-dialog/ import { ObjectUtils } from '@core/utils/object-utils.service'; import { SelectionModel } from '@angular/cdk/collections'; import { AssetService } from '@shared/services/asset.service'; -import { Asset, AssetFile, AssetFileUpdate, AssetFolderCreate, AssetFolderUpdate, AssetKind } from '@shared/models/asset.model'; +import { + Asset, + AssetFile, + AssetFileUpdate, + AssetFolder, + AssetFolderCreate, + AssetFolderUpdate, + AssetKind, +} from '@shared/models/asset.model'; import { AddFolderDialogModel } from './add-folder-dialog/add-folder-dialog.model'; import { AddFolderDialogComponent } from './add-folder-dialog/add-folder-dialog.component'; import { EditFolderDialogComponent } from './edit-folder-dialog/edit-folder-dialog.component'; @@ -26,6 +34,7 @@ import { EditFileDialogModel } from './edit-file-dialog/edit-file-dialog.model'; import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop'; import { PathItem, SpaceStore } from '@shared/stores/space.store'; import { MoveDialogComponent, MoveDialogModel, MoveDialogReturn } from './move-dialog'; +import { LocalSettingsStore } from '@shared/stores/local-settings.store'; @Component({ selector: 'll-assets', @@ -34,7 +43,7 @@ import { MoveDialogComponent, MoveDialogModel, MoveDialogReturn } from './move-d changeDetection: ChangeDetectionStrategy.OnPush, }) export class AssetsComponent implements OnInit { - sort = viewChild.required(MatSort); + sort = viewChild(MatSort); paginator = viewChild.required(MatPaginator); // Input @@ -63,6 +72,8 @@ export class AssetsComponent implements OnInit { // Loading isLoading = signal(true); + // Local Settings + settingsStore = inject(LocalSettingsStore); constructor( private readonly assetService: AssetService, @@ -81,7 +92,7 @@ export class AssetsComponent implements OnInit { next: assets => { this.assets = assets; this.dataSource = new MatTableDataSource(assets); - this.dataSource.sort = this.sort(); + this.dataSource.sort = this.sort() || null; this.dataSource.paginator = this.paginator(); this.isLoading.set(false); this.selection.clear(); @@ -160,7 +171,7 @@ export class AssetsComponent implements OnInit { panelClass: 'sm', data: { reservedNames: this.assets.map(it => it.name), - asset: ObjectUtils.clone(element), + asset: ObjectUtils.clone(element) as AssetFolder, }, }) .afterClosed() @@ -189,7 +200,7 @@ export class AssetsComponent implements OnInit { panelClass: 'sm', data: { reservedNames: this.assets.map(it => it.name), - asset: ObjectUtils.clone(element), + asset: ObjectUtils.clone(element) as AssetFile, }, }) .afterClosed() @@ -394,10 +405,11 @@ export class AssetsComponent implements OnInit { }); } - onDownload(event: Event, element: AssetFile): void { + onDownload(event: Event, element: Asset): void { // Prevent Default event.preventDefault(); event.stopImmediatePropagation(); + if (element.kind !== AssetKind.FILE) return; window.open(`/api/v1/spaces/${this.spaceId()}/assets/${element.id}?download`); } diff --git a/src/app/features/spaces/assets/edit-file-dialog/edit-file-dialog.component.html b/src/app/features/spaces/assets/edit-file-dialog/edit-file-dialog.component.html index 064b0dd5..f626a8e4 100644 --- a/src/app/features/spaces/assets/edit-file-dialog/edit-file-dialog.component.html +++ b/src/app/features/spaces/assets/edit-file-dialog/edit-file-dialog.component.html @@ -5,6 +5,7 @@

Edit File

Name + {{ data.asset.extension }} {{ form.controls['name'].value?.length || 0 }}/50 @if (form.controls['name'].errors; as errors) { {{ fe.errors(errors) }} diff --git a/src/app/features/spaces/assets/edit-file-dialog/edit-file-dialog.model.ts b/src/app/features/spaces/assets/edit-file-dialog/edit-file-dialog.model.ts index 51de90bc..cf1e6fa9 100644 --- a/src/app/features/spaces/assets/edit-file-dialog/edit-file-dialog.model.ts +++ b/src/app/features/spaces/assets/edit-file-dialog/edit-file-dialog.model.ts @@ -1,6 +1,6 @@ -import { Asset } from '@shared/models/asset.model'; +import { AssetFile } from '@shared/models/asset.model'; export interface EditFileDialogModel { - asset: Asset; + asset: AssetFile; reservedNames: string[]; } diff --git a/src/app/features/spaces/assets/edit-folder-dialog/edit-folder-dialog.model.ts b/src/app/features/spaces/assets/edit-folder-dialog/edit-folder-dialog.model.ts index eae0e88c..e04c351d 100644 --- a/src/app/features/spaces/assets/edit-folder-dialog/edit-folder-dialog.model.ts +++ b/src/app/features/spaces/assets/edit-folder-dialog/edit-folder-dialog.model.ts @@ -1,6 +1,6 @@ -import { Asset } from '@shared/models/asset.model'; +import { AssetFolder } from '@shared/models/asset.model'; export interface EditFolderDialogModel { - asset: Asset; + asset: AssetFolder; reservedNames: string[]; } diff --git a/src/app/shared/stores/local-settings.store.ts b/src/app/shared/stores/local-settings.store.ts index 15277fc9..331b2ccc 100644 --- a/src/app/shared/stores/local-settings.store.ts +++ b/src/app/shared/stores/local-settings.store.ts @@ -5,6 +5,7 @@ const LS_KEY = 'LL-SETTINGS-STATE'; export type Theme = 'light' | 'dark' | 'auto'; export type EditorSize = '' | 'sm' | 'md' | 'lg'; +export type DataLayout = 'list' | 'grid'; export interface LocalSettingsState { theme: Theme; @@ -12,6 +13,7 @@ export interface LocalSettingsState { debugEnabled: boolean; editorEnabled: boolean; editorSize: EditorSize; + assetLayout: DataLayout; } export const initialState: LocalSettingsState = { @@ -20,6 +22,7 @@ export const initialState: LocalSettingsState = { debugEnabled: false, editorEnabled: false, editorSize: '', + assetLayout: 'list', }; function setDocumentTheme(theme: Theme) { @@ -83,6 +86,10 @@ export const LocalSettingsStore = signalStore( patchState(store, { editorSize }); localStorage.setItem(LS_KEY, JSON.stringify({ ...getState(store), editorSize })); }, + setAssetLayout: (assetLayout: DataLayout): void => { + patchState(store, { assetLayout }); + localStorage.setItem(LS_KEY, JSON.stringify({ ...getState(store), assetLayout })); + }, }; }), withComputed(store => { @@ -92,6 +99,7 @@ export const LocalSettingsStore = signalStore( mainMenuExpended: computed(() => store.mainMenuExpended()), editorEnabled: computed(() => store.editorEnabled()), editorSize: computed(() => store.editorSize()), + assetLayout: computed(() => store.assetLayout()), }; }), withHooks({ diff --git a/src/assets/icons/audio_file.svg b/src/assets/icons/audio_file.svg new file mode 100644 index 00000000..ff122c7b --- /dev/null +++ b/src/assets/icons/audio_file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/description.svg b/src/assets/icons/description.svg new file mode 100644 index 00000000..43fc0edd --- /dev/null +++ b/src/assets/icons/description.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/file_present.svg b/src/assets/icons/file_present.svg new file mode 100644 index 00000000..6d062a12 --- /dev/null +++ b/src/assets/icons/file_present.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/folder.svg b/src/assets/icons/folder.svg new file mode 100644 index 00000000..021db149 --- /dev/null +++ b/src/assets/icons/folder.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/font_download.svg b/src/assets/icons/font_download.svg new file mode 100644 index 00000000..28d6867d --- /dev/null +++ b/src/assets/icons/font_download.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/image.svg b/src/assets/icons/image.svg new file mode 100644 index 00000000..4e503732 --- /dev/null +++ b/src/assets/icons/image.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/video_file.svg b/src/assets/icons/video_file.svg new file mode 100644 index 00000000..b439a9be --- /dev/null +++ b/src/assets/icons/video_file.svg @@ -0,0 +1 @@ + \ No newline at end of file From d25354334e0eee4229bcdb31368bc6a104364437 Mon Sep 17 00:00:00 2001 From: alexcibotari Date: Sat, 11 Jan 2025 20:49:09 +0100 Subject: [PATCH 02/10] fix Content import --- functions/src/models/content.zod.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/functions/src/models/content.zod.ts b/functions/src/models/content.zod.ts index 7769cacc..97246a5a 100644 --- a/functions/src/models/content.zod.ts +++ b/functions/src/models/content.zod.ts @@ -18,7 +18,7 @@ export const contentBaseSchema = z.object({ export const contentDocumentSchema = contentBaseSchema.extend({ kind: z.literal(ContentKind.DOCUMENT), schema: z.string(), - data: contentDataSchema.optional(), + data: z.string().optional().or(contentDataSchema.optional()), }); export const contentFolderSchema = contentBaseSchema.extend({ From be3f886b89f424760e60b40ad4af6633a69e546f Mon Sep 17 00:00:00 2001 From: alexcibotari Date: Sun, 12 Jan 2025 22:40:23 +0100 Subject: [PATCH 03/10] Asset View --- .../admin/spaces/spaces.component.html | 2 +- .../features/admin/users/users.component.html | 2 +- src/app/features/features.component.ts | 4 - .../spaces/assets/assets.component.html | 415 +++++++++--------- .../spaces/assets/assets.component.scss | 10 +- .../spaces/assets/assets.component.ts | 14 +- .../spaces/contents/contents.component.html | 2 +- .../spaces/schemas/schemas.component.html | 2 +- .../settings/locales/locales.component.html | 2 +- .../settings/tokens/tokens.component.html | 2 +- .../spaces/tasks/tasks.component.html | 2 +- src/styles.scss | 1 + src/styles/_background.scss | 9 +- src/styles/_mat-paginator.scss | 5 + 14 files changed, 238 insertions(+), 234 deletions(-) create mode 100644 src/styles/_mat-paginator.scss diff --git a/src/app/features/admin/spaces/spaces.component.html b/src/app/features/admin/spaces/spaces.component.html index 8f7f4d35..c7df14c2 100644 --- a/src/app/features/admin/spaces/spaces.component.html +++ b/src/app/features/admin/spaces/spaces.component.html @@ -58,5 +58,5 @@ - +
diff --git a/src/app/features/admin/users/users.component.html b/src/app/features/admin/users/users.component.html index 41d8c922..d54bd092 100644 --- a/src/app/features/admin/users/users.component.html +++ b/src/app/features/admin/users/users.component.html @@ -102,5 +102,5 @@ - + diff --git a/src/app/features/features.component.ts b/src/app/features/features.component.ts index b2e93bdf..b972867c 100644 --- a/src/app/features/features.component.ts +++ b/src/app/features/features.component.ts @@ -12,7 +12,6 @@ import { signal, Signal, } from '@angular/core'; -import { Observable } from 'rxjs'; import { LocalStorageService } from '@core/core.module'; import { Auth, signOut } from '@angular/fire/auth'; @@ -91,9 +90,6 @@ export class FeaturesComponent implements OnInit { { link: 'https://github.com/Lessify/localess/issues', label: 'Feedback', icon: 'forum' }, ]; - stickyHeader$: Observable | undefined; - language$: Observable | undefined; - private destroyRef = inject(DestroyRef); spaceStore = inject(SpaceStore); userStore = inject(UserStore); diff --git a/src/app/features/spaces/assets/assets.component.html b/src/app/features/spaces/assets/assets.component.html index 22b6e293..42ad47e0 100644 --- a/src/app/features/spaces/assets/assets.component.html +++ b/src/app/features/spaces/assets/assets.component.html @@ -9,10 +9,10 @@ hideSingleSelectionIndicator="true" (change)="settingsStore.setAssetLayout($event.value)" [value]="settingsStore.assetLayout()"> - + view_list - + grid_view @@ -62,232 +62,247 @@ } - - @if (settingsStore.assetLayout() === 'list') { - - - - - - - - - - - - - - Icon - - @switch (element.kind) { - @case ('FILE') { - {{ fileIcon(element.type) }} - } - @case ('FOLDER') { - folder - } - } - - - - Preview - - @if (element.kind === 'FILE' && filePreview(element.type)) { - @if (element.inProgress) { - - } @else { - thumbnail +
+ @if (settingsStore.assetLayout() === 'list') { + + + + + + + + + + + + + + Icon + + @switch (element.kind) { + @case ('FILE') { + {{ fileIcon(element.type) }} + } + @case ('FOLDER') { + folder + } } - } - - - - Name - -
-
{{ element.name }}{{ element.extension }}
- @if (element.metadata; as metadata) { - @if (metadata.width && metadata.height) { - W{{ metadata.width }} x H{{ metadata.height }} + + + + Preview + + @if (element.kind === 'FILE' && filePreview(element.type)) { + @if (element.inProgress) { + + } @else { + thumbnail } } -
-
-
- - Size - {{ element.size | digitalStore }} - - - Type - {{ element.type }} - - - Created At - - {{ element.createdAt?.toDate() | date: 'mediumDate' }} - - - - Updated At - - {{ element.updatedAt?.toDate() | date: 'mediumDate' }} - - - - Actions - - - @if ('ASSET_UPDATE' | canUserPerform | async) { - - } - @if ('ASSET_UPDATE' | canUserPerform | async) { - - } - @if ('ASSET_DELETE' | canUserPerform | async) { - - } - - - - - - - - - - - - - - - - - - - - - - - - - - @if (!isLoading()) { - -
-
-
- Drag and Drop a file here or use the "Upload Asset" button -
-
-
+
- } -
- } @else { -
- @for (item of dataSource.filteredData; track item.id) { - - @if (item.inProgress) { -
- -
- } @else if (item.kind === 'FILE' && filePreview(item.type)) { - thumbnail - } @else if (item.kind === 'FILE') { - File - } @else { - Folder - } - - {{ item.name }}{{ item.extension }} - - - @if (item.kind === 'FILE') { - @if (item.metadata; as metadata) { + + Name + +
+
{{ element.name }}{{ element.extension }}
+ @if (element.metadata; as metadata) { @if (metadata.width && metadata.height) { W{{ metadata.width }} x H{{ metadata.height }} } } - @if (item.size; as size) { -

{{ size | digitalStore }}

- } - } -

- {{ item.updatedAt?.toDate() | date: 'mediumDate' }} -

- - - +
+
+
+ + Size + {{ element.size | digitalStore }} + + + Type + {{ element.type }} + + + Created At + + {{ element.createdAt?.toDate() | date: 'mediumDate' }} + + + + Updated At + + {{ element.updatedAt?.toDate() | date: 'mediumDate' }} + + + + Actions + @if ('ASSET_UPDATE' | canUserPerform | async) { - } @if ('ASSET_UPDATE' | canUserPerform | async) { - } @if ('ASSET_DELETE' | canUserPerform | async) { } - -
- } -
- } - + + + + + + + + + + + + + + + + + + + + + + + + + + @if (!isLoading()) { + +
+
+
+ Drag and Drop a file here or use the "Upload Asset" button +
+
+
+
+
+ } + + } @else { +
+ @for (item of dataSource.connect() | async; track item.id) { + + @if (item.inProgress) { +
+ +
+ } @else if (item.kind === 'FILE' && filePreview(item.type)) { + thumbnail + } @else if (item.kind === 'FILE') { + File + } @else { + Folder + } + + {{ item.name }}{{ item.extension }} + + + @if (item.kind === 'FILE') { + @if (item.metadata; as metadata) { + @if (metadata.width && metadata.height) { + W{{ metadata.width }} x H{{ metadata.height }} + } + } + @if (item.size; as size) { +

{{ size | digitalStore }}

+ } + } +

+ {{ item.updatedAt?.toDate() | date: 'mediumDate' }} +

+
+ + + + @if ('ASSET_UPDATE' | canUserPerform | async) { + + } + @if ('ASSET_UPDATE' | canUserPerform | async) { + + } + @if ('ASSET_DELETE' | canUserPerform | async) { + + } + +
+ } @empty { +
+
+
+ Drag and Drop a file here or use the "Upload Asset" button +
+
+
+
+ } +
+ } +
+ @if (fileUploadQueue.length > 0) {
diff --git a/src/app/features/spaces/assets/assets.component.scss b/src/app/features/spaces/assets/assets.component.scss index 762fbc88..454ea071 100644 --- a/src/app/features/spaces/assets/assets.component.scss +++ b/src/app/features/spaces/assets/assets.component.scss @@ -40,11 +40,11 @@ table { // } //} -mat-row { - &.row-folder { - cursor: pointer; - } -} +//mat-row { +// &.row-folder { +// cursor: pointer; +// } +//} mat-cell { &.mat-column-preview { diff --git a/src/app/features/spaces/assets/assets.component.ts b/src/app/features/spaces/assets/assets.component.ts index e26b311a..683a53c4 100644 --- a/src/app/features/spaces/assets/assets.component.ts +++ b/src/app/features/spaces/assets/assets.component.ts @@ -305,19 +305,9 @@ export class AssetsComponent implements OnInit { this.selection.select(...this.dataSource.data); } - onRowSelect(element: Asset): void { - // if (element.kind === AssetKind.FILE) { - // element.publishedAt - // if (this.schemasMap.has(element.schema)) { - // this.router.navigate(['features', 'contents', element.id]); - // } else { - // this.notificationService.warn(`Content Schema can not be found.`); - // } - // return; - // } - - this.isLoading.set(true); + onAssetSelect(element: Asset): void { if (element.kind === AssetKind.FOLDER) { + this.isLoading.set(true); this.selection.clear(); const assetPath = ObjectUtils.clone(this.spaceStore.assetPath() || []); assetPath.push({ diff --git a/src/app/features/spaces/contents/contents.component.html b/src/app/features/spaces/contents/contents.component.html index 551815e2..bb509612 100644 --- a/src/app/features/spaces/contents/contents.component.html +++ b/src/app/features/spaces/contents/contents.component.html @@ -201,5 +201,5 @@ - +
diff --git a/src/app/features/spaces/schemas/schemas.component.html b/src/app/features/spaces/schemas/schemas.component.html index 56f72dc2..ea7877f1 100644 --- a/src/app/features/spaces/schemas/schemas.component.html +++ b/src/app/features/spaces/schemas/schemas.component.html @@ -106,5 +106,5 @@
- + diff --git a/src/app/features/spaces/settings/locales/locales.component.html b/src/app/features/spaces/settings/locales/locales.component.html index a9d181fd..a74ca4f3 100644 --- a/src/app/features/spaces/settings/locales/locales.component.html +++ b/src/app/features/spaces/settings/locales/locales.component.html @@ -56,5 +56,5 @@ - + diff --git a/src/app/features/spaces/settings/tokens/tokens.component.html b/src/app/features/spaces/settings/tokens/tokens.component.html index 59bacb1c..9e64f7ec 100644 --- a/src/app/features/spaces/settings/tokens/tokens.component.html +++ b/src/app/features/spaces/settings/tokens/tokens.component.html @@ -45,5 +45,5 @@ - + diff --git a/src/app/features/spaces/tasks/tasks.component.html b/src/app/features/spaces/tasks/tasks.component.html index 34f7446d..04d85900 100644 --- a/src/app/features/spaces/tasks/tasks.component.html +++ b/src/app/features/spaces/tasks/tasks.component.html @@ -133,5 +133,5 @@ - + diff --git a/src/styles.scss b/src/styles.scss index 840f5df6..afd9d8aa 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -20,6 +20,7 @@ markdown { @import 'styles/mat-grid-list'; @import 'styles/mat-list'; @import 'styles/mat-menu'; +@import 'styles/mat-paginator'; @import 'styles/mat-snack-bar'; @import 'styles/mat-table'; @import 'styles/mat-toolbar'; diff --git a/src/styles/_background.scss b/src/styles/_background.scss index cc9260a0..c240e143 100644 --- a/src/styles/_background.scss +++ b/src/styles/_background.scss @@ -3,12 +3,9 @@ @import './styles-variables'; .file-drag-and-drop-wrapper { - background-color: $background-blue-color !important; - border-style: solid !important; - border-color: $border-blue-color !important; - border-width: 3px !important; - border-radius: 5px; - opacity: 0.25; + background-color: var(--sys-secondary-container) !important; + outline: var(--sys-secondary) solid 3px !important; + opacity: 0.5; } diff --git a/src/styles/_mat-paginator.scss b/src/styles/_mat-paginator.scss new file mode 100644 index 00000000..b9e9be77 --- /dev/null +++ b/src/styles/_mat-paginator.scss @@ -0,0 +1,5 @@ +mat-paginator { + &.mat-paginator-sticky { + @apply sticky bottom-0 z-10; + } +} From 02b17e33f82da5d75c33e93db678cafe02742908 Mon Sep 17 00:00:00 2001 From: alexcibotari Date: Mon, 13 Jan 2025 20:27:29 +0100 Subject: [PATCH 04/10] Add Thumbnail image generator --- functions/src/services/open-api.service.ts | 10 ++++++++ functions/src/v1.ts | 24 +++++++++++++------ src/app/app.module.ts | 4 +++- .../spaces/assets/assets.component.html | 24 +++++++++---------- .../spaces/assets/assets.component.ts | 19 ++++++++++++++- .../features/spaces/assets/assets.module.ts | 2 ++ .../image-preview-dialog.component.html | 13 ++++++++++ .../image-preview-dialog.component.scss | 0 .../image-preview-dialog.component.ts | 13 ++++++++++ .../image-preview-dialog.model.ts | 6 +++++ .../asset-select/asset-select.component.html | 1 + .../assets-select.component.html | 1 + .../assets-select-dialog.component.html | 5 ++-- src/styles/_mat-dialog.scss | 24 ++++++++++++++++--- 14 files changed, 119 insertions(+), 27 deletions(-) create mode 100644 src/app/features/spaces/assets/image-preview-dialog/image-preview-dialog.component.html create mode 100644 src/app/features/spaces/assets/image-preview-dialog/image-preview-dialog.component.scss create mode 100644 src/app/features/spaces/assets/image-preview-dialog/image-preview-dialog.component.ts create mode 100644 src/app/features/spaces/assets/image-preview-dialog/image-preview-dialog.model.ts diff --git a/functions/src/services/open-api.service.ts b/functions/src/services/open-api.service.ts index 401edb42..958a5807 100644 --- a/functions/src/services/open-api.service.ts +++ b/functions/src/services/open-api.service.ts @@ -692,6 +692,16 @@ export function generateOpenApi(schemasById: Map): OpenAPIObject example: false, }, }, + { + name: 'thumbnail', + in: 'query', + description: 'In case you have animated image like WebP/Gif, and you wish to generate non animated thumbnail.', + required: false, + schema: { + type: 'boolean', + example: false, + }, + }, ], responses: { '200': { diff --git a/functions/src/v1.ts b/functions/src/v1.ts index b2a9f629..3f6e040e 100644 --- a/functions/src/v1.ts +++ b/functions/src/v1.ts @@ -347,7 +347,7 @@ expressApp.get('/api/v1/spaces/:spaceId/assets/:assetId', async (req, res) => { logger.info('v1 spaces asset params: ' + JSON.stringify(req.params)); logger.info('v1 spaces asset query: ' + JSON.stringify(req.query)); const { spaceId, assetId } = req.params; - const { w: width, download } = req.query; + const { w: width, download, thumbnail } = req.query; const assetFile = bucket.file(`spaces/${spaceId}/assets/${assetId}/original`); const [exists] = await assetFile.exists(); @@ -362,15 +362,25 @@ expressApp.get('/api/v1/spaces/:spaceId/assets/:assetId', async (req, res) => { if (asset.type === 'image/webp' || asset.type === 'image/gif') { // possible animated or single frame webp/gif const [file] = await assetFile.download(); - const sharpFile = sharp(file); + let sharpFile = sharp(file); const sharpFileMetadata = await sharpFile.metadata(); - if (sharpFileMetadata.pages) { - // animated webp/gif - await assetFile.download({ destination: tempFilePath }); - } else { + const isAnimated = sharpFileMetadata.pages !== undefined; + if (thumbnail && isAnimated) { + // Thumbnail with Animation: Remove animations, to reduce load + filename = `${asset.name}-w${width}-thumbnail${asset.extension}`; + sharpFile = sharp(file, { page: 0, pages: 1 }); + await sharpFile.resize(parseInt(width.toString(), 10)).toFile(tempFilePath); + } else if (thumbnail && !isAnimated) { + // thumbnail without Animation + filename = `${asset.name}-w${width}-thumbnail${asset.extension}`; // single frame webp/gif - filename = `${asset.name}-w${width}${asset.extension}`; await sharpFile.resize(parseInt(width.toString(), 10)).toFile(tempFilePath); + } else { + // Animated + filename = `${asset.name}-w${width}${asset.extension}`; + // animated webp/gif + // TODO no way now to resize animated files + await assetFile.download({ destination: tempFilePath }); } } else if (asset.type === 'image/svg+xml') { // svg, cannot resize diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 25f22f90..4d4ade5f 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -95,9 +95,11 @@ import { provideRemoteConfig, getRemoteConfig } from '@angular/fire/remote-confi { provide: IMAGE_LOADER, useValue: (config: ImageLoaderConfig) => { + console.log('IMAGE_LOADER', config); // optimize image for API assets if (config.src.startsWith('/api/') && config.width) { - return `${config.src}?w=${config.width}`; + const thumbnailParam = config.loaderParams && config.loaderParams['thumbnail'] ? '&thumbnail=true' : ''; + return `${config.src}?w=${config.width}${thumbnailParam}`; } else { return config.src; } diff --git a/src/app/features/spaces/assets/assets.component.html b/src/app/features/spaces/assets/assets.component.html index 42ad47e0..7274196b 100644 --- a/src/app/features/spaces/assets/assets.component.html +++ b/src/app/features/spaces/assets/assets.component.html @@ -104,10 +104,11 @@ } @else { thumbnail } } @@ -122,6 +123,9 @@ @if (metadata.width && metadata.height) { W{{ metadata.width }} x H{{ metadata.height }} } + @if (metadata.animated) { +

animated_images

+ } } @@ -199,10 +203,7 @@ - + @if (!isLoading()) {
@@ -219,11 +220,7 @@ } @else {
@for (item of dataSource.connect() | async; track item.id) { - + @if (item.inProgress) {
@@ -231,10 +228,11 @@ } @else if (item.kind === 'FILE' && filePreview(item.type)) { thumbnail } @else if (item.kind === 'FILE') { File diff --git a/src/app/features/spaces/assets/assets.component.ts b/src/app/features/spaces/assets/assets.component.ts index 683a53c4..aaf5e93b 100644 --- a/src/app/features/spaces/assets/assets.component.ts +++ b/src/app/features/spaces/assets/assets.component.ts @@ -35,6 +35,8 @@ import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop'; import { PathItem, SpaceStore } from '@shared/stores/space.store'; import { MoveDialogComponent, MoveDialogModel, MoveDialogReturn } from './move-dialog'; import { LocalSettingsStore } from '@shared/stores/local-settings.store'; +import { ImagePreviewDialogComponent } from './image-preview-dialog/image-preview-dialog.component'; +import { ImagePreviewDialogModel } from './image-preview-dialog/image-preview-dialog.model'; @Component({ selector: 'll-assets', @@ -306,7 +308,22 @@ export class AssetsComponent implements OnInit { } onAssetSelect(element: Asset): void { - if (element.kind === AssetKind.FOLDER) { + if (element.kind === AssetKind.FILE) { + this.dialog + .open(ImagePreviewDialogComponent, { + panelClass: 'image-preview', + data: { + spaceId: this.spaceId(), + asset: element, + }, + }) + .afterClosed() + .subscribe({ + next: () => { + console.log('close'); + }, + }); + } else if (element.kind === AssetKind.FOLDER) { this.isLoading.set(true); this.selection.clear(); const assetPath = ObjectUtils.clone(this.spaceStore.assetPath() || []); diff --git a/src/app/features/spaces/assets/assets.module.ts b/src/app/features/spaces/assets/assets.module.ts index a09979c1..cf78234f 100644 --- a/src/app/features/spaces/assets/assets.module.ts +++ b/src/app/features/spaces/assets/assets.module.ts @@ -12,6 +12,7 @@ import { ImportDialogComponent } from './import-dialog/import-dialog.component'; import { TaskService } from '@shared/services/task.service'; import { EditFileDialogComponent } from './edit-file-dialog/edit-file-dialog.component'; import { MoveDialogComponent } from './move-dialog'; +import { ImagePreviewDialogComponent } from './image-preview-dialog/image-preview-dialog.component'; @NgModule({ declarations: [ @@ -22,6 +23,7 @@ import { MoveDialogComponent } from './move-dialog'; ExportDialogComponent, ImportDialogComponent, MoveDialogComponent, + ImagePreviewDialogComponent, ], imports: [SharedModule, AssetsRoutingModule], providers: [SpaceService, AssetService, TaskService], diff --git a/src/app/features/spaces/assets/image-preview-dialog/image-preview-dialog.component.html b/src/app/features/spaces/assets/image-preview-dialog/image-preview-dialog.component.html new file mode 100644 index 00000000..b56296d9 --- /dev/null +++ b/src/app/features/spaces/assets/image-preview-dialog/image-preview-dialog.component.html @@ -0,0 +1,13 @@ + + thumbnail + + + + diff --git a/src/app/features/spaces/assets/image-preview-dialog/image-preview-dialog.component.scss b/src/app/features/spaces/assets/image-preview-dialog/image-preview-dialog.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/features/spaces/assets/image-preview-dialog/image-preview-dialog.component.ts b/src/app/features/spaces/assets/image-preview-dialog/image-preview-dialog.component.ts new file mode 100644 index 00000000..8de257d5 --- /dev/null +++ b/src/app/features/spaces/assets/image-preview-dialog/image-preview-dialog.component.ts @@ -0,0 +1,13 @@ +import { ChangeDetectionStrategy, Component, Inject } from '@angular/core'; +import { MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { ImagePreviewDialogModel } from './image-preview-dialog.model'; + +@Component({ + selector: 'll-asset-image-preview-dialog', + templateUrl: './image-preview-dialog.component.html', + styleUrls: ['./image-preview-dialog.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ImagePreviewDialogComponent { + constructor(@Inject(MAT_DIALOG_DATA) public data: ImagePreviewDialogModel) {} +} diff --git a/src/app/features/spaces/assets/image-preview-dialog/image-preview-dialog.model.ts b/src/app/features/spaces/assets/image-preview-dialog/image-preview-dialog.model.ts new file mode 100644 index 00000000..7e58c746 --- /dev/null +++ b/src/app/features/spaces/assets/image-preview-dialog/image-preview-dialog.model.ts @@ -0,0 +1,6 @@ +import { AssetFile } from '@shared/models/asset.model'; + +export interface ImagePreviewDialogModel { + spaceId: string; + asset: AssetFile; +} diff --git a/src/app/features/spaces/contents/shared/asset-select/asset-select.component.html b/src/app/features/spaces/contents/shared/asset-select/asset-select.component.html index eff1b6a4..34f476d8 100644 --- a/src/app/features/spaces/contents/shared/asset-select/asset-select.component.html +++ b/src/app/features/spaces/contents/shared/asset-select/asset-select.component.html @@ -30,6 +30,7 @@ height="200" alt="thumbnail" loading="lazy" + [loaderParams]="{ thumbnail: true }" ngSrc="/api/v1/spaces/{{ space().id }}/assets/{{ asset.id }}" /> } @else { file_present diff --git a/src/app/features/spaces/contents/shared/assets-select/assets-select.component.html b/src/app/features/spaces/contents/shared/assets-select/assets-select.component.html index 11c4311a..4e8ead82 100644 --- a/src/app/features/spaces/contents/shared/assets-select/assets-select.component.html +++ b/src/app/features/spaces/contents/shared/assets-select/assets-select.component.html @@ -29,6 +29,7 @@ height="200" alt="thumbnail" loading="lazy" + [loaderParams]="{ thumbnail: true }" ngSrc="/api/v1/spaces/{{ space().id }}/assets/{{ asset.id }}" /> } @else { file_present diff --git a/src/app/shared/components/assets-select-dialog/assets-select-dialog.component.html b/src/app/shared/components/assets-select-dialog/assets-select-dialog.component.html index 1919e9b3..0de7300b 100644 --- a/src/app/shared/components/assets-select-dialog/assets-select-dialog.component.html +++ b/src/app/shared/components/assets-select-dialog/assets-select-dialog.component.html @@ -41,10 +41,11 @@

Assets

@if (element.kind === 'FILE' && filePreview(element.type)) { thumbnail } diff --git a/src/styles/_mat-dialog.scss b/src/styles/_mat-dialog.scss index f8b850fd..48f6dd64 100644 --- a/src/styles/_mat-dialog.scss +++ b/src/styles/_mat-dialog.scss @@ -1,6 +1,11 @@ -@use '@angular/material' as mat; - -@import './styles-variables'; +/* +None width: 100%; +sm (640px) max-width: 640px; +md (768px) max-width: 768px; +lg (1024px) max-width: 1024px; +xl (1280px) max-width: 1280px; +2xl (1536px) max-width: 1536px; +*/ .cdk-overlay-pane.mat-mdc-dialog-panel { &.sm { @@ -18,4 +23,17 @@ &.full-screen { } + &.image-preview { + min-width: 950px; + max-width: 1000px; + + mat-dialog-content { + min-height: fit-content; + min-width: fit-content; + img { + width: 100%; + height: 100%; + } + } + } } From 04530cf5598d78165dc0c13e84c2a5df66244b32 Mon Sep 17 00:00:00 2001 From: alexcibotari Date: Tue, 14 Jan 2025 19:27:58 +0100 Subject: [PATCH 05/10] Add Grid Layout to Asset Selector Dialog --- .../spaces/assets/assets.component.scss | 26 -- .../asset-select/asset-select.component.ts | 2 +- .../assets-select/assets-select.component.ts | 2 +- .../assets-select-dialog.component.html | 225 ++++++++++++------ .../assets-select-dialog.component.scss | 13 +- .../assets-select-dialog.component.ts | 79 ++++-- src/app/shared/stores/local-settings.store.ts | 7 + src/styles/_mat-card.scss | 22 ++ src/styles/_mat-dialog.scss | 20 +- 9 files changed, 269 insertions(+), 127 deletions(-) diff --git a/src/app/features/spaces/assets/assets.component.scss b/src/app/features/spaces/assets/assets.component.scss index 454ea071..f0e9cc82 100644 --- a/src/app/features/spaces/assets/assets.component.scss +++ b/src/app/features/spaces/assets/assets.component.scss @@ -1,33 +1,7 @@ -@use '@angular/material' as mat; - table { width: 100%; } -.digital-asset-card { - max-width: 240px; - min-width: 240px; - img { - min-width: 240px; - min-height: 240px; - max-width: 240px; - max-height: 240px; - border-top-left-radius: inherit; - border-top-right-radius: inherit; - border-bottom-width: var(--mdc-outlined-card-outline-width); - border-bottom-color: var(--mdc-outlined-card-outline-color, var(--mat-app-outline-variant)); - } - .progress { - min-width: 240px; - min-height: 240px; - max-width: 240px; - max-height: 240px; - align-content: center; - padding-left: 60px; - } - -} - //mat-header-cell { // &.mat-column-actions { diff --git a/src/app/features/spaces/contents/shared/asset-select/asset-select.component.ts b/src/app/features/spaces/contents/shared/asset-select/asset-select.component.ts index 0b3bb6eb..9d56242c 100644 --- a/src/app/features/spaces/contents/shared/asset-select/asset-select.component.ts +++ b/src/app/features/spaces/contents/shared/asset-select/asset-select.component.ts @@ -55,7 +55,7 @@ export class AssetSelectComponent implements OnInit { openAssetSelectDialog(): void { this.dialog .open(AssetsSelectDialogComponent, { - panelClass: 'xl', + panelClass: 'full-screen', data: { spaceId: this.space().id, multiple: false, diff --git a/src/app/features/spaces/contents/shared/assets-select/assets-select.component.ts b/src/app/features/spaces/contents/shared/assets-select/assets-select.component.ts index 9ca9f029..be2b5731 100644 --- a/src/app/features/spaces/contents/shared/assets-select/assets-select.component.ts +++ b/src/app/features/spaces/contents/shared/assets-select/assets-select.component.ts @@ -64,7 +64,7 @@ export class AssetsSelectComponent implements OnInit { openAssetSelectDialog(): void { this.dialog .open(AssetsSelectDialogComponent, { - panelClass: 'xl', + panelClass: 'full-screen', data: { spaceId: this.space().id, multiple: true, diff --git a/src/app/shared/components/assets-select-dialog/assets-select-dialog.component.html b/src/app/shared/components/assets-select-dialog/assets-select-dialog.component.html index 0de7300b..ab55d6fa 100644 --- a/src/app/shared/components/assets-select-dialog/assets-select-dialog.component.html +++ b/src/app/shared/components/assets-select-dialog/assets-select-dialog.component.html @@ -1,4 +1,32 @@ -

Assets

+

+ Assets +
+ + + view_list + + + grid_view + + + @if ('ASSET_CREATE' | canUserPerform | async) { + + + } +
+

+@if (isLoading()) { + +} +@if (isLoading()) { + +}   @for (pathItem of assetPath; track pathItem.fullSlug; let isFirst = $first) { @@ -8,81 +36,134 @@

Assets

}
- - - - # - - @if (row.kind === 'FILE') { - - - } - - - - Icon - - @switch (element.kind) { - @case ('FILE') { - {{ fileIcon(element.type) }} + @if (settingsStore.assetDialogLayout() === 'list') { + + + + # + + @if (row.kind === 'FILE') { + + } - @case ('FOLDER') { - folder + + + + Icon + + @switch (element.kind) { + @case ('FILE') { + {{ fileIcon(element.type) }} + } + @case ('FOLDER') { + folder + } } - } - - - - Preview - - @if (element.kind === 'FILE' && filePreview(element.type)) { - thumbnail - } - - - - Name - -
-
{{ element.name }}{{ element.extension }}
- @if (element.metadata; as metadata) { - - @if (metadata.width && metadata.height) { - W{{ metadata.width }} x H{{ metadata.height }} - } - + + + + Preview + + @if (element.kind === 'FILE' && filePreview(element.type)) { + thumbnail } -
-
-
- - Size - {{ element.size | digitalStore }} - - - Type - {{ element.type }} - - - Updated At - - {{ element.updatedAt?.toDate() | date: 'mediumDate' }} - - +
+
+ + Name + +
+
{{ element.name }}{{ element.extension }}
+ @if (element.metadata; as metadata) { + + @if (metadata.width && metadata.height) { + W{{ metadata.width }} x H{{ metadata.height }} + } + + } +
+
+
+ + Size + {{ element.size | digitalStore }} + + + Type + {{ element.type }} + + + Updated At + + {{ element.updatedAt?.toDate() | date: 'mediumDate' }} + + - - -
+ + + + } @else { +
+ @for (item of dataSource.connect() | async; track item.id) { + + @if (item.inProgress) { +
+ +
+ } @else if (item.kind === 'FILE' && filePreview(item.type)) { + thumbnail + } @else if (item.kind === 'FILE') { + File + } @else { + Folder + } + + {{ item.name }}{{ item.extension }} + + + @if (item.kind === 'FILE') { + @if (item.metadata; as metadata) { + @if (metadata.width && metadata.height) { + W{{ metadata.width }} x H{{ metadata.height }} + } + } + @if (item.size; as size) { +

{{ size | digitalStore }}

+ } + } +

+ {{ item.updatedAt?.toDate() | date: 'mediumDate' }} +

+
+ + + + + +
+ } +
+ }
diff --git a/src/app/shared/components/assets-select-dialog/assets-select-dialog.component.scss b/src/app/shared/components/assets-select-dialog/assets-select-dialog.component.scss index 8bd9099a..4fa27a00 100644 --- a/src/app/shared/components/assets-select-dialog/assets-select-dialog.component.scss +++ b/src/app/shared/components/assets-select-dialog/assets-select-dialog.component.scss @@ -2,14 +2,25 @@ table { width: 100%; } +.header-actions { + float: right; + margin-top: 6px; + .mat-mdc-button-base { + margin-left: 8px; + margin-right: 8px; + margin-top: 2px; + } +} + mat-dialog-content { @apply pt-0 #{!important}; } mat-cell { - cursor: pointer; &.mat-column-preview { img { + min-width: 115px; + min-height: 115px; max-width: 115px; max-height: 115px; } diff --git a/src/app/shared/components/assets-select-dialog/assets-select-dialog.component.ts b/src/app/shared/components/assets-select-dialog/assets-select-dialog.component.ts index 004a4437..76aad97d 100644 --- a/src/app/shared/components/assets-select-dialog/assets-select-dialog.component.ts +++ b/src/app/shared/components/assets-select-dialog/assets-select-dialog.component.ts @@ -5,8 +5,8 @@ import { DestroyRef, inject, Inject, - OnDestroy, - OnInit, + OnDestroy, OnInit, + signal, viewChild, } from '@angular/core'; import { MAT_DIALOG_DATA } from '@angular/material/dialog'; @@ -15,14 +15,16 @@ import { FormErrorHandlerService } from '@core/error-handler/form-error-handler. import { ObjectUtils } from '@core/utils/object-utils.service'; import { SelectionModel } from '@angular/cdk/collections'; import { Asset, AssetKind } from '@shared/models/asset.model'; -import { switchMap } from 'rxjs/operators'; -import { BehaviorSubject } from 'rxjs'; +import { concatMap, switchMap, tap } from 'rxjs/operators'; +import { BehaviorSubject, Subject } from 'rxjs'; import { MatTableDataSource } from '@angular/material/table'; import { AssetService } from '@shared/services/asset.service'; import { MatSort } from '@angular/material/sort'; import { MatPaginator } from '@angular/material/paginator'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { PathItem } from '@shared/stores/space.store'; +import { LocalSettingsStore } from '@shared/stores/local-settings.store'; +import { NotificationService } from '@shared/services/notification.service'; @Component({ selector: 'll-assets-select-dialog', @@ -30,8 +32,8 @@ import { PathItem } from '@shared/stores/space.store'; styleUrls: ['./assets-select-dialog.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class AssetsSelectDialogComponent implements OnInit, OnDestroy { - sort = viewChild.required(MatSort); +export class AssetsSelectDialogComponent implements OnInit { + sort = viewChild(MatSort); paginator = viewChild.required(MatPaginator); assets: Asset[] = []; @@ -40,6 +42,8 @@ export class AssetsSelectDialogComponent implements OnInit, OnDestroy { selection = new SelectionModel(this.data.multiple, []); assetPath: PathItem[] = []; + fileUploadQueue = signal([]); + get parentPath(): string { if (this.assetPath && this.assetPath.length > 0) { return this.assetPath[this.assetPath.length - 1].fullSlug; @@ -55,21 +59,22 @@ export class AssetsSelectDialogComponent implements OnInit, OnDestroy { }, ]); + // Subscriptions + private fileUploadQueue$ = new Subject(); private destroyRef = inject(DestroyRef); + // Loading + isLoading = signal(true); + // Local Settings + settingsStore = inject(LocalSettingsStore); constructor( private readonly assetService: AssetService, + private readonly notificationService: NotificationService, readonly fe: FormErrorHandlerService, private readonly cd: ChangeDetectorRef, @Inject(MAT_DIALOG_DATA) public data: AssetsSelectDialogModel, - ) {} - - ngOnInit(): void { - this.loadData(); - } - - loadData(): void { + ) { this.path$ .asObservable() .pipe( @@ -82,29 +87,49 @@ export class AssetsSelectDialogComponent implements OnInit, OnDestroy { .subscribe({ next: assets => { this.assets = assets; - this.dataSource = new MatTableDataSource(assets); - this.dataSource.sort = this.sort(); + this.dataSource.sort = this.sort() || null; this.dataSource.paginator = this.paginator(); + this.isLoading.set(false); this.cd.markForCheck(); }, }); } + ngOnInit(): void { + this.fileUploadQueue$ + .pipe( + tap(console.log), + concatMap(it => this.assetService.createFile(this.data.spaceId, this.parentPath, it)), + takeUntilDestroyed(this.destroyRef), + ) + .subscribe({ + next: () => { + this.fileUploadQueue.update(files => { + files.shift(); + return files; + }); + }, + error: () => { + this.notificationService.error(`Asset can not be uploaded.`); + }, + }); + } + navigateToSlug(pathItem: PathItem) { + this.isLoading.set(true); const assetPath = ObjectUtils.clone(this.assetPath); const idx = assetPath.findIndex(it => it.fullSlug == pathItem.fullSlug); assetPath.splice(idx + 1); this.path$.next(assetPath); } - onRowSelect(element: Asset): void { + onAssetSelect(element: Asset): void { if (element.kind === AssetKind.FILE) { this.selection.toggle(element); return; - } - - if (element.kind === AssetKind.FOLDER) { + } else if (element.kind === AssetKind.FOLDER) { + this.isLoading.set(true); const assetPath = ObjectUtils.clone(this.assetPath); assetPath.push({ name: element.name, @@ -126,7 +151,19 @@ export class AssetsSelectDialogComponent implements OnInit, OnDestroy { return type.startsWith('image/'); } - ngOnDestroy(): void { - this.path$.complete(); + onFileUpload(event: Event): void { + if (event.target && event.target instanceof HTMLInputElement) { + const target = event.target as HTMLInputElement; + if (target.files && target.files.length > 0) { + for (let idx = 0; idx < target.files.length; idx++) { + const file = target.files[idx]; + this.fileUploadQueue.update(files => { + files.push(file); + return files; + }); + this.fileUploadQueue$.next(file); + } + } + } } } diff --git a/src/app/shared/stores/local-settings.store.ts b/src/app/shared/stores/local-settings.store.ts index 331b2ccc..b5aa661d 100644 --- a/src/app/shared/stores/local-settings.store.ts +++ b/src/app/shared/stores/local-settings.store.ts @@ -14,6 +14,7 @@ export interface LocalSettingsState { editorEnabled: boolean; editorSize: EditorSize; assetLayout: DataLayout; + assetDialogLayout: DataLayout; } export const initialState: LocalSettingsState = { @@ -23,6 +24,7 @@ export const initialState: LocalSettingsState = { editorEnabled: false, editorSize: '', assetLayout: 'list', + assetDialogLayout: 'list', }; function setDocumentTheme(theme: Theme) { @@ -90,6 +92,10 @@ export const LocalSettingsStore = signalStore( patchState(store, { assetLayout }); localStorage.setItem(LS_KEY, JSON.stringify({ ...getState(store), assetLayout })); }, + setAssetDialogLayout: (assetDialogLayout: DataLayout): void => { + patchState(store, { assetDialogLayout }); + localStorage.setItem(LS_KEY, JSON.stringify({ ...getState(store), assetDialogLayout })); + }, }; }), withComputed(store => { @@ -100,6 +106,7 @@ export const LocalSettingsStore = signalStore( editorEnabled: computed(() => store.editorEnabled()), editorSize: computed(() => store.editorSize()), assetLayout: computed(() => store.assetLayout()), + assetDialogLayout: computed(() => store.assetDialogLayout()), }; }), withHooks({ diff --git a/src/styles/_mat-card.scss b/src/styles/_mat-card.scss index b2faf059..0226cef5 100644 --- a/src/styles/_mat-card.scss +++ b/src/styles/_mat-card.scss @@ -10,4 +10,26 @@ mat-card { &.invalid { border: solid 2px var(--sys-error); } + &.digital-asset-card { + max-width: 240px; + min-width: 240px; + img { + min-width: 240px; + min-height: 240px; + max-width: 240px; + max-height: 240px; + border-top-left-radius: inherit; + border-top-right-radius: inherit; + border-bottom-width: var(--mdc-outlined-card-outline-width); + border-bottom-color: var(--mdc-outlined-card-outline-color, var(--mat-app-outline-variant)); + } + .progress { + min-width: 240px; + min-height: 240px; + max-width: 240px; + max-height: 240px; + align-content: center; + padding-left: 60px; + } + } } diff --git a/src/styles/_mat-dialog.scss b/src/styles/_mat-dialog.scss index 48f6dd64..4854bc1d 100644 --- a/src/styles/_mat-dialog.scss +++ b/src/styles/_mat-dialog.scss @@ -20,19 +20,29 @@ xl (1280px) max-width: 1280px; max-width: 1280px; max-height: calc(100vh - 80px); } + &.xxl { + min-width: 900px; + width: calc(100vw - 160px); + max-width: 1536px; + max-height: calc(100vh - 80px); + } &.full-screen { - + min-width: calc(100vw - 24px); + max-width: calc(100vw - 24px); + max-height: calc(100vh - 24px); } &.image-preview { - min-width: 950px; - max-width: 1000px; + max-width: calc(100vw - 80px); + max-height: calc(100vh - 80px); mat-dialog-content { min-height: fit-content; min-width: fit-content; img { - width: 100%; - height: 100%; + min-width: 800px; + min-height: 800px; + max-width: calc(100vw - 180px); + max-height: calc(100vh - 180px); } } } From 7be850c69307c1a02c7838f2f07c4bdc836016fc Mon Sep 17 00:00:00 2001 From: alexcibotari Date: Wed, 15 Jan 2025 20:17:38 +0100 Subject: [PATCH 06/10] Add File Upload From Asset Selector Dialog --- .../admin/settings/ui/ui.component.html | 10 +- .../admin/spaces/spaces.component.html | 10 +- .../features/admin/users/users.component.html | 18 +-- .../spaces/assets/assets.component.html | 119 ++++++++++-------- .../spaces/assets/assets.component.ts | 19 ++- .../spaces/contents/contents.component.html | 75 +++++------ .../spaces/contents/contents.component.ts | 2 +- .../spaces/dashboard/dashboard.component.html | 12 +- .../spaces/schemas/schemas.component.html | 52 ++++---- .../settings/general/general.component.html | 10 +- .../settings/locales/locales.component.html | 10 +- .../settings/tokens/tokens.component.html | 10 +- .../visual-editor.component.html | 20 +-- .../translations/translations.component.html | 84 +++++++------ .../assets-select-dialog.component.html | 37 ++++-- .../assets-select-dialog.component.scss | 9 +- .../assets-select-dialog.component.ts | 4 +- .../references-select-dialog.component.html | 1 + .../references-select-dialog.component.scss | 1 + .../references-select-dialog.component.ts | 2 +- src/styles/_background.scss | 4 +- src/styles/_mat-toolbar.scss | 4 +- 22 files changed, 290 insertions(+), 223 deletions(-) diff --git a/src/app/features/admin/settings/ui/ui.component.html b/src/app/features/admin/settings/ui/ui.component.html index 29f859aa..4780f812 100644 --- a/src/app/features/admin/settings/ui/ui.component.html +++ b/src/app/features/admin/settings/ui/ui.component.html @@ -2,10 +2,12 @@ User Interface - +
+ +
diff --git a/src/app/features/admin/spaces/spaces.component.html b/src/app/features/admin/spaces/spaces.component.html index c7df14c2..e36b917f 100644 --- a/src/app/features/admin/spaces/spaces.component.html +++ b/src/app/features/admin/spaces/spaces.component.html @@ -2,10 +2,12 @@ Spaces - +
+ +
@if (isLoading) { diff --git a/src/app/features/admin/users/users.component.html b/src/app/features/admin/users/users.component.html index d54bd092..285e36fe 100644 --- a/src/app/features/admin/users/users.component.html +++ b/src/app/features/admin/users/users.component.html @@ -2,15 +2,17 @@ Users - +
+ - + +
@if (isLoading()) { diff --git a/src/app/features/spaces/assets/assets.component.html b/src/app/features/spaces/assets/assets.component.html index 7274196b..442b9dd1 100644 --- a/src/app/features/spaces/assets/assets.component.html +++ b/src/app/features/spaces/assets/assets.component.html @@ -5,50 +5,55 @@ help - - - view_list - - - grid_view - - - @if ('ASSET_CREATE' | canUserPerform | async) { - - - - - } - - @if (['ASSET_IMPORT', 'ASSET_EXPORT'] | canUserPerform | async) { - - } +
+ @if (fileUploadQueue().length > 0) { + + } + + + view_list + + + grid_view + + + @if ('ASSET_CREATE' | canUserPerform | async) { + + - - @if ('ASSET_IMPORT' | canUserPerform | async) { - } - @if ('ASSET_EXPORT' | canUserPerform | async) { - } - + + + @if ('ASSET_IMPORT' | canUserPerform | async) { + + } + @if ('ASSET_EXPORT' | canUserPerform | async) { + + } + +
@if (isLoading()) { @@ -131,12 +136,28 @@ - Size - {{ element.size | digitalStore }} + File Size + + @if (element.size) { + {{ element.size | digitalStore }} + } @else { + remove + } + Type - {{ element.type }} + + @if (element.kind === 'FILE') { + @if (element.type) { + {{ element.type }} + } @else { + unknown + } + } @else { + Folder + } + Created At @@ -244,21 +265,21 @@ @if (item.kind === 'FILE') { + @if (item.size; as size) { +

{{ size | digitalStore }}

+ } @if (item.metadata; as metadata) { @if (metadata.width && metadata.height) { W{{ metadata.width }} x H{{ metadata.height }} } } - @if (item.size; as size) { -

{{ size | digitalStore }}

- } }

{{ item.updatedAt?.toDate() | date: 'mediumDate' }}

- + - - - - - } - - + + + + + } - - - - @if ('CONTENT_IMPORT' | canUserPerform | async) { - - } - @if ('CONTENT_EXPORT' | canUserPerform | async) { - - } - + + + @if ('CONTENT_IMPORT' | canUserPerform | async) { + + } + @if ('CONTENT_EXPORT' | canUserPerform | async) { + + } + +
@if (isLoading()) { diff --git a/src/app/features/spaces/contents/contents.component.ts b/src/app/features/spaces/contents/contents.component.ts index f9f49675..6e7f55a2 100644 --- a/src/app/features/spaces/contents/contents.component.ts +++ b/src/app/features/spaces/contents/contents.component.ts @@ -52,7 +52,7 @@ export class ContentsComponent { isLoading = signal(true); dataSource: MatTableDataSource = new MatTableDataSource([]); displayedColumns: string[] = [/*'select',*/ 'status', 'name', 'slug', 'schema', /*'publishedAt', 'createdAt',*/ 'updatedAt', 'actions']; - selection = new SelectionModel(true, []); + selection = new SelectionModel(true, [], undefined, (o1, o2) => o1.id === o2.id); schemas: Schema[] = []; schemasMapById: Map = new Map(); diff --git a/src/app/features/spaces/dashboard/dashboard.component.html b/src/app/features/spaces/dashboard/dashboard.component.html index 1970cb4d..1cfc2863 100644 --- a/src/app/features/spaces/dashboard/dashboard.component.html +++ b/src/app/features/spaces/dashboard/dashboard.component.html @@ -2,11 +2,13 @@ Dashboard - @if ('SPACE_MANAGEMENT' | canUserPerform | async) { - - } +
+ @if ('SPACE_MANAGEMENT' | canUserPerform | async) { + + } +
diff --git a/src/app/features/spaces/schemas/schemas.component.html b/src/app/features/spaces/schemas/schemas.component.html index ea7877f1..75b8edd4 100644 --- a/src/app/features/spaces/schemas/schemas.component.html +++ b/src/app/features/spaces/schemas/schemas.component.html @@ -5,31 +5,33 @@ help - @if ('SCHEMA_CREATE' | canUserPerform | async) { - - } - @if (['SCHEMA_IMPORT', 'SCHEMA_EXPORT'] | canUserPerform | async) { - - - @if ('SCHEMA_IMPORT' | canUserPerform | async) { - - } - @if ('SCHEMA_EXPORT' | canUserPerform | async) { - - } - - } +
+ @if ('SCHEMA_CREATE' | canUserPerform | async) { + + } + @if (['SCHEMA_IMPORT', 'SCHEMA_EXPORT'] | canUserPerform | async) { + + + @if ('SCHEMA_IMPORT' | canUserPerform | async) { + + } + @if ('SCHEMA_EXPORT' | canUserPerform | async) { + + } + + } +
@if (isLoading) { diff --git a/src/app/features/spaces/settings/general/general.component.html b/src/app/features/spaces/settings/general/general.component.html index 9ecd0601..115b56b1 100644 --- a/src/app/features/spaces/settings/general/general.component.html +++ b/src/app/features/spaces/settings/general/general.component.html @@ -2,10 +2,12 @@ General - +
+ +
@if (isLoading()) { diff --git a/src/app/features/spaces/settings/locales/locales.component.html b/src/app/features/spaces/settings/locales/locales.component.html index a74ca4f3..19f35400 100644 --- a/src/app/features/spaces/settings/locales/locales.component.html +++ b/src/app/features/spaces/settings/locales/locales.component.html @@ -2,10 +2,12 @@ Locales - +
+ +
@if (isLoading()) { diff --git a/src/app/features/spaces/settings/tokens/tokens.component.html b/src/app/features/spaces/settings/tokens/tokens.component.html index 9e64f7ec..ebdb29b1 100644 --- a/src/app/features/spaces/settings/tokens/tokens.component.html +++ b/src/app/features/spaces/settings/tokens/tokens.component.html @@ -2,10 +2,12 @@ Tokens - +
+ +
@if (isLoading()) { diff --git a/src/app/features/spaces/settings/visual-editor/visual-editor.component.html b/src/app/features/spaces/settings/visual-editor/visual-editor.component.html index 7085ec10..4a5599d4 100644 --- a/src/app/features/spaces/settings/visual-editor/visual-editor.component.html +++ b/src/app/features/spaces/settings/visual-editor/visual-editor.component.html @@ -2,10 +2,12 @@ Visual Editor - +
+ +
@@ -18,10 +20,12 @@ Preview URL's - +
+ +
diff --git a/src/app/features/spaces/translations/translations.component.html b/src/app/features/spaces/translations/translations.component.html index 47f07f6f..bcd8e707 100644 --- a/src/app/features/spaces/translations/translations.component.html +++ b/src/app/features/spaces/translations/translations.component.html @@ -6,52 +6,54 @@ help - @if ('TRANSLATION_CREATE' | canUserPerform | async) { - - } - @if ('TRANSLATION_PUBLISH' | canUserPerform | async) { - - } - - - - @for (locale of space.locales; track locale.id) { - } - @if (['TRANSLATION_IMPORT', 'TRANSLATION_EXPORT'] | canUserPerform | async) { - - @if ('TRANSLATION_IMPORT' | canUserPerform | async) { - + } + + + + @for (locale of space.locales; track locale.id) { + } - @if ('TRANSLATION_EXPORT' | canUserPerform | async) { - + @if (['TRANSLATION_IMPORT', 'TRANSLATION_EXPORT'] | canUserPerform | async) { + + @if ('TRANSLATION_IMPORT' | canUserPerform | async) { + + } + @if ('TRANSLATION_EXPORT' | canUserPerform | async) { + + } } - } - + +
@if (isLoading()) { diff --git a/src/app/shared/components/assets-select-dialog/assets-select-dialog.component.html b/src/app/shared/components/assets-select-dialog/assets-select-dialog.component.html index ab55d6fa..0e3ac9cb 100644 --- a/src/app/shared/components/assets-select-dialog/assets-select-dialog.component.html +++ b/src/app/shared/components/assets-select-dialog/assets-select-dialog.component.html @@ -1,6 +1,9 @@

Assets
+ @if (fileUploadQueue().length > 0) { + + } @if (isLoading()) { } -@if (isLoading()) { - -}   @for (pathItem of assetPath; track pathItem.fullSlug; let isFirst = $first) { @@ -95,12 +95,28 @@

- Size - {{ element.size | digitalStore }} + File Size + + @if (element.size) { + {{ element.size | digitalStore }} + } @else { + remove + } + Type - {{ element.type }} + + @if (element.kind === 'FILE') { + @if (element.type) { + {{ element.type }} + } @else { + unknown + } + } @else { + Folder + } + Updated At @@ -139,21 +155,21 @@

@if (item.kind === 'FILE') { + @if (item.size; as size) { +

{{ size | digitalStore }}

+ } @if (item.metadata; as metadata) { @if (metadata.width && metadata.height) { W{{ metadata.width }} x H{{ metadata.height }} } } - @if (item.size; as size) { -

{{ size | digitalStore }}

- } }

{{ item.updatedAt?.toDate() | date: 'mediumDate' }}

- + + - - - @for (locale of availableLocales; track locale.id) { - - } - - - @if (contentErrors.length > 0) { - - } - -
- @for (error of contentErrors; track error.contentId) { -
- warning - In {{ error.schema }} the {{ error.fieldDisplayName || error.fieldName }} {{ fe.errors(error.errors) }} for Locale - {{ availableLocalesMap.get(error.locale) }} -
+ + @for (locale of availableLocales; track locale.id) { + } -
-
- @if ('CONTENT_UPDATE' | canUserPerform | async) { - - } - @if ('CONTENT_PUBLISH' | canUserPerform | async) { - - } - @if (document?.publishedAt === undefined) { - - } @else if (document?.publishedAt?.seconds > document?.updatedAt?.seconds) { - - } @else if (document?.publishedAt && document?.publishedAt?.seconds < document?.updatedAt?.seconds) { - - } + - - - + @if (contentErrors.length > 0) { + + } - - @for (locale of selectedSpace?.locales; track locale.id) { - } - - @for (locale of selectedSpace?.locales; track locale.id) { - } - + @if (document?.publishedAt === undefined) { + + } @else if (document?.publishedAt?.seconds > document?.updatedAt?.seconds) { + + } @else if (document?.publishedAt && document?.publishedAt?.seconds < document?.updatedAt?.seconds) { + + } + + + + + + + @for (locale of selectedSpace?.locales; track locale.id) { + + } + + @for (locale of selectedSpace?.locales; track locale.id) { + + } + +

@@ -211,117 +214,119 @@

-
-
    - @for (item of history$ | async; track item.id; let isLast = $last) { -
  • -
    -
    - @switch (item.type) { - @case ('PUBLISHED') { -
    - - publish - -
    -
    + @if (showHistory) { +
    +
      + @for (item of history$ | async; track item.id; let isLast = $last) { +
    • +
      +
      + @switch (item.type) { + @case ('PUBLISHED') {
      -

      - Published by - - {{ item.name || 'Unknown' }} - -

      + + publish +
      -
      - +
      +
      +

      + Published by + + {{ item.name || 'Unknown' }} + +

      +
      +
      + +
      -
      - } - @case ('CREATE') { -
      - - add - -
      -
      + } + @case ('CREATE') {
      -

      - Created with name {{ item.cName }} and slug - {{ item.cSlug }} by - - {{ item.name || 'Unknown' }} - -

      + + add +
      -
      - +
      +
      +

      + Created with name {{ item.cName }} and slug + {{ item.cSlug }} by + + {{ item.name || 'Unknown' }} + +

      +
      +
      + +
      -
      - } - @case ('UPDATE') { -
      - - edit - -
      -
      + } + @case ('UPDATE') {
      -

      - Updated with - @if (item.cName) { - name {{ item.cName }} - } - @if (item.cSlug) { + + edit + +

      +
      +
      +

      + Updated with @if (item.cName) { - and + name {{ item.cName }} } - slug {{ item.cSlug }} - } - @if (item.cParentSlug) { - parent slug {{ item.cParentSlug }} - } @else if (item.cData) { - content - } @else { - nothing - } - by - - {{ item.name || 'Unknown' }} - -

      -
      -
      - + @if (item.cSlug) { + @if (item.cName) { + and + } + slug {{ item.cSlug }} + } + @if (item.cParentSlug) { + parent slug {{ item.cParentSlug }} + } @else if (item.cData) { + content + } @else { + nothing + } + by + + {{ item.name || 'Unknown' }} + +

      +
      +
      + +
      -
      - } - @default { -
      - - question_mark - -
      -
      + } + @default {
      -

      Unknown

      by - - {{ item.name || 'Unknown' }} + + question_mark
      -
      - +
      +
      +

      Unknown

      by + + {{ item.name || 'Unknown' }} + +
      +
      + +
      -
      + } } - } +
      -
      -
    • - } @empty { - No Records found - } -
    -
    +
  • + } @empty { + No Records found + } +
+
+ }
diff --git a/src/app/features/spaces/contents/edit-document/edit-document.component.ts b/src/app/features/spaces/contents/edit-document/edit-document.component.ts index 0c1e6879..a2dee531 100644 --- a/src/app/features/spaces/contents/edit-document/edit-document.component.ts +++ b/src/app/features/spaces/contents/edit-document/edit-document.component.ts @@ -164,7 +164,7 @@ export class EditDocumentComponent implements OnInit, DirtyFormGuardComponent { } get isFormDirty(): boolean { - return !ObjectUtils.isEqual(this.document?.data, JSON.stringify(this.contentHelperService.clone(this.documentData))); + return JSON.stringify(this.document?.data) !== JSON.stringify(this.contentHelperService.clone(this.documentData)); } publish(): void { diff --git a/src/app/features/spaces/translations/translations.component.html b/src/app/features/spaces/translations/translations.component.html index bcd8e707..af8037c3 100644 --- a/src/app/features/spaces/translations/translations.component.html +++ b/src/app/features/spaces/translations/translations.component.html @@ -353,117 +353,119 @@
-
-
    - @for (item of history$ | async; track item.id; let isLast = $last) { -
  • -
    -
    - @switch (item.type) { - @case ('PUBLISHED') { -
    - - publish - -
    -
    + @if (showHistory) { +
    +
      + @for (item of history$ | async; track item.id; let isLast = $last) { +
    • +
      +
      + @switch (item.type) { + @case ('PUBLISHED') {
      -

      - Published by - - {{ item.name || 'Unknown' }} - -

      + + publish +
      -
      - +
      +
      +

      + Published by + + {{ item.name || 'Unknown' }} + +

      +
      +
      + +
      -
      - } - @case ('CREATE') { -
      - - add - -
      -
      + } + @case ('CREATE') {
      -

      - Add {{ item.key }} by - - {{ item.name || 'Unknown' }} - -

      + + add +
      -
      - +
      +
      +

      + Add {{ item.key }} by + + {{ item.name || 'Unknown' }} + +

      +
      +
      + +
      -
      - } - @case ('UPDATE') { -
      - - edit - -
      -
      + } + @case ('UPDATE') {
      -

      - Edit {{ item.key }} by - - {{ item.name || 'Unknown' }} - -

      + + edit +
      -
      - +
      +
      +

      + Edit {{ item.key }} by + + {{ item.name || 'Unknown' }} + +

      +
      +
      + +
      -
      - } - @case ('DELETE') { -
      - - delete - -
      -
      + } + @case ('DELETE') {
      -

      - Delete {{ item.key }} by - - {{ item.name || 'Unknown' }} - -

      + + delete +
      -
      - +
      +
      +

      + Delete {{ item.key }} by + + {{ item.name || 'Unknown' }} + +

      +
      +
      + +
      -
      - } - @default { -
      - - question_mark - -
      -
      + } + @default {
      -

      Unknown

      + + question_mark +
      -
      - +
      +
      +

      Unknown

      +
      +
      + +
      -
      + } } - } +
      -
      -
    • - } @empty { - No Records found - } -
    -
    +
  • + } @empty { + No Records found + } +
+
+ }
} diff --git a/src/app/shared/services/content-history.service.ts b/src/app/shared/services/content-history.service.ts index 94210274..4162e07b 100644 --- a/src/app/shared/services/content-history.service.ts +++ b/src/app/shared/services/content-history.service.ts @@ -11,7 +11,7 @@ export class ContentHistoryService { constructor(private readonly firestore: Firestore) {} findAll(spaceId: string, id: string): Observable { - const queryConstrains: QueryConstraint[] = [orderBy('createdAt', 'desc'), limit(20)]; + const queryConstrains: QueryConstraint[] = [orderBy('createdAt', 'desc'), limit(30)]; return collectionData(query(collection(this.firestore, `spaces/${spaceId}/contents/${id}/histories`), ...queryConstrains), { idField: 'id', }).pipe( diff --git a/src/app/shared/services/translation-history.service.ts b/src/app/shared/services/translation-history.service.ts index 83a15b1a..61985157 100644 --- a/src/app/shared/services/translation-history.service.ts +++ b/src/app/shared/services/translation-history.service.ts @@ -11,7 +11,7 @@ export class TranslationHistoryService { constructor(private readonly firestore: Firestore) {} findAll(spaceId: string): Observable { - const queryConstrains: QueryConstraint[] = [orderBy('createdAt', 'desc'), limit(20)]; + const queryConstrains: QueryConstraint[] = [orderBy('createdAt', 'desc'), limit(30)]; return collectionData(query(collection(this.firestore, `spaces/${spaceId}/translations_history`), ...queryConstrains), { idField: 'id', }).pipe( From e53e9a96af17e5067c4bea9e6aa3f3e88fadd576 Mon Sep 17 00:00:00 2001 From: alexcibotari Date: Sat, 18 Jan 2025 23:25:36 +0200 Subject: [PATCH 09/10] fix preview only images --- src/app/app.module.ts | 1 - src/app/features/spaces/assets/assets.component.ts | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 4d4ade5f..c84cd320 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -95,7 +95,6 @@ import { provideRemoteConfig, getRemoteConfig } from '@angular/fire/remote-confi { provide: IMAGE_LOADER, useValue: (config: ImageLoaderConfig) => { - console.log('IMAGE_LOADER', config); // optimize image for API assets if (config.src.startsWith('/api/') && config.width) { const thumbnailParam = config.loaderParams && config.loaderParams['thumbnail'] ? '&thumbnail=true' : ''; diff --git a/src/app/features/spaces/assets/assets.component.ts b/src/app/features/spaces/assets/assets.component.ts index 62aecfc6..31186180 100644 --- a/src/app/features/spaces/assets/assets.component.ts +++ b/src/app/features/spaces/assets/assets.component.ts @@ -92,6 +92,7 @@ export class AssetsComponent implements OnInit { ) .subscribe({ next: assets => { + console.log(assets); this.assets = assets; this.dataSource = new MatTableDataSource(assets); this.dataSource.sort = this.sort() || null; @@ -314,7 +315,7 @@ export class AssetsComponent implements OnInit { } onAssetSelect(element: Asset): void { - if (element.kind === AssetKind.FILE) { + if (element.kind === AssetKind.FILE && element.type.startsWith('image/')) { this.dialog .open(ImagePreviewDialogComponent, { panelClass: 'image-preview', From 0ec776556f07f82dbb461ba6a6ede6ad0e66851d Mon Sep 17 00:00:00 2001 From: alexcibotari Date: Sat, 18 Jan 2025 23:29:50 +0200 Subject: [PATCH 10/10] increase asset name from 50 to 100 --- .../assets/add-folder-dialog/add-folder-dialog.component.html | 4 ++-- .../assets/edit-file-dialog/edit-file-dialog.component.html | 4 ++-- .../edit-folder-dialog/edit-folder-dialog.component.html | 4 ++-- src/app/shared/validators/asset.validator.ts | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/app/features/spaces/assets/add-folder-dialog/add-folder-dialog.component.html b/src/app/features/spaces/assets/add-folder-dialog/add-folder-dialog.component.html index d4abff54..73048229 100644 --- a/src/app/features/spaces/assets/add-folder-dialog/add-folder-dialog.component.html +++ b/src/app/features/spaces/assets/add-folder-dialog/add-folder-dialog.component.html @@ -4,8 +4,8 @@

Create new Folder

Name - - {{ form.controls['name'].value?.length || 0 }}/50 + + {{ form.controls['name'].value?.length || 0 }}/100 @if (form.controls['name'].errors; as errors) { {{ fe.errors(errors) }} } diff --git a/src/app/features/spaces/assets/edit-file-dialog/edit-file-dialog.component.html b/src/app/features/spaces/assets/edit-file-dialog/edit-file-dialog.component.html index f626a8e4..22751d52 100644 --- a/src/app/features/spaces/assets/edit-file-dialog/edit-file-dialog.component.html +++ b/src/app/features/spaces/assets/edit-file-dialog/edit-file-dialog.component.html @@ -4,9 +4,9 @@

Edit File

Name - + {{ data.asset.extension }} - {{ form.controls['name'].value?.length || 0 }}/50 + {{ form.controls['name'].value?.length || 0 }}/100 @if (form.controls['name'].errors; as errors) { {{ fe.errors(errors) }} } diff --git a/src/app/features/spaces/assets/edit-folder-dialog/edit-folder-dialog.component.html b/src/app/features/spaces/assets/edit-folder-dialog/edit-folder-dialog.component.html index b1cdb460..4367f8a2 100644 --- a/src/app/features/spaces/assets/edit-folder-dialog/edit-folder-dialog.component.html +++ b/src/app/features/spaces/assets/edit-folder-dialog/edit-folder-dialog.component.html @@ -4,8 +4,8 @@

Edit Folder

Name - - {{ form.controls['name'].value?.length || 0 }}/50 + + {{ form.controls['name'].value?.length || 0 }}/100 @if (form.controls['name'].errors; as errors) { {{ fe.errors(errors) }} } diff --git a/src/app/shared/validators/asset.validator.ts b/src/app/shared/validators/asset.validator.ts index c34e3d8d..ccdf45df 100644 --- a/src/app/shared/validators/asset.validator.ts +++ b/src/app/shared/validators/asset.validator.ts @@ -6,6 +6,6 @@ export class AssetValidator { Validators.required, CommonValidator.noSpaceAround, Validators.minLength(3), - Validators.maxLength(50), + Validators.maxLength(100), ]; }