@flusys/ng-storage 1.1.0-beta → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +144 -5
- package/fesm2022/{flusys-ng-storage-file-manager-form.component-CxAYC6nj.mjs → flusys-ng-storage-file-manager-form.component-CXVB9G-f.mjs} +120 -351
- package/fesm2022/flusys-ng-storage-file-manager-form.component-CXVB9G-f.mjs.map +1 -0
- package/fesm2022/flusys-ng-storage-file-manager-list.component-0O_b4EjN.mjs +304 -0
- package/fesm2022/flusys-ng-storage-file-manager-list.component-0O_b4EjN.mjs.map +1 -0
- package/fesm2022/flusys-ng-storage-folder-form.component-BTQGEqNu.mjs +155 -0
- package/fesm2022/flusys-ng-storage-folder-form.component-BTQGEqNu.mjs.map +1 -0
- package/fesm2022/flusys-ng-storage-folder-list.component-B8GoIh6Z.mjs +194 -0
- package/fesm2022/flusys-ng-storage-folder-list.component-B8GoIh6Z.mjs.map +1 -0
- package/fesm2022/{flusys-ng-storage-storage-config-form.component-SEYIBife.mjs → flusys-ng-storage-storage-config-form.component-CorNWrmF.mjs} +219 -302
- package/fesm2022/flusys-ng-storage-storage-config-form.component-CorNWrmF.mjs.map +1 -0
- package/fesm2022/flusys-ng-storage-storage-config-list.component-YXzz3Tvo.mjs +187 -0
- package/fesm2022/flusys-ng-storage-storage-config-list.component-YXzz3Tvo.mjs.map +1 -0
- package/fesm2022/flusys-ng-storage.mjs +267 -226
- package/fesm2022/flusys-ng-storage.mjs.map +1 -1
- package/package.json +9 -9
- package/types/flusys-ng-storage.d.ts +101 -151
- package/fesm2022/flusys-ng-storage-file-manager-form.component-CxAYC6nj.mjs.map +0 -1
- package/fesm2022/flusys-ng-storage-file-manager-list.component-BevfDZO0.mjs +0 -475
- package/fesm2022/flusys-ng-storage-file-manager-list.component-BevfDZO0.mjs.map +0 -1
- package/fesm2022/flusys-ng-storage-folder-form.component-BhurG3dl.mjs +0 -253
- package/fesm2022/flusys-ng-storage-folder-form.component-BhurG3dl.mjs.map +0 -1
- package/fesm2022/flusys-ng-storage-folder-list.component-Clrjcw0B.mjs +0 -267
- package/fesm2022/flusys-ng-storage-folder-list.component-Clrjcw0B.mjs.map +0 -1
- package/fesm2022/flusys-ng-storage-storage-config-form.component-SEYIBife.mjs.map +0 -1
- package/fesm2022/flusys-ng-storage-storage-config-list.component-CofVBysj.mjs +0 -328
- package/fesm2022/flusys-ng-storage-storage-config-list.component-CofVBysj.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flusys-ng-storage-file-manager-form.component-CXVB9G-f.mjs","sources":["../../../projects/ng-storage/pages/file-manager/file-manager-form.component.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, effect, inject, signal } from '@angular/core';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { form, FormField, required } from '@angular/forms/signals';\nimport { ActivatedRoute } from '@angular/router';\nimport { AngularModule, PrimeModule } from '@flusys/ng-shared';\nimport { firstValueFrom } from 'rxjs';\nimport { IFileManager } from '../../interfaces/file-manager.interface';\nimport { IFolder } from '../../interfaces/folder.interface';\nimport { IStorageConfig } from '../../interfaces/storage-config.interface';\nimport { FileManagerApiService } from '../../services/file-manager-api.service';\nimport { FolderApiService } from '../../services/folder-api.service';\nimport { StorageConfigApiService } from '../../services/storage-config-api.service';\nimport { UploadService } from '../../services/upload.service';\nimport { BaseStoragePage } from '../../utils/base-storage-page';\nimport { formatFileSize, getProviderLabel } from '../../utils/storage-utils';\n\n/** File manager form model interface */\ninterface IFileManagerFormModel {\n id: string;\n name: string;\n isPrivate: boolean;\n folderId: string;\n storageConfigId: string;\n}\n\n/**\n * File Manager Form Component\n * Upload and edit file metadata\n */\n@Component({\n selector: 'lib-file-manager-form',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [AngularModule, PrimeModule, FormField],\n template: `\n <div class=\"card\">\n <div class=\"mb-4\">\n <h3 class=\"text-lg sm:text-xl font-semibold\">{{ isEditMode() ? 'Edit File' : 'Upload File' }}</h3>\n @if (showCompanyInfo()) {\n <p class=\"text-sm text-muted-color mt-1\">Company: {{ currentCompanyName() }}</p>\n }\n </div>\n\n <form (ngSubmit)=\"onSubmit()\">\n @if (!isEditMode()) {\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4 mb-4\">\n <div class=\"field\">\n <label for=\"storageConfig\" class=\"block font-medium mb-2 text-sm sm:text-base\">Storage Configuration *</label>\n <select id=\"storageConfig\" class=\"p-select-native w-full\" [formField]=\"fileForm.storageConfigId\">\n <option value=\"\">Select storage configuration...</option>\n @for (config of availableConfigs(); track config.id) {\n <option [value]=\"config.id\">{{ config.name }} ({{ getProviderLabel(config.storage) }})</option>\n }\n </select>\n @if (availableConfigs().length === 0 && !isLoadingConfigs()) {\n <small class=\"text-warn block mt-2\">\n <i class=\"pi pi-exclamation-triangle mr-1\"></i>\n No storage configurations found. Please create one first.\n </small>\n }\n </div>\n\n <div class=\"field\">\n <label for=\"folder\" class=\"block font-medium mb-2 text-sm sm:text-base\">Folder (Optional)</label>\n <select id=\"folder\" class=\"p-select-native w-full\" [formField]=\"fileForm.folderId\">\n <option value=\"\">No folder (root level)</option>\n @for (folder of availableFolders(); track folder.id) {\n <option [value]=\"folder.id\">{{ folder.name }}</option>\n }\n </select>\n @if (availableFolders().length === 0 && !isLoadingFolders()) {\n <small class=\"text-muted-color block mt-2\">\n <i class=\"pi pi-info-circle mr-1\"></i>\n No folders available. File will be uploaded to root level.\n </small>\n }\n </div>\n </div>\n } @else {\n <div class=\"field mb-4\">\n <label for=\"folder\" class=\"block font-medium mb-2 text-sm sm:text-base\">Folder (Optional)</label>\n <select id=\"folder\" class=\"p-select-native w-full\" [formField]=\"fileForm.folderId\">\n <option value=\"\">No folder (root level)</option>\n @for (folder of availableFolders(); track folder.id) {\n <option [value]=\"folder.id\">{{ folder.name }}</option>\n }\n </select>\n @if (availableFolders().length === 0 && !isLoadingFolders()) {\n <small class=\"text-muted-color block mt-2\">\n <i class=\"pi pi-info-circle mr-1\"></i>\n No folders available.\n </small>\n }\n </div>\n }\n\n @if (!isEditMode()) {\n <div class=\"field mb-4\">\n <label class=\"block font-medium mb-2 text-sm sm:text-base\">Select File *</label>\n <p-fileupload\n #fileUpload\n [customUpload]=\"true\"\n (onSelect)=\"onFileSelect($event)\"\n [multiple]=\"false\"\n [maxFileSize]=\"50000000\"\n [showUploadButton]=\"false\"\n [showCancelButton]=\"false\"\n chooseLabel=\"Choose File\"\n chooseIcon=\"pi pi-upload\"\n accept=\"*/*\"\n class=\"w-full\"\n >\n <ng-template #content let-files>\n @if (files && files.length > 0) {\n <div class=\"flex flex-col gap-2\">\n @for (file of files; track file.name) {\n <div class=\"flex items-center gap-3 p-3 border border-surface rounded-lg bg-surface-ground\">\n <i class=\"pi pi-file text-xl sm:text-2xl text-primary\"></i>\n <div class=\"flex-1 min-w-0\">\n <div class=\"font-medium truncate\">{{ file.name }}</div>\n <div class=\"text-sm text-muted-color\">{{ formatFileSize(file.size) }}</div>\n </div>\n <p-button icon=\"pi pi-times\" [text]=\"true\" severity=\"danger\" size=\"small\" (onClick)=\"fileUpload.clear()\" />\n </div>\n }\n </div>\n } @else {\n <div class=\"flex items-center justify-center flex-col p-6 sm:p-8 border-2 border-dashed border-surface rounded-lg\">\n <i class=\"pi pi-cloud-upload text-3xl sm:text-4xl text-muted-color mb-3\"></i>\n <p class=\"text-muted-color text-center text-sm sm:text-base\">Drag and drop file here or click to browse</p>\n <p class=\"text-xs sm:text-sm text-muted-color mt-2\">Maximum file size: 50MB</p>\n </div>\n }\n </ng-template>\n </p-fileupload>\n @if (!selectedFile() && !isEditMode()) {\n <small class=\"text-muted-color\">Please select a file to upload</small>\n }\n </div>\n }\n\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div class=\"field md:col-span-2\">\n <label for=\"name\" class=\"block font-medium mb-2 text-sm sm:text-base\">File Name *</label>\n <input pInputText id=\"name\" [formField]=\"fileForm.name\" [placeholder]=\"isEditMode() ? 'Enter file name' : 'Will be auto-filled from selected file'\" class=\"w-full\" />\n </div>\n\n <div class=\"field\">\n <label class=\"p-checkbox-native flex items-center gap-2\">\n <input type=\"checkbox\" [formField]=\"fileForm.isPrivate\" />\n <span>Private File</span>\n </label>\n <small class=\"text-muted-color block mt-2\">\n {{ formModel().isPrivate ? 'Only users with permission can access' : 'File is publicly accessible' }}\n </small>\n </div>\n </div>\n\n <div class=\"flex justify-end gap-2 mt-4\">\n <p-button label=\"Cancel\" severity=\"secondary\" [outlined]=\"true\" (onClick)=\"onCancel()\" />\n <p-button\n type=\"submit\"\n [label]=\"isEditMode() ? 'Update' : 'Upload'\"\n [loading]=\"isLoading()\"\n [disabled]=\"!isFormValid() || (!isEditMode() && !selectedFile()) || isLoading()\"\n />\n </div>\n </form>\n </div>\n `,\n})\nexport class FileManagerFormComponent extends BaseStoragePage {\n private readonly route = inject(ActivatedRoute);\n private readonly fileService = inject(FileManagerApiService);\n private readonly uploadService = inject(UploadService);\n private readonly configService = inject(StorageConfigApiService);\n private readonly folderService = inject(FolderApiService);\n\n private readonly routeParams = toSignal(this.route.paramMap);\n private initialized = false;\n\n readonly isLoadingConfigs = signal(false);\n readonly isLoadingFolders = signal(false);\n readonly existingFile = signal<IFileManager | null>(null);\n readonly isEditMode = computed(() => !!this.existingFile());\n readonly selectedFile = signal<File | null>(null);\n readonly availableConfigs = signal<IStorageConfig[]>([]);\n readonly availableFolders = signal<IFolder[]>([]);\n\n /** Utility functions exposed to template */\n readonly formatFileSize = formatFileSize;\n readonly getProviderLabel = getProviderLabel;\n\n /** Form model */\n readonly formModel = signal<IFileManagerFormModel>({\n id: '',\n name: '',\n isPrivate: false,\n folderId: '',\n storageConfigId: '',\n });\n\n /** Form with validation */\n readonly fileForm = form(this.formModel, (f) => {\n required(f.name, { message: 'File name is required' });\n });\n\n /** Check if form is valid */\n readonly isFormValid = computed(() => this.formModel().name.trim().length > 0);\n\n constructor() {\n super();\n effect(() => {\n const params = this.routeParams();\n if (!params || this.initialized) return;\n\n this.initialized = true;\n const fileId = params.get('id');\n if (fileId) {\n this.loadFile(fileId);\n } else {\n this.loadStorageConfigs();\n }\n this.loadFolders();\n });\n }\n\n async loadStorageConfigs(): Promise<void> {\n this.isLoadingConfigs.set(true);\n try {\n const response = await firstValueFrom(\n this.configService.getAll('', {\n pagination: { currentPage: 0, pageSize: 100 },\n filter: {},\n select: [],\n sort: {},\n }),\n );\n if (response.success && response.data) {\n this.availableConfigs.set(response.data);\n if (response.data.length === 1) {\n this.formModel.update((m) => ({ ...m, storageConfigId: response.data![0].id }));\n }\n }\n } catch {\n this.showError('Failed to load storage configurations.');\n } finally {\n this.isLoadingConfigs.set(false);\n }\n }\n\n async loadFolders(): Promise<void> {\n this.isLoadingFolders.set(true);\n try {\n const response = await firstValueFrom(\n this.folderService.getAll('', {\n pagination: { currentPage: 0, pageSize: 100 },\n filter: {},\n select: [],\n sort: {},\n }),\n );\n if (response.success && response.data) {\n this.availableFolders.set(response.data);\n }\n } catch {\n // Silently fail - folders are optional\n } finally {\n this.isLoadingFolders.set(false);\n }\n }\n\n async loadFile(id: string): Promise<void> {\n this.isLoading.set(true);\n try {\n const response = await this.fileService.findByIdAsync(id);\n if (response.success && response.data) {\n const file = response.data;\n this.existingFile.set(file);\n this.formModel.set({\n id: file.id,\n name: file.name,\n isPrivate: file.isPrivate ?? false,\n folderId: file.folderId ?? '',\n storageConfigId: '',\n });\n }\n } catch {\n this.showError('Failed to load file.');\n this.navigateTo(['/storage/files']);\n } finally {\n this.isLoading.set(false);\n }\n }\n\n onFileSelect(event: { files?: File[]; currentFiles?: File[] }): void {\n const file = event.files?.[0] || event.currentFiles?.[0];\n if (file) {\n this.selectedFile.set(file);\n this.formModel.update((m) => ({ ...m, name: file.name }));\n }\n }\n\n async onSubmit(): Promise<void> {\n if (!this.isFormValid()) return;\n\n this.isLoading.set(true);\n try {\n const formValue = this.formModel();\n\n if (this.isEditMode()) {\n await this.fileService.updateAsync({\n id: formValue.id,\n name: formValue.name,\n isPrivate: formValue.isPrivate,\n folderId: formValue.folderId || null,\n });\n this.showSuccess('File updated successfully.');\n } else {\n const file = this.selectedFile();\n if (!file) {\n this.showError('Please select a file to upload.');\n return;\n }\n\n if (!formValue.storageConfigId) {\n this.showError('Please select a storage configuration.');\n return;\n }\n\n const uploadResponse = await firstValueFrom(\n this.uploadService.uploadSingleFile(file, {\n compress: true,\n quality: 85,\n storageConfigId: formValue.storageConfigId,\n }),\n );\n\n if (uploadResponse.success && uploadResponse.data) {\n const uploadedFileInfo = uploadResponse.data;\n await this.fileService.createFileAsync({\n name: formValue.name,\n key: uploadedFileInfo.key,\n contentType: file.type || 'application/octet-stream',\n size: Math.round(file.size / 1024).toString(),\n isPrivate: formValue.isPrivate,\n folderId: formValue.folderId || undefined,\n storageConfigId: formValue.storageConfigId,\n });\n this.showSuccess('File uploaded successfully.');\n } else {\n throw new Error('Upload failed');\n }\n }\n\n this.navigateTo(['/storage/files']);\n } catch (error: any) {\n this.showError(error?.message || `Failed to ${this.isEditMode() ? 'update' : 'upload'} file.`);\n } finally {\n this.isLoading.set(false);\n }\n }\n\n onCancel(): void {\n this.navigateTo(['/storage/files']);\n }\n}\n"],"names":["i2","i4"],"mappings":"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"}
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, signal, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import { FILE_PERMISSIONS, AngularModule, PrimeModule, HasPermissionDirective } from '@flusys/ng-shared';
|
|
4
|
+
import { firstValueFrom } from 'rxjs';
|
|
5
|
+
import { BaseStorageListPage, FileManagerApiService, getFileIcon, getProviderLabel, getProviderSeverity } from './flusys-ng-storage.mjs';
|
|
6
|
+
import * as i1 from 'primeng/button';
|
|
7
|
+
import * as i2 from 'primeng/table';
|
|
8
|
+
import * as i3 from 'primeng/tag';
|
|
9
|
+
import * as i4 from 'primeng/tooltip';
|
|
10
|
+
import * as i5 from '@angular/common';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* File Manager List Component
|
|
14
|
+
* Displays all files with company filter (if enabled)
|
|
15
|
+
*/
|
|
16
|
+
class FileManagerListComponent extends BaseStorageListPage {
|
|
17
|
+
// Permission constants for template
|
|
18
|
+
FILE_PERMISSIONS = FILE_PERMISSIONS;
|
|
19
|
+
fileService = inject(FileManagerApiService);
|
|
20
|
+
/** Files list alias for template compatibility */
|
|
21
|
+
files = this.items;
|
|
22
|
+
/** ID of file currently being viewed (null when not viewing) */
|
|
23
|
+
viewingFileId = signal(null, ...(ngDevMode ? [{ debugName: "viewingFileId" }] : []));
|
|
24
|
+
/** Utility functions exposed to template */
|
|
25
|
+
getFileIcon = getFileIcon;
|
|
26
|
+
getProviderLabel = getProviderLabel;
|
|
27
|
+
getProviderSeverity = getProviderSeverity;
|
|
28
|
+
getResourceRoute() {
|
|
29
|
+
return '/storage/files';
|
|
30
|
+
}
|
|
31
|
+
getDeleteConfirmMessage(file) {
|
|
32
|
+
return `Are you sure you want to delete "${file.name}"?`;
|
|
33
|
+
}
|
|
34
|
+
async loadData() {
|
|
35
|
+
this.isLoading.set(true);
|
|
36
|
+
try {
|
|
37
|
+
const response = await firstValueFrom(this.fileService.getAll('', {
|
|
38
|
+
pagination: this.getPaginationParams(),
|
|
39
|
+
filter: {},
|
|
40
|
+
select: [],
|
|
41
|
+
sort: {},
|
|
42
|
+
}));
|
|
43
|
+
if (response.success) {
|
|
44
|
+
this.items.set(response.data ?? []);
|
|
45
|
+
this.total.set(response.meta?.total ?? 0);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
this.showError('Failed to load files.');
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
this.isLoading.set(false);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
onUpload() {
|
|
56
|
+
this.navigateTo(['/storage/files/new']);
|
|
57
|
+
}
|
|
58
|
+
async onView(file) {
|
|
59
|
+
this.viewingFileId.set(file.id);
|
|
60
|
+
try {
|
|
61
|
+
const response = await firstValueFrom(this.fileService.getFiles([file.id]));
|
|
62
|
+
// Response type is ISingleResponse<IFilesResponseDto[]>
|
|
63
|
+
if (response.success && response.data?.length && response.data[0].url) {
|
|
64
|
+
window.open(response.data[0].url, '_blank');
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
this.showError('File URL is not available.');
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
this.showError('Failed to get file URL.');
|
|
72
|
+
}
|
|
73
|
+
finally {
|
|
74
|
+
this.viewingFileId.set(null);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
onSoftDelete(file) {
|
|
78
|
+
this.confirmationService.confirm({
|
|
79
|
+
message: `Move "${file.name}" to trash? You can recover it later.`,
|
|
80
|
+
header: 'Move to Trash',
|
|
81
|
+
icon: 'pi pi-trash',
|
|
82
|
+
acceptLabel: 'Move to Trash',
|
|
83
|
+
acceptButtonStyleClass: 'p-button-warning',
|
|
84
|
+
accept: async () => {
|
|
85
|
+
try {
|
|
86
|
+
await this.fileService.deleteAsync({ id: file.id, type: 'delete' });
|
|
87
|
+
this.showSuccess('File moved to trash successfully.');
|
|
88
|
+
this.loadData();
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
this.showError('Failed to move file to trash.');
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
onPermanentDelete(file) {
|
|
97
|
+
this.confirmationService.confirm({
|
|
98
|
+
message: `Permanently delete "${file.name}"? This action CANNOT be undone and will delete the file from storage.`,
|
|
99
|
+
header: 'Permanent Delete',
|
|
100
|
+
icon: 'pi pi-exclamation-triangle',
|
|
101
|
+
acceptLabel: 'Delete Permanently',
|
|
102
|
+
rejectLabel: 'Cancel',
|
|
103
|
+
acceptButtonStyleClass: 'p-button-danger',
|
|
104
|
+
accept: async () => {
|
|
105
|
+
try {
|
|
106
|
+
await this.fileService.deleteAsync({ id: file.id, type: 'permanent' });
|
|
107
|
+
this.showSuccess('File permanently deleted.');
|
|
108
|
+
this.loadData();
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
this.showError('Failed to permanently delete file.');
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: FileManagerListComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
117
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", type: FileManagerListComponent, isStandalone: true, selector: "lib-file-manager-list", usesInheritance: true, ngImport: i0, template: `
|
|
118
|
+
<div class="card">
|
|
119
|
+
<div class="flex flex-col sm:flex-row sm:justify-between sm:items-center gap-3 mb-4">
|
|
120
|
+
<div>
|
|
121
|
+
<h3 class="text-lg sm:text-xl font-semibold">File Manager</h3>
|
|
122
|
+
@if (showCompanyInfo()) {
|
|
123
|
+
<p class="text-sm text-muted-color mt-1">
|
|
124
|
+
Company: {{ currentCompanyName() }}
|
|
125
|
+
</p>
|
|
126
|
+
}
|
|
127
|
+
</div>
|
|
128
|
+
<p-button *hasPermission="FILE_PERMISSIONS.CREATE" label="Upload File" icon="pi pi-upload" (onClick)="onUpload()" styleClass="w-full sm:w-auto" />
|
|
129
|
+
</div>
|
|
130
|
+
|
|
131
|
+
<div class="overflow-x-auto">
|
|
132
|
+
<p-table
|
|
133
|
+
[value]="files()"
|
|
134
|
+
[loading]="isLoading()"
|
|
135
|
+
[paginator]="totalRecords() > 0"
|
|
136
|
+
[rows]="pageSize()"
|
|
137
|
+
[totalRecords]="totalRecords()"
|
|
138
|
+
[lazy]="true"
|
|
139
|
+
(onLazyLoad)="onPageChange($event)"
|
|
140
|
+
[rowsPerPageOptions]="[10, 25, 50]"
|
|
141
|
+
[scrollable]="true"
|
|
142
|
+
styleClass="p-datatable-sm"
|
|
143
|
+
>
|
|
144
|
+
<ng-template #header>
|
|
145
|
+
<tr>
|
|
146
|
+
<th>Name</th>
|
|
147
|
+
<th class="hidden lg:table-cell">Type</th>
|
|
148
|
+
<th>Size</th>
|
|
149
|
+
<th>Location</th>
|
|
150
|
+
<th class="hidden xl:table-cell">Config</th>
|
|
151
|
+
<th>Private</th>
|
|
152
|
+
<th class="hidden md:table-cell">Created</th>
|
|
153
|
+
<th class="w-[120px]">Actions</th>
|
|
154
|
+
</tr>
|
|
155
|
+
</ng-template>
|
|
156
|
+
<ng-template #body let-file>
|
|
157
|
+
<tr>
|
|
158
|
+
<td>
|
|
159
|
+
<div class="flex items-center gap-2">
|
|
160
|
+
<i [class]="getFileIcon(file.contentType)"></i>
|
|
161
|
+
<span class="truncate max-w-32 sm:max-w-none">{{ file.name }}</span>
|
|
162
|
+
</div>
|
|
163
|
+
</td>
|
|
164
|
+
<td class="hidden lg:table-cell">
|
|
165
|
+
<span class="text-sm text-muted-color">{{ file.contentType }}</span>
|
|
166
|
+
</td>
|
|
167
|
+
<td>{{ file.size }} KB</td>
|
|
168
|
+
<td>
|
|
169
|
+
<p-tag [value]="getProviderLabel(file.location)" [severity]="getProviderSeverity(file.location)" />
|
|
170
|
+
</td>
|
|
171
|
+
<td class="hidden xl:table-cell">{{ file.providerName || '-' }}</td>
|
|
172
|
+
<td>
|
|
173
|
+
@if (file.isPrivate) {
|
|
174
|
+
<p-tag value="Private" severity="warn" />
|
|
175
|
+
} @else {
|
|
176
|
+
<p-tag value="Public" severity="success" />
|
|
177
|
+
}
|
|
178
|
+
</td>
|
|
179
|
+
<td class="hidden md:table-cell">{{ file.createdAt | date: 'short' }}</td>
|
|
180
|
+
<td>
|
|
181
|
+
<div class="flex gap-1">
|
|
182
|
+
<p-button *hasPermission="FILE_PERMISSIONS.READ" icon="pi pi-eye" [text]="true" severity="secondary" size="small" [loading]="viewingFileId() === file.id" [disabled]="viewingFileId() === file.id" (onClick)="onView(file)" pTooltip="View" tooltipPosition="top" />
|
|
183
|
+
<p-button *hasPermission="FILE_PERMISSIONS.UPDATE" icon="pi pi-pencil" [text]="true" severity="secondary" size="small" (onClick)="onEdit(file.id)" pTooltip="Edit" tooltipPosition="top" />
|
|
184
|
+
<p-button *hasPermission="FILE_PERMISSIONS.DELETE" icon="pi pi-trash" [text]="true" severity="warn" size="small" (onClick)="onSoftDelete(file)" pTooltip="Trash" tooltipPosition="top" />
|
|
185
|
+
<p-button *hasPermission="FILE_PERMISSIONS.DELETE" icon="pi pi-times-circle" [text]="true" severity="danger" size="small" (onClick)="onPermanentDelete(file)" pTooltip="Delete" tooltipPosition="top" />
|
|
186
|
+
</div>
|
|
187
|
+
</td>
|
|
188
|
+
</tr>
|
|
189
|
+
</ng-template>
|
|
190
|
+
<ng-template #emptymessage>
|
|
191
|
+
<tr>
|
|
192
|
+
<td colspan="8" class="text-center py-4 text-muted-color">
|
|
193
|
+
@if (showCompanyInfo()) {
|
|
194
|
+
No files found in current company
|
|
195
|
+
} @else {
|
|
196
|
+
No files found
|
|
197
|
+
}
|
|
198
|
+
</td>
|
|
199
|
+
</tr>
|
|
200
|
+
</ng-template>
|
|
201
|
+
</p-table>
|
|
202
|
+
</div>
|
|
203
|
+
</div>
|
|
204
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i1.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i2.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "component", type: i3.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "directive", type: i4.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "directive", type: HasPermissionDirective, selector: "[hasPermission]", inputs: ["hasPermission"] }, { kind: "pipe", type: i5.DatePipe, name: "date" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
205
|
+
}
|
|
206
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: FileManagerListComponent, decorators: [{
|
|
207
|
+
type: Component,
|
|
208
|
+
args: [{
|
|
209
|
+
selector: 'lib-file-manager-list',
|
|
210
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
211
|
+
imports: [AngularModule, PrimeModule, HasPermissionDirective],
|
|
212
|
+
template: `
|
|
213
|
+
<div class="card">
|
|
214
|
+
<div class="flex flex-col sm:flex-row sm:justify-between sm:items-center gap-3 mb-4">
|
|
215
|
+
<div>
|
|
216
|
+
<h3 class="text-lg sm:text-xl font-semibold">File Manager</h3>
|
|
217
|
+
@if (showCompanyInfo()) {
|
|
218
|
+
<p class="text-sm text-muted-color mt-1">
|
|
219
|
+
Company: {{ currentCompanyName() }}
|
|
220
|
+
</p>
|
|
221
|
+
}
|
|
222
|
+
</div>
|
|
223
|
+
<p-button *hasPermission="FILE_PERMISSIONS.CREATE" label="Upload File" icon="pi pi-upload" (onClick)="onUpload()" styleClass="w-full sm:w-auto" />
|
|
224
|
+
</div>
|
|
225
|
+
|
|
226
|
+
<div class="overflow-x-auto">
|
|
227
|
+
<p-table
|
|
228
|
+
[value]="files()"
|
|
229
|
+
[loading]="isLoading()"
|
|
230
|
+
[paginator]="totalRecords() > 0"
|
|
231
|
+
[rows]="pageSize()"
|
|
232
|
+
[totalRecords]="totalRecords()"
|
|
233
|
+
[lazy]="true"
|
|
234
|
+
(onLazyLoad)="onPageChange($event)"
|
|
235
|
+
[rowsPerPageOptions]="[10, 25, 50]"
|
|
236
|
+
[scrollable]="true"
|
|
237
|
+
styleClass="p-datatable-sm"
|
|
238
|
+
>
|
|
239
|
+
<ng-template #header>
|
|
240
|
+
<tr>
|
|
241
|
+
<th>Name</th>
|
|
242
|
+
<th class="hidden lg:table-cell">Type</th>
|
|
243
|
+
<th>Size</th>
|
|
244
|
+
<th>Location</th>
|
|
245
|
+
<th class="hidden xl:table-cell">Config</th>
|
|
246
|
+
<th>Private</th>
|
|
247
|
+
<th class="hidden md:table-cell">Created</th>
|
|
248
|
+
<th class="w-[120px]">Actions</th>
|
|
249
|
+
</tr>
|
|
250
|
+
</ng-template>
|
|
251
|
+
<ng-template #body let-file>
|
|
252
|
+
<tr>
|
|
253
|
+
<td>
|
|
254
|
+
<div class="flex items-center gap-2">
|
|
255
|
+
<i [class]="getFileIcon(file.contentType)"></i>
|
|
256
|
+
<span class="truncate max-w-32 sm:max-w-none">{{ file.name }}</span>
|
|
257
|
+
</div>
|
|
258
|
+
</td>
|
|
259
|
+
<td class="hidden lg:table-cell">
|
|
260
|
+
<span class="text-sm text-muted-color">{{ file.contentType }}</span>
|
|
261
|
+
</td>
|
|
262
|
+
<td>{{ file.size }} KB</td>
|
|
263
|
+
<td>
|
|
264
|
+
<p-tag [value]="getProviderLabel(file.location)" [severity]="getProviderSeverity(file.location)" />
|
|
265
|
+
</td>
|
|
266
|
+
<td class="hidden xl:table-cell">{{ file.providerName || '-' }}</td>
|
|
267
|
+
<td>
|
|
268
|
+
@if (file.isPrivate) {
|
|
269
|
+
<p-tag value="Private" severity="warn" />
|
|
270
|
+
} @else {
|
|
271
|
+
<p-tag value="Public" severity="success" />
|
|
272
|
+
}
|
|
273
|
+
</td>
|
|
274
|
+
<td class="hidden md:table-cell">{{ file.createdAt | date: 'short' }}</td>
|
|
275
|
+
<td>
|
|
276
|
+
<div class="flex gap-1">
|
|
277
|
+
<p-button *hasPermission="FILE_PERMISSIONS.READ" icon="pi pi-eye" [text]="true" severity="secondary" size="small" [loading]="viewingFileId() === file.id" [disabled]="viewingFileId() === file.id" (onClick)="onView(file)" pTooltip="View" tooltipPosition="top" />
|
|
278
|
+
<p-button *hasPermission="FILE_PERMISSIONS.UPDATE" icon="pi pi-pencil" [text]="true" severity="secondary" size="small" (onClick)="onEdit(file.id)" pTooltip="Edit" tooltipPosition="top" />
|
|
279
|
+
<p-button *hasPermission="FILE_PERMISSIONS.DELETE" icon="pi pi-trash" [text]="true" severity="warn" size="small" (onClick)="onSoftDelete(file)" pTooltip="Trash" tooltipPosition="top" />
|
|
280
|
+
<p-button *hasPermission="FILE_PERMISSIONS.DELETE" icon="pi pi-times-circle" [text]="true" severity="danger" size="small" (onClick)="onPermanentDelete(file)" pTooltip="Delete" tooltipPosition="top" />
|
|
281
|
+
</div>
|
|
282
|
+
</td>
|
|
283
|
+
</tr>
|
|
284
|
+
</ng-template>
|
|
285
|
+
<ng-template #emptymessage>
|
|
286
|
+
<tr>
|
|
287
|
+
<td colspan="8" class="text-center py-4 text-muted-color">
|
|
288
|
+
@if (showCompanyInfo()) {
|
|
289
|
+
No files found in current company
|
|
290
|
+
} @else {
|
|
291
|
+
No files found
|
|
292
|
+
}
|
|
293
|
+
</td>
|
|
294
|
+
</tr>
|
|
295
|
+
</ng-template>
|
|
296
|
+
</p-table>
|
|
297
|
+
</div>
|
|
298
|
+
</div>
|
|
299
|
+
`,
|
|
300
|
+
}]
|
|
301
|
+
}] });
|
|
302
|
+
|
|
303
|
+
export { FileManagerListComponent };
|
|
304
|
+
//# sourceMappingURL=flusys-ng-storage-file-manager-list.component-0O_b4EjN.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flusys-ng-storage-file-manager-list.component-0O_b4EjN.mjs","sources":["../../../projects/ng-storage/pages/file-manager/file-manager-list.component.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, inject, signal } from '@angular/core';\nimport { AngularModule, FILE_PERMISSIONS, HasPermissionDirective, PrimeModule } from '@flusys/ng-shared';\nimport { firstValueFrom } from 'rxjs';\nimport { IFileManager } from '../../interfaces/file-manager.interface';\nimport { FileManagerApiService } from '../../services/file-manager-api.service';\nimport { BaseStorageListPage } from '../../utils/base-storage-page';\nimport { getFileIcon, getProviderLabel, getProviderSeverity } from '../../utils/storage-utils';\n\n/**\n * File Manager List Component\n * Displays all files with company filter (if enabled)\n */\n@Component({\n selector: 'lib-file-manager-list',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [AngularModule, PrimeModule, HasPermissionDirective],\n template: `\n <div class=\"card\">\n <div class=\"flex flex-col sm:flex-row sm:justify-between sm:items-center gap-3 mb-4\">\n <div>\n <h3 class=\"text-lg sm:text-xl font-semibold\">File Manager</h3>\n @if (showCompanyInfo()) {\n <p class=\"text-sm text-muted-color mt-1\">\n Company: {{ currentCompanyName() }}\n </p>\n }\n </div>\n <p-button *hasPermission=\"FILE_PERMISSIONS.CREATE\" label=\"Upload File\" icon=\"pi pi-upload\" (onClick)=\"onUpload()\" styleClass=\"w-full sm:w-auto\" />\n </div>\n\n <div class=\"overflow-x-auto\">\n <p-table\n [value]=\"files()\"\n [loading]=\"isLoading()\"\n [paginator]=\"totalRecords() > 0\"\n [rows]=\"pageSize()\"\n [totalRecords]=\"totalRecords()\"\n [lazy]=\"true\"\n (onLazyLoad)=\"onPageChange($event)\"\n [rowsPerPageOptions]=\"[10, 25, 50]\"\n [scrollable]=\"true\"\n styleClass=\"p-datatable-sm\"\n >\n <ng-template #header>\n <tr>\n <th>Name</th>\n <th class=\"hidden lg:table-cell\">Type</th>\n <th>Size</th>\n <th>Location</th>\n <th class=\"hidden xl:table-cell\">Config</th>\n <th>Private</th>\n <th class=\"hidden md:table-cell\">Created</th>\n <th class=\"w-[120px]\">Actions</th>\n </tr>\n </ng-template>\n <ng-template #body let-file>\n <tr>\n <td>\n <div class=\"flex items-center gap-2\">\n <i [class]=\"getFileIcon(file.contentType)\"></i>\n <span class=\"truncate max-w-32 sm:max-w-none\">{{ file.name }}</span>\n </div>\n </td>\n <td class=\"hidden lg:table-cell\">\n <span class=\"text-sm text-muted-color\">{{ file.contentType }}</span>\n </td>\n <td>{{ file.size }} KB</td>\n <td>\n <p-tag [value]=\"getProviderLabel(file.location)\" [severity]=\"getProviderSeverity(file.location)\" />\n </td>\n <td class=\"hidden xl:table-cell\">{{ file.providerName || '-' }}</td>\n <td>\n @if (file.isPrivate) {\n <p-tag value=\"Private\" severity=\"warn\" />\n } @else {\n <p-tag value=\"Public\" severity=\"success\" />\n }\n </td>\n <td class=\"hidden md:table-cell\">{{ file.createdAt | date: 'short' }}</td>\n <td>\n <div class=\"flex gap-1\">\n <p-button *hasPermission=\"FILE_PERMISSIONS.READ\" icon=\"pi pi-eye\" [text]=\"true\" severity=\"secondary\" size=\"small\" [loading]=\"viewingFileId() === file.id\" [disabled]=\"viewingFileId() === file.id\" (onClick)=\"onView(file)\" pTooltip=\"View\" tooltipPosition=\"top\" />\n <p-button *hasPermission=\"FILE_PERMISSIONS.UPDATE\" icon=\"pi pi-pencil\" [text]=\"true\" severity=\"secondary\" size=\"small\" (onClick)=\"onEdit(file.id)\" pTooltip=\"Edit\" tooltipPosition=\"top\" />\n <p-button *hasPermission=\"FILE_PERMISSIONS.DELETE\" icon=\"pi pi-trash\" [text]=\"true\" severity=\"warn\" size=\"small\" (onClick)=\"onSoftDelete(file)\" pTooltip=\"Trash\" tooltipPosition=\"top\" />\n <p-button *hasPermission=\"FILE_PERMISSIONS.DELETE\" icon=\"pi pi-times-circle\" [text]=\"true\" severity=\"danger\" size=\"small\" (onClick)=\"onPermanentDelete(file)\" pTooltip=\"Delete\" tooltipPosition=\"top\" />\n </div>\n </td>\n </tr>\n </ng-template>\n <ng-template #emptymessage>\n <tr>\n <td colspan=\"8\" class=\"text-center py-4 text-muted-color\">\n @if (showCompanyInfo()) {\n No files found in current company\n } @else {\n No files found\n }\n </td>\n </tr>\n </ng-template>\n </p-table>\n </div>\n </div>\n `,\n})\nexport class FileManagerListComponent extends BaseStorageListPage<IFileManager> {\n // Permission constants for template\n readonly FILE_PERMISSIONS = FILE_PERMISSIONS;\n\n private readonly fileService = inject(FileManagerApiService);\n\n /** Files list alias for template compatibility */\n readonly files = this.items;\n\n /** ID of file currently being viewed (null when not viewing) */\n readonly viewingFileId = signal<string | null>(null);\n\n /** Utility functions exposed to template */\n readonly getFileIcon = getFileIcon;\n readonly getProviderLabel = getProviderLabel;\n readonly getProviderSeverity = getProviderSeverity;\n\n getResourceRoute(): string {\n return '/storage/files';\n }\n\n override getDeleteConfirmMessage(file: IFileManager): string {\n return `Are you sure you want to delete \"${file.name}\"?`;\n }\n\n async loadData(): Promise<void> {\n this.isLoading.set(true);\n try {\n const response = await firstValueFrom(\n this.fileService.getAll('', {\n pagination: this.getPaginationParams(),\n filter: {},\n select: [],\n sort: {},\n }),\n );\n\n if (response.success) {\n this.items.set(response.data ?? []);\n this.total.set(response.meta?.total ?? 0);\n }\n } catch {\n this.showError('Failed to load files.');\n } finally {\n this.isLoading.set(false);\n }\n }\n\n onUpload(): void {\n this.navigateTo(['/storage/files/new']);\n }\n\n async onView(file: IFileManager): Promise<void> {\n this.viewingFileId.set(file.id);\n try {\n const response = await firstValueFrom(this.fileService.getFiles([file.id]));\n\n // Response type is ISingleResponse<IFilesResponseDto[]>\n if (response.success && response.data?.length && response.data[0].url) {\n window.open(response.data[0].url, '_blank');\n } else {\n this.showError('File URL is not available.');\n }\n } catch {\n this.showError('Failed to get file URL.');\n } finally {\n this.viewingFileId.set(null);\n }\n }\n\n onSoftDelete(file: IFileManager): void {\n this.confirmationService.confirm({\n message: `Move \"${file.name}\" to trash? You can recover it later.`,\n header: 'Move to Trash',\n icon: 'pi pi-trash',\n acceptLabel: 'Move to Trash',\n acceptButtonStyleClass: 'p-button-warning',\n accept: async () => {\n try {\n await this.fileService.deleteAsync({ id: file.id, type: 'delete' });\n this.showSuccess('File moved to trash successfully.');\n this.loadData();\n } catch {\n this.showError('Failed to move file to trash.');\n }\n },\n });\n }\n\n onPermanentDelete(file: IFileManager): void {\n this.confirmationService.confirm({\n message: `Permanently delete \"${file.name}\"? This action CANNOT be undone and will delete the file from storage.`,\n header: 'Permanent Delete',\n icon: 'pi pi-exclamation-triangle',\n acceptLabel: 'Delete Permanently',\n rejectLabel: 'Cancel',\n acceptButtonStyleClass: 'p-button-danger',\n accept: async () => {\n try {\n await this.fileService.deleteAsync({ id: file.id, type: 'permanent' });\n this.showSuccess('File permanently deleted.');\n this.loadData();\n } catch {\n this.showError('Failed to permanently delete file.');\n }\n },\n });\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, signal, computed, effect, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import { toSignal } from '@angular/core/rxjs-interop';
|
|
4
|
+
import { form, required, FormField } from '@angular/forms/signals';
|
|
5
|
+
import { ActivatedRoute } from '@angular/router';
|
|
6
|
+
import { AngularModule, PrimeModule } from '@flusys/ng-shared';
|
|
7
|
+
import { BaseStoragePage, FolderApiService } from './flusys-ng-storage.mjs';
|
|
8
|
+
import * as i1 from '@angular/forms';
|
|
9
|
+
import * as i1$1 from 'primeng/button';
|
|
10
|
+
import * as i3 from 'primeng/inputtext';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Folder Form Component
|
|
14
|
+
* Create and edit folders
|
|
15
|
+
*/
|
|
16
|
+
class FolderFormComponent extends BaseStoragePage {
|
|
17
|
+
route = inject(ActivatedRoute);
|
|
18
|
+
folderService = inject(FolderApiService);
|
|
19
|
+
// Route params as signal
|
|
20
|
+
routeParams = toSignal(this.route.paramMap);
|
|
21
|
+
initialized = false;
|
|
22
|
+
/** Existing folder for edit mode */
|
|
23
|
+
existingFolder = signal(null, ...(ngDevMode ? [{ debugName: "existingFolder" }] : []));
|
|
24
|
+
/** Check if in edit mode */
|
|
25
|
+
isEditMode = computed(() => !!this.existingFolder(), ...(ngDevMode ? [{ debugName: "isEditMode" }] : []));
|
|
26
|
+
/** Form model */
|
|
27
|
+
formModel = signal({
|
|
28
|
+
id: '',
|
|
29
|
+
name: '',
|
|
30
|
+
}, ...(ngDevMode ? [{ debugName: "formModel" }] : []));
|
|
31
|
+
/** Form with validation */
|
|
32
|
+
folderForm = form(this.formModel, (f) => {
|
|
33
|
+
required(f.name, { message: 'Folder name is required' });
|
|
34
|
+
});
|
|
35
|
+
/** Check if form is valid */
|
|
36
|
+
isFormValid = computed(() => this.formModel().name.trim().length > 0, ...(ngDevMode ? [{ debugName: "isFormValid" }] : []));
|
|
37
|
+
constructor() {
|
|
38
|
+
super();
|
|
39
|
+
// Effect to handle route-based initialization
|
|
40
|
+
effect(() => {
|
|
41
|
+
const params = this.routeParams();
|
|
42
|
+
if (!params || this.initialized)
|
|
43
|
+
return;
|
|
44
|
+
this.initialized = true;
|
|
45
|
+
const folderId = params.get('id');
|
|
46
|
+
if (folderId && folderId !== 'new') {
|
|
47
|
+
this.loadFolder(folderId);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
async loadFolder(id) {
|
|
52
|
+
this.isLoading.set(true);
|
|
53
|
+
try {
|
|
54
|
+
const response = await this.folderService.findByIdAsync(id);
|
|
55
|
+
if (response.success && response.data) {
|
|
56
|
+
const folder = response.data;
|
|
57
|
+
this.existingFolder.set(folder);
|
|
58
|
+
this.formModel.set({ id: folder.id, name: folder.name });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
this.showError('Failed to load folder.');
|
|
63
|
+
this.navigateTo(['/storage/folders']);
|
|
64
|
+
}
|
|
65
|
+
finally {
|
|
66
|
+
this.isLoading.set(false);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
async onSubmit() {
|
|
70
|
+
if (!this.isFormValid())
|
|
71
|
+
return;
|
|
72
|
+
this.isLoading.set(true);
|
|
73
|
+
try {
|
|
74
|
+
const formValue = this.formModel();
|
|
75
|
+
if (this.isEditMode()) {
|
|
76
|
+
await this.folderService.updateAsync({ id: formValue.id, name: formValue.name });
|
|
77
|
+
this.showSuccess('Folder updated successfully.');
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
await this.folderService.insertAsync({ name: formValue.name });
|
|
81
|
+
this.showSuccess('Folder created successfully.');
|
|
82
|
+
}
|
|
83
|
+
this.navigateTo(['/storage/folders']);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
this.showError(`Failed to ${this.isEditMode() ? 'update' : 'create'} folder.`);
|
|
87
|
+
}
|
|
88
|
+
finally {
|
|
89
|
+
this.isLoading.set(false);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
onCancel() {
|
|
93
|
+
this.navigateTo(['/storage/folders']);
|
|
94
|
+
}
|
|
95
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: FolderFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
96
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", type: FolderFormComponent, isStandalone: true, selector: "lib-folder-form", usesInheritance: true, ngImport: i0, template: `
|
|
97
|
+
<div class="card">
|
|
98
|
+
<div class="mb-4">
|
|
99
|
+
<h3 class="text-lg sm:text-xl font-semibold">{{ isEditMode() ? 'Edit Folder' : 'New Folder' }}</h3>
|
|
100
|
+
@if (showCompanyInfo()) {
|
|
101
|
+
<p class="text-sm text-muted-color mt-1">Company: {{ currentCompanyName() }}</p>
|
|
102
|
+
}
|
|
103
|
+
</div>
|
|
104
|
+
|
|
105
|
+
<form (ngSubmit)="onSubmit()">
|
|
106
|
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
107
|
+
<div class="field">
|
|
108
|
+
<label for="name" class="block font-medium mb-2 text-sm sm:text-base">Folder Name *</label>
|
|
109
|
+
<input pInputText id="name" [formField]="folderForm.name" placeholder="Enter folder name" class="w-full" />
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
|
|
113
|
+
<div class="flex justify-end gap-2 mt-4">
|
|
114
|
+
<p-button label="Cancel" severity="secondary" [outlined]="true" (onClick)="onCancel()" />
|
|
115
|
+
<p-button type="submit" [label]="isEditMode() ? 'Update' : 'Create'" [loading]="isLoading()" [disabled]="!isFormValid() || isLoading()" />
|
|
116
|
+
</div>
|
|
117
|
+
</form>
|
|
118
|
+
</div>
|
|
119
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i3.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
120
|
+
}
|
|
121
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: FolderFormComponent, decorators: [{
|
|
122
|
+
type: Component,
|
|
123
|
+
args: [{
|
|
124
|
+
selector: 'lib-folder-form',
|
|
125
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
126
|
+
imports: [AngularModule, PrimeModule, FormField],
|
|
127
|
+
template: `
|
|
128
|
+
<div class="card">
|
|
129
|
+
<div class="mb-4">
|
|
130
|
+
<h3 class="text-lg sm:text-xl font-semibold">{{ isEditMode() ? 'Edit Folder' : 'New Folder' }}</h3>
|
|
131
|
+
@if (showCompanyInfo()) {
|
|
132
|
+
<p class="text-sm text-muted-color mt-1">Company: {{ currentCompanyName() }}</p>
|
|
133
|
+
}
|
|
134
|
+
</div>
|
|
135
|
+
|
|
136
|
+
<form (ngSubmit)="onSubmit()">
|
|
137
|
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
138
|
+
<div class="field">
|
|
139
|
+
<label for="name" class="block font-medium mb-2 text-sm sm:text-base">Folder Name *</label>
|
|
140
|
+
<input pInputText id="name" [formField]="folderForm.name" placeholder="Enter folder name" class="w-full" />
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
|
|
144
|
+
<div class="flex justify-end gap-2 mt-4">
|
|
145
|
+
<p-button label="Cancel" severity="secondary" [outlined]="true" (onClick)="onCancel()" />
|
|
146
|
+
<p-button type="submit" [label]="isEditMode() ? 'Update' : 'Create'" [loading]="isLoading()" [disabled]="!isFormValid() || isLoading()" />
|
|
147
|
+
</div>
|
|
148
|
+
</form>
|
|
149
|
+
</div>
|
|
150
|
+
`,
|
|
151
|
+
}]
|
|
152
|
+
}], ctorParameters: () => [] });
|
|
153
|
+
|
|
154
|
+
export { FolderFormComponent };
|
|
155
|
+
//# sourceMappingURL=flusys-ng-storage-folder-form.component-BTQGEqNu.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flusys-ng-storage-folder-form.component-BTQGEqNu.mjs","sources":["../../../projects/ng-storage/pages/folder/folder-form.component.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, effect, inject, signal } from '@angular/core';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { form, FormField, required } from '@angular/forms/signals';\nimport { ActivatedRoute } from '@angular/router';\nimport { AngularModule, PrimeModule } from '@flusys/ng-shared';\nimport { IFolder } from '../../interfaces/folder.interface';\nimport { FolderApiService } from '../../services/folder-api.service';\nimport { BaseStoragePage } from '../../utils/base-storage-page';\n\n/** Folder form model interface */\ninterface IFolderFormModel {\n id: string;\n name: string;\n}\n\n/**\n * Folder Form Component\n * Create and edit folders\n */\n@Component({\n selector: 'lib-folder-form',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [AngularModule, PrimeModule, FormField],\n template: `\n <div class=\"card\">\n <div class=\"mb-4\">\n <h3 class=\"text-lg sm:text-xl font-semibold\">{{ isEditMode() ? 'Edit Folder' : 'New Folder' }}</h3>\n @if (showCompanyInfo()) {\n <p class=\"text-sm text-muted-color mt-1\">Company: {{ currentCompanyName() }}</p>\n }\n </div>\n\n <form (ngSubmit)=\"onSubmit()\">\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div class=\"field\">\n <label for=\"name\" class=\"block font-medium mb-2 text-sm sm:text-base\">Folder Name *</label>\n <input pInputText id=\"name\" [formField]=\"folderForm.name\" placeholder=\"Enter folder name\" class=\"w-full\" />\n </div>\n </div>\n\n <div class=\"flex justify-end gap-2 mt-4\">\n <p-button label=\"Cancel\" severity=\"secondary\" [outlined]=\"true\" (onClick)=\"onCancel()\" />\n <p-button type=\"submit\" [label]=\"isEditMode() ? 'Update' : 'Create'\" [loading]=\"isLoading()\" [disabled]=\"!isFormValid() || isLoading()\" />\n </div>\n </form>\n </div>\n `,\n})\nexport class FolderFormComponent extends BaseStoragePage {\n private readonly route = inject(ActivatedRoute);\n private readonly folderService = inject(FolderApiService);\n\n // Route params as signal\n private readonly routeParams = toSignal(this.route.paramMap);\n private initialized = false;\n\n /** Existing folder for edit mode */\n readonly existingFolder = signal<IFolder | null>(null);\n\n /** Check if in edit mode */\n readonly isEditMode = computed(() => !!this.existingFolder());\n\n /** Form model */\n readonly formModel = signal<IFolderFormModel>({\n id: '',\n name: '',\n });\n\n /** Form with validation */\n readonly folderForm = form(this.formModel, (f) => {\n required(f.name, { message: 'Folder name is required' });\n });\n\n /** Check if form is valid */\n readonly isFormValid = computed(() => this.formModel().name.trim().length > 0);\n\n constructor() {\n super();\n // Effect to handle route-based initialization\n effect(() => {\n const params = this.routeParams();\n if (!params || this.initialized) return;\n\n this.initialized = true;\n const folderId = params.get('id');\n if (folderId && folderId !== 'new') {\n this.loadFolder(folderId);\n }\n });\n }\n\n async loadFolder(id: string): Promise<void> {\n this.isLoading.set(true);\n try {\n const response = await this.folderService.findByIdAsync(id);\n if (response.success && response.data) {\n const folder = response.data;\n this.existingFolder.set(folder);\n this.formModel.set({ id: folder.id, name: folder.name });\n }\n } catch {\n this.showError('Failed to load folder.');\n this.navigateTo(['/storage/folders']);\n } finally {\n this.isLoading.set(false);\n }\n }\n\n async onSubmit(): Promise<void> {\n if (!this.isFormValid()) return;\n\n this.isLoading.set(true);\n try {\n const formValue = this.formModel();\n\n if (this.isEditMode()) {\n await this.folderService.updateAsync({ id: formValue.id, name: formValue.name });\n this.showSuccess('Folder updated successfully.');\n } else {\n await this.folderService.insertAsync({ name: formValue.name });\n this.showSuccess('Folder created successfully.');\n }\n\n this.navigateTo(['/storage/folders']);\n } catch {\n this.showError(`Failed to ${this.isEditMode() ? 'update' : 'create'} folder.`);\n } finally {\n this.isLoading.set(false);\n }\n }\n\n onCancel(): void {\n this.navigateTo(['/storage/folders']);\n }\n}\n"],"names":["i2"],"mappings":"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"}
|