@endora-commerce/mod-assets-library 0.0.0-stage → 0.100.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/LICENSE +21 -0
- package/README.md +61 -2
- package/dist/admin/api/assets-library-client.d.ts +29 -0
- package/dist/admin/api/assets-library-client.d.ts.map +1 -0
- package/dist/admin/api/assets-library-client.js +70 -0
- package/dist/admin/api/assets-library-client.js.map +1 -0
- package/dist/admin/components/AssetDetailDrawer.d.ts +8 -0
- package/dist/admin/components/AssetDetailDrawer.d.ts.map +1 -0
- package/dist/admin/components/AssetDetailDrawer.js +96 -0
- package/dist/admin/components/AssetDetailDrawer.js.map +1 -0
- package/dist/admin/components/FolderTree.d.ts +13 -0
- package/dist/admin/components/FolderTree.d.ts.map +1 -0
- package/dist/admin/components/FolderTree.js +71 -0
- package/dist/admin/components/FolderTree.js.map +1 -0
- package/dist/admin/index.d.ts +44 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +46 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/pages/LibraryPage.d.ts +9 -0
- package/dist/admin/pages/LibraryPage.d.ts.map +1 -0
- package/dist/admin/pages/LibraryPage.js +163 -0
- package/dist/admin/pages/LibraryPage.js.map +1 -0
- package/dist/backend/entities/asset-folder.entity.d.ts +16 -0
- package/dist/backend/entities/asset-folder.entity.d.ts.map +1 -0
- package/dist/backend/entities/asset-folder.entity.js +57 -0
- package/dist/backend/entities/asset-folder.entity.js.map +1 -0
- package/dist/backend/entities/asset.entity.d.ts +38 -0
- package/dist/backend/entities/asset.entity.d.ts.map +1 -0
- package/dist/backend/entities/asset.entity.js +128 -0
- package/dist/backend/entities/asset.entity.js.map +1 -0
- package/dist/backend/index.d.ts +57 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +150 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/jobs/hard-delete-asset.job.d.ts +18 -0
- package/dist/backend/jobs/hard-delete-asset.job.d.ts.map +1 -0
- package/dist/backend/jobs/hard-delete-asset.job.js +91 -0
- package/dist/backend/jobs/hard-delete-asset.job.js.map +1 -0
- package/dist/backend/plugin.d.ts +47 -0
- package/dist/backend/plugin.d.ts.map +1 -0
- package/dist/backend/plugin.js +96 -0
- package/dist/backend/plugin.js.map +1 -0
- package/dist/backend/routes.admin.d.ts +15 -0
- package/dist/backend/routes.admin.d.ts.map +1 -0
- package/dist/backend/routes.admin.js +189 -0
- package/dist/backend/routes.admin.js.map +1 -0
- package/dist/backend/routes.public.d.ts +14 -0
- package/dist/backend/routes.public.d.ts.map +1 -0
- package/dist/backend/routes.public.js +99 -0
- package/dist/backend/routes.public.js.map +1 -0
- package/dist/backend/services/asset-read-port.d.ts +103 -0
- package/dist/backend/services/asset-read-port.d.ts.map +1 -0
- package/dist/backend/services/asset-read-port.js +167 -0
- package/dist/backend/services/asset-read-port.js.map +1 -0
- package/dist/backend/services/assets-library.service.d.ts +76 -0
- package/dist/backend/services/assets-library.service.d.ts.map +1 -0
- package/dist/backend/services/assets-library.service.js +261 -0
- package/dist/backend/services/assets-library.service.js.map +1 -0
- package/dist/backend/services/cms-body-resolver.d.ts +6 -0
- package/dist/backend/services/cms-body-resolver.d.ts.map +1 -0
- package/dist/backend/services/cms-body-resolver.js +44 -0
- package/dist/backend/services/cms-body-resolver.js.map +1 -0
- package/dist/backend/services/folders.service.d.ts +29 -0
- package/dist/backend/services/folders.service.d.ts.map +1 -0
- package/dist/backend/services/folders.service.js +231 -0
- package/dist/backend/services/folders.service.js.map +1 -0
- package/dist/backend/services/hmac.d.ts +28 -0
- package/dist/backend/services/hmac.d.ts.map +1 -0
- package/dist/backend/services/hmac.js +50 -0
- package/dist/backend/services/hmac.js.map +1 -0
- package/dist/backend/services/reference-registry.d.ts +36 -0
- package/dist/backend/services/reference-registry.d.ts.map +1 -0
- package/dist/backend/services/reference-registry.js +63 -0
- package/dist/backend/services/reference-registry.js.map +1 -0
- package/dist/backend/services/storage/adapter-registry.d.ts +77 -0
- package/dist/backend/services/storage/adapter-registry.d.ts.map +1 -0
- package/dist/backend/services/storage/adapter-registry.js +95 -0
- package/dist/backend/services/storage/adapter-registry.js.map +1 -0
- package/dist/backend/services/storage/errors.d.ts +18 -0
- package/dist/backend/services/storage/errors.d.ts.map +1 -0
- package/dist/backend/services/storage/errors.js +30 -0
- package/dist/backend/services/storage/errors.js.map +1 -0
- package/dist/backend/services/storage/gcs-adapter.d.ts +42 -0
- package/dist/backend/services/storage/gcs-adapter.d.ts.map +1 -0
- package/dist/backend/services/storage/gcs-adapter.js +106 -0
- package/dist/backend/services/storage/gcs-adapter.js.map +1 -0
- package/dist/backend/services/storage/legacy-resolver.d.ts +15 -0
- package/dist/backend/services/storage/legacy-resolver.d.ts.map +1 -0
- package/dist/backend/services/storage/legacy-resolver.js +32 -0
- package/dist/backend/services/storage/legacy-resolver.js.map +1 -0
- package/dist/backend/services/storage/local-fs-adapter.d.ts +59 -0
- package/dist/backend/services/storage/local-fs-adapter.d.ts.map +1 -0
- package/dist/backend/services/storage/local-fs-adapter.js +153 -0
- package/dist/backend/services/storage/local-fs-adapter.js.map +1 -0
- package/dist/backend/services/storage/locator.d.ts +5 -0
- package/dist/backend/services/storage/locator.d.ts.map +1 -0
- package/dist/backend/services/storage/locator.js +16 -0
- package/dist/backend/services/storage/locator.js.map +1 -0
- package/dist/backend/services/storage/object-storage-port.d.ts +46 -0
- package/dist/backend/services/storage/object-storage-port.d.ts.map +1 -0
- package/dist/backend/services/storage/object-storage-port.js +78 -0
- package/dist/backend/services/storage/object-storage-port.js.map +1 -0
- package/dist/backend/services/storage/public-url-base.d.ts +50 -0
- package/dist/backend/services/storage/public-url-base.d.ts.map +1 -0
- package/dist/backend/services/storage/public-url-base.js +70 -0
- package/dist/backend/services/storage/public-url-base.js.map +1 -0
- package/dist/backend/services/storage/s3-adapter.d.ts +50 -0
- package/dist/backend/services/storage/s3-adapter.d.ts.map +1 -0
- package/dist/backend/services/storage/s3-adapter.js +110 -0
- package/dist/backend/services/storage/s3-adapter.js.map +1 -0
- package/dist/backend/services/storage/settings-view.d.ts +4 -0
- package/dist/backend/services/storage/settings-view.d.ts.map +1 -0
- package/dist/backend/services/storage/settings-view.js +73 -0
- package/dist/backend/services/storage/settings-view.js.map +1 -0
- package/dist/backend/services/storage/storage-adapter.d.ts +62 -0
- package/dist/backend/services/storage/storage-adapter.d.ts.map +1 -0
- package/dist/backend/services/storage/storage-adapter.js +10 -0
- package/dist/backend/services/storage/storage-adapter.js.map +1 -0
- package/dist/backend/services/upload-pipeline.d.ts +41 -0
- package/dist/backend/services/upload-pipeline.d.ts.map +1 -0
- package/dist/backend/services/upload-pipeline.js +231 -0
- package/dist/backend/services/upload-pipeline.js.map +1 -0
- package/dist/manifest.d.ts +185 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +229 -0
- package/dist/manifest.js.map +1 -0
- package/dist/migrations/20260505T102206_assets_library_init.d.ts +35 -0
- package/dist/migrations/20260505T102206_assets_library_init.d.ts.map +1 -0
- package/dist/migrations/20260505T102206_assets_library_init.js +132 -0
- package/dist/migrations/20260505T102206_assets_library_init.js.map +1 -0
- package/dist/migrations/index.d.ts +27 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +29 -0
- package/dist/migrations/index.js.map +1 -0
- package/docs/assets-library/index.md +125 -0
- package/i18n/en.json +54 -0
- package/i18n/pl.json +54 -0
- package/package.json +99 -3
- package/tailwind.css +14 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Endora sp. z o.o. and the Endora Commerce contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,62 @@
|
|
|
1
|
-
|
|
1
|
+
<!-- Generated by `pnpm --filter backend run manifests:generate`. Delete this line to take the file over; a README without it is never regenerated. -->
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# @endora-commerce/mod-assets-library
|
|
4
|
+
|
|
5
|
+
Storage adapter registry (local / S3 / GCS), asset upload, and reference tracking.
|
|
6
|
+
|
|
7
|
+
## What this is
|
|
8
|
+
|
|
9
|
+
An **Endora Commerce module package**. Its module id is `assets_library` — the identity of record in the platform's registries, in its migrations and in its setting, permission and translation codes.
|
|
10
|
+
|
|
11
|
+
A module is not imported by application code. The platform discovers the extension packages an instance has installed, reads the manifest on the root subpath and composes the module from it, so installing this package and starting the instance is the whole integration.
|
|
12
|
+
|
|
13
|
+
## Entry points
|
|
14
|
+
|
|
15
|
+
| Import | Contents |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| `@endora-commerce/mod-assets-library` | the module manifest — its id, version, dependencies, settings and activation |
|
|
18
|
+
| `@endora-commerce/mod-assets-library/admin` | the Admin UI contribution: the screens, navigation and palette actions it adds |
|
|
19
|
+
| `@endora-commerce/mod-assets-library/backend` | the composition root the platform calls, with the entities, services, routes and workers it registers |
|
|
20
|
+
| `@endora-commerce/mod-assets-library/migrations` | the module’s own schema migrations, in the order the platform runs them |
|
|
21
|
+
| `@endora-commerce/mod-assets-library/tailwind.css` | the Tailwind source declaration for the admin code above |
|
|
22
|
+
|
|
23
|
+
## Depends on
|
|
24
|
+
|
|
25
|
+
Everything below is a **peer** dependency, so the application resolves exactly one copy of each — two copies of a host or of React are a runtime failure rather than a type error. An entry marked *optional* is needed only by the layers that use it.
|
|
26
|
+
|
|
27
|
+
**Endora packages**
|
|
28
|
+
|
|
29
|
+
- `@endora-commerce/admin-kit` — *optional*
|
|
30
|
+
- `@endora-commerce/contracts`
|
|
31
|
+
- `@endora-commerce/platform`
|
|
32
|
+
|
|
33
|
+
**Third-party**
|
|
34
|
+
|
|
35
|
+
- `@aws-sdk/client-s3` ^3
|
|
36
|
+
- `@aws-sdk/s3-request-presigner` ^3
|
|
37
|
+
- `@fastify/multipart` ^10
|
|
38
|
+
- `@google-cloud/storage` ^7
|
|
39
|
+
- `@mikro-orm/core` ^6
|
|
40
|
+
- `@mikro-orm/migrations` ^6
|
|
41
|
+
- `@mikro-orm/postgresql` ^6
|
|
42
|
+
- `fastify` ^5
|
|
43
|
+
- `file-type` ^22
|
|
44
|
+
- `lucide-react` ^1 — *optional*
|
|
45
|
+
- `react` ^19 — *optional*
|
|
46
|
+
|
|
47
|
+
## What the tarball carries
|
|
48
|
+
|
|
49
|
+
- `dist/` — the compiled JavaScript and its type declarations
|
|
50
|
+
- `i18n/` — the translation bundles this package ships (`en`, `pl`), loaded by the platform
|
|
51
|
+
- `docs/` — the package’s own pages in the Endora Commerce documentation site
|
|
52
|
+
- `tailwind.css` — the Tailwind source declaration
|
|
53
|
+
|
|
54
|
+
## Install
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pnpm add @endora-commerce/mod-assets-library
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Licence
|
|
61
|
+
|
|
62
|
+
MIT — the text is in `LICENSE`, beside this file.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { AssetDetail, AssetFolder, AssetSummary, CreateFolderRequest, DeleteFolderRequest, ListAssetsResponse, PatchAssetRequest, PatchFolderRequest } from '@endora-commerce/contracts';
|
|
2
|
+
export type { AssetSummary, AssetDetail, AssetFolder };
|
|
3
|
+
export declare const assetsLibraryClient: {
|
|
4
|
+
listAssets(query: {
|
|
5
|
+
folderId?: string | null;
|
|
6
|
+
q?: string;
|
|
7
|
+
mime?: string;
|
|
8
|
+
visibility?: "public" | "private";
|
|
9
|
+
cursor?: string;
|
|
10
|
+
limit?: number;
|
|
11
|
+
}): Promise<ListAssetsResponse>;
|
|
12
|
+
getAsset(id: string): Promise<AssetDetail>;
|
|
13
|
+
getAssetUrl(id: string): Promise<{
|
|
14
|
+
url: string;
|
|
15
|
+
expiresAt: string | null;
|
|
16
|
+
}>;
|
|
17
|
+
patchAsset(id: string, patch: PatchAssetRequest): Promise<AssetDetail>;
|
|
18
|
+
softDeleteAsset(id: string): Promise<void>;
|
|
19
|
+
restoreAsset(id: string): Promise<AssetDetail>;
|
|
20
|
+
moveAsset(id: string, folderId: string | null): Promise<AssetDetail>;
|
|
21
|
+
listFolders(): Promise<AssetFolder[]>;
|
|
22
|
+
createFolder(req: CreateFolderRequest): Promise<AssetFolder>;
|
|
23
|
+
patchFolder(id: string, req: PatchFolderRequest): Promise<AssetFolder>;
|
|
24
|
+
deleteFolder(id: string, req: DeleteFolderRequest): Promise<{
|
|
25
|
+
deletedFolderId: string;
|
|
26
|
+
softDeletedAssetIds?: string[];
|
|
27
|
+
}>;
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=assets-library-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assets-library-client.d.ts","sourceRoot":"","sources":["../../../src/admin/api/assets-library-client.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EACX,YAAY,EACZ,mBAAmB,EACnB,mBAAmB,EACnB,kBAAkB,EAElB,iBAAiB,EACjB,kBAAkB,EACnB,MAAM,4BAA4B,CAAC;AAEpC,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC;AAEvD,eAAO,MAAM,mBAAmB;sBACN;QACtB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,CAAC,CAAC,EAAE,MAAM,CAAC;QACX,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,UAAU,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;QAClC,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,GAAG,OAAO,CAAC,kBAAkB,CAAC;iBAgBZ,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;oBAO1B,MAAM,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;mBAO5D,MAAM,SAAS,iBAAiB,GAAG,OAAO,CAAC,WAAW,CAAC;wBAQlD,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;qBAIzB,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;kBAQhC,MAAM,YAAY,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC;mBAUrD,OAAO,CAAC,WAAW,EAAE,CAAC;sBAOnB,mBAAmB,GAAG,OAAO,CAAC,WAAW,CAAC;oBAQ5C,MAAM,OAAO,kBAAkB,GAAG,OAAO,CAAC,WAAW,CAAC;qBAStE,MAAM,OACL,mBAAmB,GACvB,OAAO,CAAC;QAAE,eAAe,EAAE,MAAM,CAAC;QAAC,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CASxE,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// Typed admin client for the Assets Library — feature 013 / US1.
|
|
2
|
+
//
|
|
3
|
+
// Wraps the shared `apiClient` with strong response types inferred from
|
|
4
|
+
// `@endora-commerce/contracts/assets-library`. Components consume this rather than
|
|
5
|
+
// touching `apiClient` directly.
|
|
6
|
+
import { apiClient } from '@endora-commerce/admin-kit/lib';
|
|
7
|
+
export const assetsLibraryClient = {
|
|
8
|
+
async listAssets(query) {
|
|
9
|
+
const params = new URLSearchParams();
|
|
10
|
+
if (query.folderId !== undefined && query.folderId !== null) {
|
|
11
|
+
params.set('folderId', query.folderId);
|
|
12
|
+
}
|
|
13
|
+
if (query.q)
|
|
14
|
+
params.set('q', query.q);
|
|
15
|
+
if (query.mime)
|
|
16
|
+
params.set('mime', query.mime);
|
|
17
|
+
if (query.visibility)
|
|
18
|
+
params.set('visibility', query.visibility);
|
|
19
|
+
if (query.cursor)
|
|
20
|
+
params.set('cursor', query.cursor);
|
|
21
|
+
if (query.limit !== undefined)
|
|
22
|
+
params.set('limit', String(query.limit));
|
|
23
|
+
const qs = params.toString();
|
|
24
|
+
return apiClient.get(`/api/v1/admin/assets${qs ? `?${qs}` : ''}`);
|
|
25
|
+
},
|
|
26
|
+
async getAsset(id) {
|
|
27
|
+
const out = await apiClient.get(`/api/v1/admin/assets/${id}`);
|
|
28
|
+
return out.data;
|
|
29
|
+
},
|
|
30
|
+
async getAssetUrl(id) {
|
|
31
|
+
const out = await apiClient.get(`/api/v1/admin/assets/${id}/url`);
|
|
32
|
+
return out.data;
|
|
33
|
+
},
|
|
34
|
+
async patchAsset(id, patch) {
|
|
35
|
+
const out = await apiClient.patch(`/api/v1/admin/assets/${id}`, patch);
|
|
36
|
+
return out.data;
|
|
37
|
+
},
|
|
38
|
+
async softDeleteAsset(id) {
|
|
39
|
+
await apiClient.delete(`/api/v1/admin/assets/${id}`);
|
|
40
|
+
},
|
|
41
|
+
async restoreAsset(id) {
|
|
42
|
+
const out = await apiClient.post(`/api/v1/admin/assets/${id}/restore`, {});
|
|
43
|
+
return out.data;
|
|
44
|
+
},
|
|
45
|
+
async moveAsset(id, folderId) {
|
|
46
|
+
const out = await apiClient.post(`/api/v1/admin/assets/${id}/move`, { folderId });
|
|
47
|
+
return out.data;
|
|
48
|
+
},
|
|
49
|
+
// — Folders --------------------------------------------------------------
|
|
50
|
+
async listFolders() {
|
|
51
|
+
const out = await apiClient.get('/api/v1/admin/assets/folders');
|
|
52
|
+
return out.data;
|
|
53
|
+
},
|
|
54
|
+
async createFolder(req) {
|
|
55
|
+
const out = await apiClient.post('/api/v1/admin/assets/folders', req);
|
|
56
|
+
return out.data;
|
|
57
|
+
},
|
|
58
|
+
async patchFolder(id, req) {
|
|
59
|
+
const out = await apiClient.patch(`/api/v1/admin/assets/folders/${id}`, req);
|
|
60
|
+
return out.data;
|
|
61
|
+
},
|
|
62
|
+
async deleteFolder(id, req) {
|
|
63
|
+
const out = await apiClient.delete(`/api/v1/admin/assets/folders/${id}`, {
|
|
64
|
+
body: JSON.stringify(req),
|
|
65
|
+
headers: { 'content-type': 'application/json' },
|
|
66
|
+
});
|
|
67
|
+
return out.data;
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
//# sourceMappingURL=assets-library-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assets-library-client.js","sourceRoot":"","sources":["../../../src/admin/api/assets-library-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
export interface AssetDetailDrawerProps {
|
|
3
|
+
assetId: string;
|
|
4
|
+
onChanged: () => void;
|
|
5
|
+
onClose: () => void;
|
|
6
|
+
}
|
|
7
|
+
export declare function AssetDetailDrawer({ assetId, onChanged, onClose, }: AssetDetailDrawerProps): ReactNode;
|
|
8
|
+
//# sourceMappingURL=AssetDetailDrawer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AssetDetailDrawer.d.ts","sourceRoot":"","sources":["../../../src/admin/components/AssetDetailDrawer.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAuB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAyB5D,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,iBAAiB,CAAC,EAChC,OAAO,EACP,SAAS,EACT,OAAO,GACR,EAAE,sBAAsB,GAAG,SAAS,CAoLpC"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// Asset detail drawer — feature 013 / US2 / T068.
|
|
3
|
+
// Displays a single asset's metadata + reference list, supports inline edits
|
|
4
|
+
// (filename, label, mimeType, visibility) and a soft-delete affordance.
|
|
5
|
+
import { useEffect, useState } from 'react';
|
|
6
|
+
import { ExternalLink, Trash2 } from 'lucide-react';
|
|
7
|
+
import { Alert, AlertDescription, Button, Card, CardContent, CardHeader, CardTitle, Input, Label, Select } from '@endora-commerce/admin-kit/ui';
|
|
8
|
+
import { toAbsoluteAssetUrl } from '@endora-commerce/admin-kit/lib';
|
|
9
|
+
import { useTranslation } from '@endora-commerce/admin-kit/i18n';
|
|
10
|
+
import { assetsLibraryClient, } from '../api/assets-library-client.js';
|
|
11
|
+
// Curated set of MIME types the Assets Library handles (image / video / pdf).
|
|
12
|
+
// The MIME type is a technical identifier, so it is offered as a fixed dropdown
|
|
13
|
+
// rather than a free-text field to prevent typos and unsupported values.
|
|
14
|
+
const MIME_TYPE_OPTIONS = [
|
|
15
|
+
'image/jpeg',
|
|
16
|
+
'image/png',
|
|
17
|
+
'image/webp',
|
|
18
|
+
'image/gif',
|
|
19
|
+
'image/svg+xml',
|
|
20
|
+
'image/avif',
|
|
21
|
+
'video/mp4',
|
|
22
|
+
'video/webm',
|
|
23
|
+
'application/pdf',
|
|
24
|
+
];
|
|
25
|
+
export function AssetDetailDrawer({ assetId, onChanged, onClose, }) {
|
|
26
|
+
const t = useTranslation('assets_library');
|
|
27
|
+
const [detail, setDetail] = useState(null);
|
|
28
|
+
const [error, setError] = useState(null);
|
|
29
|
+
const [busy, setBusy] = useState(false);
|
|
30
|
+
const reload = () => {
|
|
31
|
+
setError(null);
|
|
32
|
+
assetsLibraryClient
|
|
33
|
+
.getAsset(assetId)
|
|
34
|
+
.then(setDetail)
|
|
35
|
+
.catch((e) => setError(e instanceof Error ? e.message : String(e)));
|
|
36
|
+
};
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
reload();
|
|
39
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
40
|
+
}, [assetId]);
|
|
41
|
+
if (error) {
|
|
42
|
+
return (_jsx(Alert, { variant: "destructive", children: _jsx(AlertDescription, { children: error }) }));
|
|
43
|
+
}
|
|
44
|
+
if (!detail) {
|
|
45
|
+
return _jsx("p", { className: "text-sm text-muted-foreground", children: t('common.loading') });
|
|
46
|
+
}
|
|
47
|
+
const save = async (patch) => {
|
|
48
|
+
setBusy(true);
|
|
49
|
+
setError(null);
|
|
50
|
+
try {
|
|
51
|
+
const next = await assetsLibraryClient.patchAsset(assetId, patch);
|
|
52
|
+
setDetail(next);
|
|
53
|
+
onChanged();
|
|
54
|
+
}
|
|
55
|
+
catch (e) {
|
|
56
|
+
setError(e instanceof Error ? e.message : String(e));
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
setBusy(false);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
const softDelete = async () => {
|
|
63
|
+
setBusy(true);
|
|
64
|
+
setError(null);
|
|
65
|
+
try {
|
|
66
|
+
await assetsLibraryClient.softDeleteAsset(assetId);
|
|
67
|
+
onChanged();
|
|
68
|
+
onClose();
|
|
69
|
+
}
|
|
70
|
+
catch (e) {
|
|
71
|
+
setError(e instanceof Error ? e.message : String(e));
|
|
72
|
+
}
|
|
73
|
+
finally {
|
|
74
|
+
setBusy(false);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
return (_jsxs(Card, { className: "sticky top-2 max-h-[calc(100vh-2rem)] overflow-y-auto", children: [_jsxs(CardHeader, { className: "flex flex-row items-center justify-between", children: [_jsx(CardTitle, { className: "text-base", children: t('detail.title') }), _jsx(Button, { type: "button", size: "sm", variant: "ghost", onClick: onClose, children: "\u2715" })] }), _jsxs(CardContent, { className: "space-y-3", children: [detail.mimeType.startsWith('image/') ? (
|
|
78
|
+
// eslint-disable-next-line jsx-a11y/alt-text
|
|
79
|
+
_jsx("img", { src: toAbsoluteAssetUrl(detail.url), className: "w-full rounded border bg-muted/30 object-contain" })) : (_jsx("div", { className: "rounded border bg-muted/30 p-4 text-center text-xs text-muted-foreground", children: detail.mimeType })), _jsxs("a", { href: toAbsoluteAssetUrl(detail.url), target: "_blank", rel: "noopener", className: "inline-flex items-center gap-1 text-xs underline", children: [t('detail.openFile'), " ", _jsx(ExternalLink, { className: "size-3" })] }), _jsx(Field, { label: t('detail.filename'), value: detail.filename, onSave: (v) => save({ filename: v }), disabled: busy, saveLabel: t('common.save') }), _jsx(Field, { label: t('detail.label'), value: detail.label ?? '', placeholder: t('common.optional'), onSave: (v) => save({ label: v.length === 0 ? null : v }), disabled: busy, saveLabel: t('common.save') }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { children: t('detail.mimeType') }), _jsxs(Select, { value: detail.mimeType, onChange: (e) => {
|
|
80
|
+
const v = e.target.value;
|
|
81
|
+
if (v !== detail.mimeType)
|
|
82
|
+
void save({ mimeType: v });
|
|
83
|
+
}, disabled: busy, children: [MIME_TYPE_OPTIONS.includes(detail.mimeType) ? null : (_jsx("option", { value: detail.mimeType, children: detail.mimeType })), MIME_TYPE_OPTIONS.map((m) => (_jsx("option", { value: m, children: m }, m)))] })] }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { children: t('detail.visibility') }), _jsxs(Select, { value: detail.visibility, onChange: (e) => {
|
|
84
|
+
const v = e.target.value;
|
|
85
|
+
void save({ visibility: v });
|
|
86
|
+
}, disabled: busy, children: [_jsx("option", { value: "public", children: t('visibility.public') }), _jsx("option", { value: "private", children: t('visibility.private') })] })] }), _jsxs("div", { className: "text-xs text-muted-foreground", children: [t('detail.storage'), ": ", detail.storageBackend, " \u00B7 ", t('detail.size'), ": ", detail.sizeBytes, " ", t('detail.bytes')] }), _jsxs("div", { className: "border-t pt-3", children: [_jsx("p", { className: "mb-1 text-sm font-medium", children: t('detail.referencedBy') }), detail.references.length === 0 ? (_jsx("p", { className: "text-xs text-muted-foreground", children: t('detail.notReferenced') })) : (_jsx("ul", { className: "space-y-1 text-xs", children: detail.references.map((r, i) => (_jsxs("li", { children: [_jsx("span", { className: "font-mono text-muted-foreground", children: r.kind }), ' — ', r.label] }, `${r.kind}-${r.entityId}-${i}`))) }))] }), _jsx("div", { className: "border-t pt-3", children: _jsxs(Button, { type: "button", variant: "destructive", size: "sm", disabled: busy || detail.references.length > 0, title: detail.references.length > 0
|
|
87
|
+
? t('detail.softDeleteBlockedTitle')
|
|
88
|
+
: t('detail.softDeleteTitle'), onClick: () => void softDelete(), children: [_jsx(Trash2, { className: "size-4 mr-1" }), " ", t('detail.softDelete')] }) })] })] }));
|
|
89
|
+
}
|
|
90
|
+
function Field({ label, value, placeholder, onSave, disabled, saveLabel, }) {
|
|
91
|
+
const [v, setV] = useState(value);
|
|
92
|
+
useEffect(() => setV(value), [value]);
|
|
93
|
+
const dirty = v !== value;
|
|
94
|
+
return (_jsxs("div", { className: "space-y-1", children: [_jsx(Label, { children: label }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Input, { value: v, ...(placeholder !== undefined ? { placeholder } : {}), onChange: (e) => setV(e.target.value), disabled: disabled }), dirty ? (_jsx(Button, { type: "button", size: "sm", onClick: () => void onSave(v), disabled: disabled, children: saveLabel })) : null] })] }));
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=AssetDetailDrawer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AssetDetailDrawer.js","sourceRoot":"","sources":["../../../src/admin/components/AssetDetailDrawer.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import type { AssetFolder } from '../api/assets-library-client.js';
|
|
3
|
+
export interface FolderTreeProps {
|
|
4
|
+
folders: AssetFolder[];
|
|
5
|
+
selectedId: string | null;
|
|
6
|
+
/** null ⇒ Unsorted (root). */
|
|
7
|
+
onSelect: (id: string | null) => void;
|
|
8
|
+
onCreate: (parentId: string | null, name: string) => Promise<void> | void;
|
|
9
|
+
onRename: (id: string, name: string) => Promise<void> | void;
|
|
10
|
+
onDelete: (id: string) => Promise<void> | void;
|
|
11
|
+
}
|
|
12
|
+
export declare function FolderTree(props: FolderTreeProps): ReactNode;
|
|
13
|
+
//# sourceMappingURL=FolderTree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FolderTree.d.ts","sourceRoot":"","sources":["../../../src/admin/components/FolderTree.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAI1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAEnE,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,8BAA8B;IAC9B,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACtC,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1E,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC7D,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAChD;AAyBD,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,SAAS,CAgJ5D"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// Folder tree — feature 013 / US2 / T067.
|
|
3
|
+
// Renders the Library's folder hierarchy with create/rename/delete actions.
|
|
4
|
+
import { useMemo, useState } from 'react';
|
|
5
|
+
import { Folder, FolderPlus, Trash2 } from 'lucide-react';
|
|
6
|
+
import { Button, Input } from '@endora-commerce/admin-kit/ui';
|
|
7
|
+
import { useTranslation } from '@endora-commerce/admin-kit/i18n';
|
|
8
|
+
function flatten(folders, parentId, depth) {
|
|
9
|
+
const rows = [];
|
|
10
|
+
const children = folders
|
|
11
|
+
.filter((f) => (f.parentId ?? null) === parentId)
|
|
12
|
+
.sort((a, b) => a.position - b.position || a.name.localeCompare(b.name));
|
|
13
|
+
for (const c of children) {
|
|
14
|
+
rows.push({ id: c.id, name: c.name, parentId: c.parentId ?? null, depth });
|
|
15
|
+
rows.push(...flatten(folders, c.id, depth + 1));
|
|
16
|
+
}
|
|
17
|
+
return rows;
|
|
18
|
+
}
|
|
19
|
+
export function FolderTree(props) {
|
|
20
|
+
const t = useTranslation('assets_library');
|
|
21
|
+
const [creatingFor, setCreatingFor] = useState(undefined);
|
|
22
|
+
const [newName, setNewName] = useState('');
|
|
23
|
+
const [renamingId, setRenamingId] = useState(null);
|
|
24
|
+
const [renameName, setRenameName] = useState('');
|
|
25
|
+
const rows = useMemo(() => flatten(props.folders, null, 0), [props.folders]);
|
|
26
|
+
return (_jsxs("div", { className: "space-y-1", children: [_jsxs("button", { type: "button", className: `flex w-full items-center justify-between rounded px-2 py-1 text-left text-sm hover:bg-muted ${props.selectedId === null ? 'bg-muted font-medium' : ''}`, onClick: () => props.onSelect(null), children: [_jsxs("span", { className: "flex items-center gap-2", children: [_jsx(Folder, { className: "size-4" }), t('folders.root')] }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: (e) => {
|
|
27
|
+
e.stopPropagation();
|
|
28
|
+
setCreatingFor(null);
|
|
29
|
+
setNewName('');
|
|
30
|
+
}, children: _jsx(FolderPlus, { className: "size-4" }) })] }), creatingFor === null ? (_jsx(InlineCreator, { value: newName, onChange: setNewName, onConfirm: async () => {
|
|
31
|
+
if (newName.trim().length === 0)
|
|
32
|
+
return;
|
|
33
|
+
await props.onCreate(null, newName.trim());
|
|
34
|
+
setCreatingFor(undefined);
|
|
35
|
+
setNewName('');
|
|
36
|
+
}, onCancel: () => {
|
|
37
|
+
setCreatingFor(undefined);
|
|
38
|
+
setNewName('');
|
|
39
|
+
}, depth: 1, placeholder: t('folders.namePlaceholder'), confirmLabel: t('common.ok'), cancelLabel: t('common.cancel') })) : null, rows.map((r) => (_jsxs("div", { children: [renamingId === r.id ? (_jsx(InlineCreator, { value: renameName, onChange: setRenameName, onConfirm: async () => {
|
|
40
|
+
if (renameName.trim().length === 0)
|
|
41
|
+
return;
|
|
42
|
+
await props.onRename(r.id, renameName.trim());
|
|
43
|
+
setRenamingId(null);
|
|
44
|
+
}, onCancel: () => setRenamingId(null), depth: r.depth, placeholder: t('folders.namePlaceholder'), confirmLabel: t('common.ok'), cancelLabel: t('common.cancel') })) : (_jsxs("div", { className: `group flex items-center justify-between rounded px-2 py-1 text-sm hover:bg-muted ${props.selectedId === r.id ? 'bg-muted font-medium' : ''}`, style: { paddingLeft: `${0.5 + r.depth * 1.25}rem` }, children: [_jsxs("button", { type: "button", className: "flex flex-1 items-center gap-2 text-left", onClick: () => props.onSelect(r.id), onDoubleClick: () => {
|
|
45
|
+
setRenamingId(r.id);
|
|
46
|
+
setRenameName(r.name);
|
|
47
|
+
}, children: [_jsx(Folder, { className: "size-4" }), _jsx("span", { className: "truncate", children: r.name })] }), _jsxs("div", { className: "opacity-0 transition group-hover:opacity-100", children: [_jsx(Button, { type: "button", variant: "ghost", size: "sm", title: t('folders.newSubfolder'), onClick: () => {
|
|
48
|
+
setCreatingFor(r.id);
|
|
49
|
+
setNewName('');
|
|
50
|
+
}, children: _jsx(FolderPlus, { className: "size-4" }) }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", title: t('common.delete'), onClick: () => {
|
|
51
|
+
void props.onDelete(r.id);
|
|
52
|
+
}, children: _jsx(Trash2, { className: "size-4" }) })] })] })), creatingFor === r.id ? (_jsx(InlineCreator, { value: newName, onChange: setNewName, onConfirm: async () => {
|
|
53
|
+
if (newName.trim().length === 0)
|
|
54
|
+
return;
|
|
55
|
+
await props.onCreate(r.id, newName.trim());
|
|
56
|
+
setCreatingFor(undefined);
|
|
57
|
+
setNewName('');
|
|
58
|
+
}, onCancel: () => {
|
|
59
|
+
setCreatingFor(undefined);
|
|
60
|
+
setNewName('');
|
|
61
|
+
}, depth: r.depth + 1, placeholder: t('folders.namePlaceholder'), confirmLabel: t('common.ok'), cancelLabel: t('common.cancel') })) : null] }, r.id)))] }));
|
|
62
|
+
}
|
|
63
|
+
function InlineCreator({ value, onChange, onConfirm, onCancel, depth, placeholder, confirmLabel, cancelLabel, }) {
|
|
64
|
+
return (_jsxs("div", { className: "flex items-center gap-1 px-2 py-1", style: { paddingLeft: `${0.5 + depth * 1.25}rem` }, children: [_jsx(Input, { autoFocus: true, value: value, onChange: (e) => onChange(e.target.value), onKeyDown: (e) => {
|
|
65
|
+
if (e.key === 'Enter')
|
|
66
|
+
void onConfirm();
|
|
67
|
+
if (e.key === 'Escape')
|
|
68
|
+
onCancel();
|
|
69
|
+
}, placeholder: placeholder }), _jsx(Button, { type: "button", size: "sm", onClick: () => void onConfirm(), children: confirmLabel }), _jsx(Button, { type: "button", size: "sm", variant: "ghost", onClick: onCancel, children: cancelLabel })] }));
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=FolderTree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FolderTree.js","sourceRoot":"","sources":["../../../src/admin/components/FolderTree.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `assets_library`' admin surface — one route and one sidebar entry
|
|
3
|
+
* (feature 091, Phase 4, batch 9;
|
|
4
|
+
* `specs/091-module-owned-admin-surfaces/contracts/admin-contribution.md`).
|
|
5
|
+
*
|
|
6
|
+
* **Its drain was thirteen incoming reaches and it is zero**, which is a
|
|
7
|
+
* measurement rather than a claim. P4c (!1225) published `AssetPicker`,
|
|
8
|
+
* `AssetUploader`, `AssetFieldPicker` and `toAbsoluteAssetUrl` into
|
|
9
|
+
* `@endora-commerce/admin-kit` on the terms P2 set — each rebuilds its own
|
|
10
|
+
* request from the published `apiClient` and the contract types, so nothing
|
|
11
|
+
* that crosses those seams was ever this module's *code*. What is left under
|
|
12
|
+
* `src/admin/` is the library screen itself, its folder tree, its detail drawer
|
|
13
|
+
* and its typed client, and no module names any of them.
|
|
14
|
+
*
|
|
15
|
+
* **The drawer carried a fourteenth copy of `toAbsoluteAssetUrl` and P4c could
|
|
16
|
+
* not see it.** That publication counted *cross-module* reaches, and a copy in
|
|
17
|
+
* the owner's own file is not one — so the helper the kit publishes was
|
|
18
|
+
* re-implemented, identically, in `AssetDetailDrawer.tsx`, over a private
|
|
19
|
+
* `import.meta.env.VITE_API_BASE_URL` read with the same
|
|
20
|
+
* `http://localhost:3001` fallback. The move forces the repair rather than
|
|
21
|
+
* merely permitting it: this package's `tsconfig.ui.json` carries no
|
|
22
|
+
* `vite/client` types, so `import.meta.env` does not compile here. It takes
|
|
23
|
+
* `toAbsoluteAssetUrl` from `@endora-commerce/admin-kit/lib`, which is where
|
|
24
|
+
* `LibraryPage` was already taking it from two files away.
|
|
25
|
+
*
|
|
26
|
+
* **No palette action, and that is asserted rather than skipped.** This module
|
|
27
|
+
* declares none in its `manifest.ts` and this batch does not invent one:
|
|
28
|
+
* choosing a landing action for a screen is a product decision, not a file
|
|
29
|
+
* move — the reasoning batch 8 recorded for `seo` and `taxes`. The off-state
|
|
30
|
+
* test drives the empty answer in both states, so an action added later without
|
|
31
|
+
* a test fails.
|
|
32
|
+
*
|
|
33
|
+
* **`nonDeactivatable`, so the operator axis is the platform's** (`plan.md`
|
|
34
|
+
* Ruling 2). Media storage is a platform primitive — product images, CMS media
|
|
35
|
+
* and e-mail assets all resolve here — and the manifest says so with a reason.
|
|
36
|
+
* The permission axis is what this module still has and is what the off-state
|
|
37
|
+
* test drives; the missing axis is read off the manifest rather than skipped.
|
|
38
|
+
*
|
|
39
|
+
* **This entry exports data and nothing else** (R2); the component is a
|
|
40
|
+
* dynamic-import factory (R6).
|
|
41
|
+
*/
|
|
42
|
+
import type { AdminContributions } from '@endora-commerce/admin-kit/contributions';
|
|
43
|
+
export declare const contributions: AdminContributions;
|
|
44
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAC;AAgBnF,eAAO,MAAM,aAAa,EAAE,kBAgC3B,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** The module's only route: the three-pane library screen. */
|
|
2
|
+
const ROUTE_PATH = '/assets-library';
|
|
3
|
+
/**
|
|
4
|
+
* The code `GET /api/v1/admin/assets` and the folder tree's reads enforce.
|
|
5
|
+
*
|
|
6
|
+
* The screen writes too — upload, rename, soft-delete — behind `assets.write`,
|
|
7
|
+
* which is a second code this module declares and which is **not** what gates
|
|
8
|
+
* the surface: an operator holding only `assets.read` opens the library and
|
|
9
|
+
* sees the write affordances refuse. The nav entry and the route therefore
|
|
10
|
+
* carry the read code, which is what `AppShell.tsx`'s hand-written row carried.
|
|
11
|
+
*/
|
|
12
|
+
const ASSETS_READ_PERMISSION = 'assets.read';
|
|
13
|
+
export const contributions = {
|
|
14
|
+
routes: [
|
|
15
|
+
{
|
|
16
|
+
path: ROUTE_PATH,
|
|
17
|
+
component: () => import('./pages/LibraryPage.js'),
|
|
18
|
+
requiredPermission: ASSETS_READ_PERMISSION,
|
|
19
|
+
index: true,
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
nav: [
|
|
23
|
+
{
|
|
24
|
+
to: ROUTE_PATH,
|
|
25
|
+
// Module-relative (R8), resolved in this module's own namespace out of
|
|
26
|
+
// `packages/modules/assets_library/i18n/`. It was
|
|
27
|
+
// `appShell.nav.assetsLibrary` in the shared `_i18n` bundle, one of the
|
|
28
|
+
// four shared files a module author had to edit.
|
|
29
|
+
labelKey: 'nav.assetsLibrary.label',
|
|
30
|
+
// The glyph `AppShell.tsx` rendered by hand (`Image as ImageIcon`), and
|
|
31
|
+
// already on `KnownIconNameSchema`.
|
|
32
|
+
icon: 'Image',
|
|
33
|
+
section: 'catalog',
|
|
34
|
+
// The hand-written table put `/assets-library` sixth of seven in
|
|
35
|
+
// *Catalog*, directly above `/pim-ergonode`. `pim_pimcore` declares 300
|
|
36
|
+
// to sit "immediately after `pim_ergonode`", so 200 keeps this row above
|
|
37
|
+
// it and above `product_feeds`' 1000 — the order an operator already had
|
|
38
|
+
// among the rows the registry contributes. All three still append after
|
|
39
|
+
// the section's remaining host-declared rows, which is `composeNav`'s
|
|
40
|
+
// behaviour until those carry weights too.
|
|
41
|
+
weight: 200,
|
|
42
|
+
requiredPermission: ASSETS_READ_PERMISSION,
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AA2CA,8DAA8D;AAC9D,MAAM,UAAU,GAAG,iBAAiB,CAAC;AAErC;;;;;;;;GAQG;AACH,MAAM,sBAAsB,GAAG,aAAa,CAAC;AAE7C,MAAM,CAAC,MAAM,aAAa,GAAuB;IAC/C,MAAM,EAAE;QACN;YACE,IAAI,EAAE,UAAU;YAChB,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,wBAAwB,CAAC;YACjD,kBAAkB,EAAE,sBAAsB;YAC1C,KAAK,EAAE,IAAI;SACZ;KACF;IACD,GAAG,EAAE;QACH;YACE,EAAE,EAAE,UAAU;YACd,uEAAuE;YACvE,kDAAkD;YAClD,wEAAwE;YACxE,iDAAiD;YACjD,QAAQ,EAAE,yBAAyB;YACnC,wEAAwE;YACxE,oCAAoC;YACpC,IAAI,EAAE,OAAO;YACb,OAAO,EAAE,SAAS;YAClB,iEAAiE;YACjE,wEAAwE;YACxE,yEAAyE;YACzE,yEAAyE;YACzE,wEAAwE;YACxE,sEAAsE;YACtE,2CAA2C;YAC3C,MAAM,EAAE,GAAG;YACX,kBAAkB,EAAE,sBAAsB;SAC3C;KACF;CACF,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
export declare function LibraryPage(): ReactNode;
|
|
3
|
+
/**
|
|
4
|
+
* The registry loads a route component through a dynamic-import factory and
|
|
5
|
+
* reads its default export (feature 091, FR-013). The named export stays: it is
|
|
6
|
+
* the spelling this module's own code and its tests use.
|
|
7
|
+
*/
|
|
8
|
+
export default LibraryPage;
|
|
9
|
+
//# sourceMappingURL=LibraryPage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LibraryPage.d.ts","sourceRoot":"","sources":["../../../src/admin/pages/LibraryPage.tsx"],"names":[],"mappings":"AAIA,OAAO,EAA4C,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAajF,wBAAgB,WAAW,IAAI,SAAS,CA0QvC;AAED;;;;GAIG;AACH,eAAe,WAAW,CAAC"}
|