@jini-ai/admin 0.4.12 → 0.4.13
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/CHANGELOG.md +4 -0
- package/dist/agent-plugins/controllers/agent-plugin-files.controller.js +14 -9
- package/dist/agent-plugins/controllers/agent-plugins.controller.js +12 -9
- package/dist/agent-plugins/package-file-tree.js +54 -51
- package/dist/agent-plugins/react/components/AgentPluginRow.d.ts +1 -1
- package/dist/agent-plugins/react/components/AgentPluginRow.js +9 -2
- package/dist/agent-plugins/react/hooks/AgentPluginInspector.hooks.d.ts +5 -5
- package/dist/agent-plugins/react/hooks/AgentPluginInspector.hooks.js +14 -5
- package/dist/agent-plugins/react/hooks/AgentPluginPanel.hooks.d.ts +15 -13
- package/dist/agent-plugins/react/hooks/AgentPluginPanel.hooks.js +54 -40
- package/dist/agent-plugins/react/hooks/AgentPluginsPage.hooks.d.ts +13 -13
- package/dist/agent-plugins/react/hooks/AgentPluginsPage.hooks.js +23 -11
- package/dist/browser/navigation.js +44 -27
- package/dist/comments/adapters/memory.js +30 -12
- package/dist/comments/conformance/comments-api.conformance.js +55 -33
- package/dist/comments/controllers/comment-queue.controller.js +13 -4
- package/dist/comments/react/hooks/use-comment-queue.hooks.d.ts +17 -2
- package/dist/comments/react/hooks/use-comment-queue.hooks.js +79 -30
- package/dist/comments/react/hooks/use-comment-settings.hooks.js +9 -5
- package/dist/comments/react/index.d.ts +2 -1
- package/dist/comments/react/index.js +1 -1
- package/dist/consent/react/ConsentFields.d.ts +35 -0
- package/dist/consent/react/ConsentFields.js +74 -0
- package/dist/consent/react/ConsentPreviewFrame.d.ts +14 -0
- package/dist/consent/react/ConsentPreviewFrame.js +14 -0
- package/dist/consent/react/ConsentSettingsPanel.d.ts +27 -4
- package/dist/consent/react/ConsentSettingsPanel.js +6 -17
- package/dist/consent/react/index.d.ts +6 -1
- package/dist/consent/react/index.js +2 -0
- package/dist/consent/react/settings-panel.hooks.d.ts +28 -1
- package/dist/consent/react/settings-panel.hooks.js +26 -0
- package/dist/core/entities/rules.js +126 -81
- package/dist/core/manifest/rules.js +10 -10
- package/dist/core/module/create-admin.js +195 -117
- package/dist/core/ports/redirects.d.ts +8 -6
- package/dist/core/ports/redirects.js +8 -6
- package/dist/core/routing/rules.js +9 -4
- package/dist/core/transport/http.js +37 -20
- package/dist/forms/adapters/memory.js +22 -11
- package/dist/forms/conformance/forms-api.conformance.d.ts +6 -4
- package/dist/forms/conformance/forms-api.conformance.js +42 -46
- package/dist/forms/field-settings.js +150 -115
- package/dist/forms/html-rules.js +45 -28
- package/dist/forms/react/components/FieldSettingsRows.d.ts +22 -0
- package/dist/forms/react/components/FieldSettingsRows.js +29 -0
- package/dist/forms/react/components/FieldSettingsSection.d.ts +1 -1
- package/dist/forms/react/components/FieldSettingsSection.js +5 -6
- package/dist/forms/react/components/FormEditorFieldsBody.d.ts +1 -1
- package/dist/forms/react/components/FormEditorFieldsBody.js +4 -15
- package/dist/forms/react/components/FormEditorFieldsBodyParts.d.ts +18 -0
- package/dist/forms/react/components/FormEditorFieldsBodyParts.js +32 -0
- package/dist/forms/react/components/FormSubmissions.d.ts +1 -1
- package/dist/forms/react/components/FormSubmissions.js +4 -20
- package/dist/forms/react/components/FormSubmissionsTable.d.ts +19 -0
- package/dist/forms/react/components/FormSubmissionsTable.js +22 -0
- package/dist/media/adapters/memory.js +31 -26
- package/dist/media/controllers/edit-media.controller.js +2 -1
- package/dist/media/controllers/library.controller.js +48 -35
- package/dist/media/controllers/providers.controller.js +2 -1
- package/dist/media/html-attributes.js +29 -15
- package/dist/media/index.d.ts +1 -1
- package/dist/media/index.js +1 -1
- package/dist/media/react/components/MediaIcons.d.ts +0 -3
- package/dist/media/react/components/MediaIcons.js +0 -9
- package/dist/media/react/components/MediaLightbox.d.ts +2 -1
- package/dist/media/react/components/MediaLightbox.js +11 -5
- package/dist/media/react/hooks/LibraryTab.hooks.d.ts +55 -45
- package/dist/media/react/hooks/LibraryTab.hooks.js +107 -70
- package/dist/media/react/hooks/MediaCard.hooks.d.ts +27 -31
- package/dist/media/react/hooks/MediaCard.hooks.js +52 -26
- package/dist/media/react/hooks/MediaGrid.hooks.d.ts +1 -1
- package/dist/media/react/hooks/MediaLightbox.hooks.d.ts +10 -14
- package/dist/media/react/hooks/MediaLightbox.hooks.js +9 -56
- package/dist/media/react/hooks/MediaPage.hooks.d.ts +6 -0
- package/dist/media/react/hooks/MediaPage.hooks.js +29 -12
- package/dist/media/react/hooks/ProvidersTab.hooks.d.ts +33 -33
- package/dist/media/react/hooks/ProvidersTab.hooks.js +119 -79
- package/dist/media/react/hooks/UploadButton.hooks.d.ts +7 -5
- package/dist/media/react/hooks/UploadButton.hooks.js +36 -24
- package/dist/media/react/index.js +4 -0
- package/dist/media/react/tabs/LibraryTab.d.ts +1 -1
- package/dist/media/react/tabs/LibraryTab.js +2 -2
- package/dist/media/rules.d.ts +7 -0
- package/dist/media/rules.js +25 -2
- package/dist/react/components/ConfirmDialog/ConfirmDialog.js +5 -8
- package/dist/react/components/ConfirmDialog/confirm-dialog-attrs.d.ts +20 -0
- package/dist/react/components/ConfirmDialog/confirm-dialog-attrs.js +24 -0
- package/dist/react/components/InteractiveHtmlEditor/InteractiveHtmlEditor.js +16 -7
- package/dist/react/components/RowMenu/RowMenu.js +16 -10
- package/dist/react/components/Sidebar.js +32 -26
- package/dist/react/entities/EntityEdit.js +17 -14
- package/dist/react/entities/EntityField.d.ts +5 -2
- package/dist/react/entities/EntityField.js +38 -23
- package/dist/react/entities/EntityList.js +6 -5
- package/dist/react/entities/RelationTruncationNotice.d.ts +9 -0
- package/dist/react/entities/RelationTruncationNotice.js +9 -0
- package/dist/react/entities/use-entity-edit.d.ts +4 -2
- package/dist/react/entities/use-entity-edit.js +52 -33
- package/dist/react/shell/AdminShell.js +40 -23
- package/dist/react/shell/model.d.ts +4 -1
- package/dist/react/shell/model.js +3 -2
- package/dist/react/shell/use-admin-shell-session.js +25 -26
- package/dist/redirects/adapters/memory.js +9 -2
- package/dist/redirects/conformance/redirects-api.conformance.js +66 -36
- package/dist/redirects/react/hooks/use-import-redirects-form.hooks.d.ts +1 -1
- package/dist/redirects/react/hooks/use-import-redirects-form.hooks.js +10 -3
- package/dist/redirects/react/hooks/wired.hooks.d.ts +1 -1
- package/dist/security/adapters/http.js +25 -10
- package/dist/security/adapters/memory.js +19 -5
- package/dist/security/controllers/access-tokens.controller.js +27 -26
- package/dist/security/controllers/other-credentials.controller.js +4 -2
- package/dist/security/controllers/root-key.controller.js +17 -9
- package/dist/security/react/hooks/AccessTokensTab.hooks.d.ts +40 -38
- package/dist/security/react/hooks/AccessTokensTab.hooks.js +36 -9
- package/dist/security/react/hooks/RootKeyTab.hooks.d.ts +14 -14
- package/dist/security/react/hooks/RootKeyTab.hooks.js +12 -3
- package/dist/security/react/tabs/RootKeyTab.d.ts +1 -1
- package/dist/security/react/tabs/RootKeyTab.js +12 -3
- package/dist/security/rules.js +45 -25
- package/dist/seo/controllers/seo.controller.js +4 -2
- package/dist/seo/react/components/MediaRefField.d.ts +1 -1
- package/dist/seo/react/components/MediaRefField.js +19 -2
- package/dist/seo/react/hooks/MediaRefField.hooks.js +3 -1
- package/dist/seo/react/hooks/SeoPage.hooks.d.ts +1 -1
- package/dist/seo/react/hooks/use-share-image-warning.hooks.js +48 -34
- package/dist/seo/react/pages/SeoPage.d.ts +4 -4
- package/dist/seo/react/pages/SeoPage.js +26 -6
- package/dist/seo/rules.js +39 -10
- package/dist/source-control/conformance/source-control-api.conformance.js +68 -38
- package/dist/source-control/controllers/source-control.controller.js +20 -8
- package/dist/source-control/react/hooks/ProvidersTab.hooks.d.ts +2 -1
- package/dist/source-control/react/hooks/ProvidersTab.hooks.js +18 -11
- package/dist/widgets/conformance/widgets-api.conformance.js +15 -1
- package/dist/widgets/controllers/instance-editor.controller.js +33 -24
- package/dist/widgets/controllers/library.controller.js +18 -12
- package/dist/widgets/controllers/region-editor.controller.js +6 -5
- package/dist/widgets/react/hooks/page-views.hooks.d.ts +1 -0
- package/dist/widgets/react/hooks/page-views.hooks.js +3 -2
- package/dist/widgets/react/hooks/use-widget-regions.hooks.d.ts +1 -1
- package/dist/widgets/react/hooks/use-widget-regions.hooks.js +9 -3
- package/dist/widgets/react/hooks/use-widgets-library.hooks.js +9 -2
- package/dist/widgets/react/pages/WidgetInstanceEditor.d.ts +1 -1
- package/dist/widgets/react/pages/WidgetInstanceEditor.js +7 -8
- package/dist/widgets/rules.d.ts +14 -2
- package/dist/widgets/rules.js +9 -6
- package/package.json +17 -8
- package/src/themes/default/admin.css +51 -0
- package/src/themes/default/chat.css +21 -0
- package/src/themes/default/manifest.json +29 -0
- package/dist/media/styles.d.ts +0 -4
- package/dist/media/styles.js +0 -5
|
@@ -23,6 +23,39 @@ export function createLibraryController({ api }, { query = {} } = {}) {
|
|
|
23
23
|
retryTimer = null;
|
|
24
24
|
}
|
|
25
25
|
let readAbort = null, generation = 0;
|
|
26
|
+
/** Store patch for an accepted full library: filtered rows plus whole-library tab counts.
|
|
27
|
+
* @complexity O(n) in the library size. */
|
|
28
|
+
function libraryView({ media }, _optional = {}) {
|
|
29
|
+
return { items: queryMedia({ media, query: store.getSnapshot().query }), counts: countMediaTabs({ media }) };
|
|
30
|
+
}
|
|
31
|
+
/** Commits a read that is still the latest one; items are frozen so consumers cannot mutate rows. */
|
|
32
|
+
function acceptRead({ all }, _optional = {}) {
|
|
33
|
+
readFailed = false;
|
|
34
|
+
retryAttempt = 0;
|
|
35
|
+
library = all;
|
|
36
|
+
const { items, counts } = libraryView({ media: all });
|
|
37
|
+
store.set({
|
|
38
|
+
patch: {
|
|
39
|
+
items: Object.freeze(items.map((item) => Object.freeze({ ...item }))),
|
|
40
|
+
counts,
|
|
41
|
+
hasUntyped: all.some((item) => item.contentType === null),
|
|
42
|
+
error: null,
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
/** Publishes the latest read's failure and, when the failure is transient, schedules a retry. */
|
|
47
|
+
function failRead({ error }, _optional = {}) {
|
|
48
|
+
readFailed = true;
|
|
49
|
+
store.set({
|
|
50
|
+
patch: { loading: false, error: error instanceof Error ? error.message : 'Failed to load media' },
|
|
51
|
+
});
|
|
52
|
+
// Retry reads only, never destructive writes. Keep trying at a capped delay so
|
|
53
|
+
// recovery needs no manual repair, while an offline service isn't hammered.
|
|
54
|
+
if (isRetryableMediaError({ error })) {
|
|
55
|
+
const delay = Math.min(1000 * 2 ** Math.min(retryAttempt++, 5), 30000);
|
|
56
|
+
retryTimer = setTimeout(() => { retryTimer = null; void load(); }, delay);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
26
59
|
async function load(_required = {}, _optional = {}) {
|
|
27
60
|
if (store.signal.aborted)
|
|
28
61
|
return;
|
|
@@ -34,35 +67,13 @@ export function createLibraryController({ api }, { query = {} } = {}) {
|
|
|
34
67
|
store.set({ patch: { loading: true, error: null } });
|
|
35
68
|
try {
|
|
36
69
|
const all = await api.list({}, { signal: abort.signal });
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
readFailed = false;
|
|
40
|
-
retryAttempt = 0;
|
|
41
|
-
library = all;
|
|
42
|
-
store.set({
|
|
43
|
-
patch: {
|
|
44
|
-
items: Object.freeze(items.map((item) => Object.freeze({ ...item }))),
|
|
45
|
-
counts: countMediaTabs({ media: all }),
|
|
46
|
-
hasUntyped: all.some((item) => item.contentType === null),
|
|
47
|
-
error: null,
|
|
48
|
-
},
|
|
49
|
-
});
|
|
50
|
-
}
|
|
70
|
+
if (ticket === generation)
|
|
71
|
+
acceptRead({ all });
|
|
51
72
|
}
|
|
52
73
|
catch (error) {
|
|
53
74
|
// A later background failure must not blank an already-rendered screen.
|
|
54
|
-
if (!abort.signal.aborted && ticket === generation)
|
|
55
|
-
|
|
56
|
-
store.set({
|
|
57
|
-
patch: { loading: false, error: error instanceof Error ? error.message : 'Failed to load media' },
|
|
58
|
-
});
|
|
59
|
-
// Retry reads only, never destructive writes. Keep trying at a capped delay so
|
|
60
|
-
// recovery needs no manual repair, while an offline service isn't hammered.
|
|
61
|
-
if (isRetryableMediaError({ error })) {
|
|
62
|
-
const delay = Math.min(1000 * 2 ** Math.min(retryAttempt++, 5), 30000);
|
|
63
|
-
retryTimer = setTimeout(() => { retryTimer = null; void load(); }, delay);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
75
|
+
if (!abort.signal.aborted && ticket === generation)
|
|
76
|
+
failRead({ error });
|
|
66
77
|
}
|
|
67
78
|
finally {
|
|
68
79
|
if (ticket === generation)
|
|
@@ -76,7 +87,7 @@ export function createLibraryController({ api }, { query = {} } = {}) {
|
|
|
76
87
|
return;
|
|
77
88
|
if (all) {
|
|
78
89
|
library = all;
|
|
79
|
-
store.set({ patch: {
|
|
90
|
+
store.set({ patch: { ...libraryView({ media: all }), hasUntyped: all.some(item => item.contentType === null), error: null } });
|
|
80
91
|
}
|
|
81
92
|
if (error)
|
|
82
93
|
store.set({ patch: { error: error.message } });
|
|
@@ -100,17 +111,18 @@ export function createLibraryController({ api }, { query = {} } = {}) {
|
|
|
100
111
|
readAbort?.abort();
|
|
101
112
|
cancelRetry();
|
|
102
113
|
store.set({ patch: { loading: false, error: null } });
|
|
114
|
+
// A single exit: a write disposed mid-flight or a failed write reports false.
|
|
115
|
+
let saved = false;
|
|
103
116
|
try {
|
|
104
117
|
await run();
|
|
105
|
-
if (store.signal.aborted)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
118
|
+
if (!store.signal.aborted) {
|
|
119
|
+
await load();
|
|
120
|
+
saved = true;
|
|
121
|
+
}
|
|
109
122
|
}
|
|
110
123
|
catch (error) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
return false;
|
|
124
|
+
// The store ignores patches once disposed, so a write failing after dispose publishes nothing.
|
|
125
|
+
store.set({ patch: { loading: false, error: error instanceof Error ? error.message : 'Media write failed' } });
|
|
114
126
|
}
|
|
115
127
|
finally {
|
|
116
128
|
if (id === undefined)
|
|
@@ -118,6 +130,7 @@ export function createLibraryController({ api }, { query = {} } = {}) {
|
|
|
118
130
|
const pendingIds = store.getSnapshot().pendingIds.filter(value => value !== id);
|
|
119
131
|
store.set({ patch: { busy: pendingIds.length > 0, pendingIds } });
|
|
120
132
|
}
|
|
133
|
+
return saved;
|
|
121
134
|
});
|
|
122
135
|
writes = operation.catch(() => undefined);
|
|
123
136
|
return operation;
|
|
@@ -168,7 +181,7 @@ export function createLibraryController({ api }, { query = {} } = {}) {
|
|
|
168
181
|
// A failed follow-up read must not leave a permanently deleted card focusable.
|
|
169
182
|
if (library) {
|
|
170
183
|
library = library.filter(row => row.id !== item.id);
|
|
171
|
-
store.set({ patch:
|
|
184
|
+
store.set({ patch: libraryView({ media: library }) });
|
|
172
185
|
}
|
|
173
186
|
});
|
|
174
187
|
if (saved)
|
|
@@ -46,11 +46,12 @@ export function createProvidersController({ api }, _optional = {}) {
|
|
|
46
46
|
}
|
|
47
47
|
catch {
|
|
48
48
|
store.set({ patch: { error: 'Failed to save provider credentials' } });
|
|
49
|
-
return false;
|
|
50
49
|
}
|
|
51
50
|
finally {
|
|
52
51
|
store.set({ patch: { saving: false } });
|
|
53
52
|
}
|
|
53
|
+
// Reached only through the catch above: the failure is already recorded in `error`.
|
|
54
|
+
return false;
|
|
54
55
|
}
|
|
55
56
|
return {
|
|
56
57
|
getSnapshot: store.getSnapshot,
|
|
@@ -80,7 +80,9 @@ const ASCII_WHITESPACE_OR_CONTROL_MAX_CODE_POINT = 0x20;
|
|
|
80
80
|
function isUnsafeMediaUrlValue(value) {
|
|
81
81
|
let stripped = "";
|
|
82
82
|
for (const char of value) {
|
|
83
|
-
|
|
83
|
+
// `char` is never empty, so `charCodeAt(0)` is always a number; for an astral character it is
|
|
84
|
+
// the high surrogate (>= 0xD800), which is kept exactly as the full code point would be.
|
|
85
|
+
if (char.charCodeAt(0) > ASCII_WHITESPACE_OR_CONTROL_MAX_CODE_POINT)
|
|
84
86
|
stripped += char;
|
|
85
87
|
}
|
|
86
88
|
stripped = stripped.toLowerCase();
|
|
@@ -165,15 +167,11 @@ export function parseMediaHtmlAttributes({ text }, _optional = {}) {
|
|
|
165
167
|
// Non-whitespace text between the previous match and this one is a fragment the token pattern
|
|
166
168
|
// could not parse as a name (e.g. a stray quote) — the tokenizer has lost sync, so everything
|
|
167
169
|
// parsed so far is discarded rather than trusted.
|
|
168
|
-
const skipped = trimmed.slice(consumed, match.index);
|
|
169
|
-
if (skipped
|
|
170
|
-
|
|
171
|
-
errors.push(malformed);
|
|
172
|
-
return { attributes: {}, errors, error: malformed };
|
|
173
|
-
}
|
|
170
|
+
const skipped = trimmed.slice(consumed, match.index).trim();
|
|
171
|
+
if (skipped !== "")
|
|
172
|
+
return malformedMediaHtmlAttributes({ errors, fragment: skipped });
|
|
174
173
|
consumed = match.index + match[0].length;
|
|
175
|
-
const name = match
|
|
176
|
-
const value = match[2] ?? match[3] ?? match[4] ?? "";
|
|
174
|
+
const { name, value } = readMediaHtmlAttributeToken({ match });
|
|
177
175
|
const rejection = classifyMediaHtmlAttributeToken(name, value);
|
|
178
176
|
if (rejection) {
|
|
179
177
|
errors.push(rejection);
|
|
@@ -181,14 +179,30 @@ export function parseMediaHtmlAttributes({ text }, _optional = {}) {
|
|
|
181
179
|
}
|
|
182
180
|
attributes[name] = value;
|
|
183
181
|
}
|
|
184
|
-
const trailing = trimmed.slice(consumed);
|
|
185
|
-
if (trailing
|
|
186
|
-
|
|
187
|
-
errors.push(malformed);
|
|
188
|
-
return { attributes: {}, errors, error: malformed };
|
|
189
|
-
}
|
|
182
|
+
const trailing = trimmed.slice(consumed).trim();
|
|
183
|
+
if (trailing !== "")
|
|
184
|
+
return malformedMediaHtmlAttributes({ errors, fragment: trailing });
|
|
190
185
|
return { attributes, errors, error: errors[0] ?? null };
|
|
191
186
|
}
|
|
187
|
+
/** The lowercased name and the value of one {@link HTML_ATTRIBUTE_TOKEN} match: whichever of the
|
|
188
|
+
* double-quoted, single-quoted or unquoted value groups matched, or `""` for a bare boolean name.
|
|
189
|
+
*
|
|
190
|
+
* @complexity O(n) in the name's length (one lowercase pass).
|
|
191
|
+
*/
|
|
192
|
+
function readMediaHtmlAttributeToken({ match }, _optional = {}) {
|
|
193
|
+
return { name: match[1].toLowerCase(), value: match[2] ?? match[3] ?? match[4] ?? "" };
|
|
194
|
+
}
|
|
195
|
+
/** The fail-closed result once the tokenizer loses sync: `fragment` (already trimmed) is appended
|
|
196
|
+
* to `errors` as the final `malformed` entry, and every accepted attribute is discarded — see
|
|
197
|
+
* {@link parseMediaHtmlAttributes}'s header for why. Mutates `errors` (the caller's own list).
|
|
198
|
+
*
|
|
199
|
+
* @complexity O(1).
|
|
200
|
+
*/
|
|
201
|
+
function malformedMediaHtmlAttributes({ errors, fragment }, _optional = {}) {
|
|
202
|
+
const malformed = { reason: "malformed", attribute: fragment };
|
|
203
|
+
errors.push(malformed);
|
|
204
|
+
return { attributes: {}, errors, error: malformed };
|
|
205
|
+
}
|
|
192
206
|
/** The hint names the rejected token so operators can distinguish a typo from a hard no.
|
|
193
207
|
* This is client feedback only; the server must independently enforce write/render policy. */
|
|
194
208
|
export function describeMediaHtmlAttributeError({ error }, _optional = {}) {
|
package/dist/media/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export { mediaApiToken, mediaProvidersToken } from './ports.js';
|
|
|
3
3
|
export type { MediaApiPort, MediaProvidersPort, MediaEventsPort } from './ports.js';
|
|
4
4
|
export type { MediaAsset, MediaQuery, UploadInput, MediaMetadataPatch, MediaRequestOptions, MediaProvider, MediaProviderOption, MediaProviderConfiguration, MediaProviderConfigurationMap, MediaTabId, MediaContentTabId, MediaOrderBy, } from './models.js';
|
|
5
5
|
export { mediaMessagesEn } from './messages.en.js';
|
|
6
|
-
export { filterMediaByTab, resolveActiveTab, queryMedia, diffMediaMetadata, acceptsMedia, safeMediaUrl, canReplaceMedia, canRestoreMedia, isRetryableMediaError, parseOptionalPixelSize, formatByteSize, formatUploadDate, countMediaTabs, mediaEmbedSnippet, mediaRowHandles, } from './rules.js';
|
|
6
|
+
export { filterMediaByTab, resolveActiveTab, queryMedia, diffMediaMetadata, acceptsMedia, safeMediaUrl, canReplaceMedia, canRestoreMedia, isRetryableMediaError, parseOptionalPixelSize, formatByteSize, formatUploadDate, mediaFileName, countMediaTabs, mediaEmbedSnippet, mediaRowHandles, } from './rules.js';
|
|
7
7
|
export { createLibraryController } from './controllers/library.controller.js';
|
|
8
8
|
export type { LibraryState } from './controllers/library.controller.js';
|
|
9
9
|
export { createEditMediaController } from './controllers/edit-media.controller.js';
|
package/dist/media/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { mediaModule } from './media.module.js';
|
|
2
2
|
export { mediaApiToken, mediaProvidersToken } from './ports.js';
|
|
3
3
|
export { mediaMessagesEn } from './messages.en.js';
|
|
4
|
-
export { filterMediaByTab, resolveActiveTab, queryMedia, diffMediaMetadata, acceptsMedia, safeMediaUrl, canReplaceMedia, canRestoreMedia, isRetryableMediaError, parseOptionalPixelSize, formatByteSize, formatUploadDate, countMediaTabs, mediaEmbedSnippet, mediaRowHandles, } from './rules.js';
|
|
4
|
+
export { filterMediaByTab, resolveActiveTab, queryMedia, diffMediaMetadata, acceptsMedia, safeMediaUrl, canReplaceMedia, canRestoreMedia, isRetryableMediaError, parseOptionalPixelSize, formatByteSize, formatUploadDate, mediaFileName, countMediaTabs, mediaEmbedSnippet, mediaRowHandles, } from './rules.js';
|
|
5
5
|
export { createLibraryController } from './controllers/library.controller.js';
|
|
6
6
|
export { createEditMediaController } from './controllers/edit-media.controller.js';
|
|
7
7
|
export { createProvidersController } from './controllers/providers.controller.js';
|
|
@@ -4,9 +4,6 @@ export declare function ReloadIcon(_required: Record<string, never>, _optional?:
|
|
|
4
4
|
export declare function HiddenEyeIcon(_required: Record<string, never>, _optional?: Record<string, never>): import("react").JSX.Element;
|
|
5
5
|
export declare function EyeIcon(_required: Record<string, never>, _optional?: Record<string, never>): import("react").JSX.Element;
|
|
6
6
|
export declare function ExpandIcon(_required: Record<string, never>, _optional?: Record<string, never>): import("react").JSX.Element;
|
|
7
|
-
export declare function CloseIcon(_required: Record<string, never>, _optional?: Record<string, never>): import("react").JSX.Element;
|
|
8
|
-
export declare function PreviousIcon(_required: Record<string, never>, _optional?: Record<string, never>): import("react").JSX.Element;
|
|
9
|
-
export declare function NextIcon(_required: Record<string, never>, _optional?: Record<string, never>): import("react").JSX.Element;
|
|
10
7
|
export declare function AllIcon(_required: Record<string, never>, _optional?: Record<string, never>): import("react").JSX.Element;
|
|
11
8
|
export declare function ImageIcon(_required: Record<string, never>, _optional?: Record<string, never>): import("react").JSX.Element;
|
|
12
9
|
export declare function VideoIcon(_required: Record<string, never>, _optional?: Record<string, never>): import("react").JSX.Element;
|
|
@@ -15,15 +15,6 @@ export function EyeIcon(_required, _optional = {}) {
|
|
|
15
15
|
export function ExpandIcon(_required, _optional = {}) {
|
|
16
16
|
return _jsx("svg", { className: "jini-icon", viewBox: "0 0 18 18", fill: "none", stroke: "currentColor", strokeWidth: "1.5", "aria-hidden": "true", children: _jsx("path", { className: "jini-icon-path", d: "M6 2H2v4m10-4h4v4M2 12v4h4m10-4v4h-4" }) });
|
|
17
17
|
}
|
|
18
|
-
export function CloseIcon(_required, _optional = {}) {
|
|
19
|
-
return _jsx("svg", { className: "jini-icon", viewBox: "0 0 18 18", fill: "none", stroke: "currentColor", strokeWidth: "1.5", "aria-hidden": "true", children: _jsx("path", { className: "jini-icon-path", d: "m4 4 10 10M14 4 4 14" }) });
|
|
20
|
-
}
|
|
21
|
-
export function PreviousIcon(_required, _optional = {}) {
|
|
22
|
-
return _jsx("svg", { className: "jini-icon", viewBox: "0 0 18 18", fill: "none", stroke: "currentColor", strokeWidth: "1.5", "aria-hidden": "true", children: _jsx("path", { className: "jini-icon-path", d: "m11 4-5 5 5 5" }) });
|
|
23
|
-
}
|
|
24
|
-
export function NextIcon(_required, _optional = {}) {
|
|
25
|
-
return _jsx("svg", { className: "jini-icon", viewBox: "0 0 18 18", fill: "none", stroke: "currentColor", strokeWidth: "1.5", "aria-hidden": "true", children: _jsx("path", { className: "jini-icon-path", d: "m7 4 5 5-5 5" }) });
|
|
26
|
-
}
|
|
27
18
|
export function AllIcon(_required, _optional = {}) {
|
|
28
19
|
return _jsxs("svg", { className: "jini-icon", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("rect", { className: "jini-icon-rect", x: "4", y: "4", width: "6.5", height: "6.5", rx: "1.2" }), _jsx("rect", { className: "jini-icon-rect", x: "13.5", y: "4", width: "6.5", height: "6.5", rx: "1.2" }), _jsx("rect", { className: "jini-icon-rect", x: "4", y: "13.5", width: "6.5", height: "6.5", rx: "1.2" }), _jsx("rect", { className: "jini-icon-rect", x: "13.5", y: "13.5", width: "6.5", height: "6.5", rx: "1.2" })] });
|
|
29
20
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { MediaLightboxProps } from '../hooks/MediaLightbox.hooks.js';
|
|
2
2
|
/** One shared dialog for the grid: mounting N real dialogs to show at most one open
|
|
3
|
-
* at a time buys nothing and costs N DOM subtrees.
|
|
3
|
+
* at a time buys nothing and costs N DOM subtrees. Chrome, keyboard and focus come from
|
|
4
|
+
* the shared `Lightbox`; this only supplies the asset and its agent-addressable parts. */
|
|
4
5
|
export declare function MediaLightbox(props: MediaLightboxProps, _optional?: Record<string, never>): import("react").JSX.Element;
|
|
5
6
|
//# sourceMappingURL=MediaLightbox.d.ts.map
|
|
@@ -1,12 +1,18 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
2
|
-
import {
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Lightbox } from '@jini-ai/ui/admin-widgets';
|
|
3
3
|
import { useMediaLightbox } from '../hooks/MediaLightbox.hooks.js';
|
|
4
|
-
import { CloseIcon, PreviousIcon, NextIcon } from './MediaIcons.js';
|
|
5
4
|
import { MediaPreview } from './MediaCard.js';
|
|
6
5
|
/** One shared dialog for the grid: mounting N real dialogs to show at most one open
|
|
7
|
-
* at a time buys nothing and costs N DOM subtrees.
|
|
6
|
+
* at a time buys nothing and costs N DOM subtrees. Chrome, keyboard and focus come from
|
|
7
|
+
* the shared `Lightbox`; this only supplies the asset and its agent-addressable parts. */
|
|
8
8
|
export function MediaLightbox(props, _optional = {}) {
|
|
9
9
|
const vm = useMediaLightbox(props);
|
|
10
|
-
return (
|
|
10
|
+
return (_jsx(Lightbox, { ...vm.lightbox, className: "jini-media-lightbox", labels: { close: 'Close', previous: 'Previous', next: 'Next' }, partAttrs: MEDIA_LIGHTBOX_PARTS, children: vm.item && _jsx("div", { className: "jini-media-lightbox-media", children: _jsx(MediaPreview, { item: vm.item, api: props.api }, vm.item.id) }) }));
|
|
11
11
|
}
|
|
12
|
+
const MEDIA_LIGHTBOX_PARTS = {
|
|
13
|
+
dialog: { 'data-jini-part': 'media.lightbox', 'data-jini-size': 'large' },
|
|
14
|
+
close: { 'data-jini-part': 'media.lightbox.close', 'data-agent-element': 'media-lightbox-close' },
|
|
15
|
+
previous: { 'data-jini-part': 'media.lightbox.previous', 'data-agent-element': 'media-lightbox-prev' },
|
|
16
|
+
next: { 'data-jini-part': 'media.lightbox.next', 'data-agent-element': 'media-lightbox-next' },
|
|
17
|
+
};
|
|
12
18
|
//# sourceMappingURL=MediaLightbox.js.map
|
|
@@ -1,19 +1,65 @@
|
|
|
1
|
+
import type { RefObject } from 'react';
|
|
1
2
|
import type { TabViewProps } from '../../../core/react/bind-react.js';
|
|
2
3
|
import { createLibraryController } from '../../controllers/library.controller.js';
|
|
3
4
|
import type { MediaAsset } from '../../models.js';
|
|
5
|
+
import type { LibraryState } from '../../controllers/library.controller.js';
|
|
6
|
+
import type { MediaApiPort } from '../../ports.js';
|
|
7
|
+
type LibraryController = ReturnType<typeof createLibraryController>;
|
|
4
8
|
export declare function useLibraryTab({ params, permissions }: TabViewProps, _optional?: Record<string, never>): {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
purgeDialog: {
|
|
10
|
+
filename?: string;
|
|
11
|
+
open: boolean;
|
|
12
|
+
pending: boolean;
|
|
13
|
+
};
|
|
14
|
+
upload({ input, alt }: Parameters<LibraryController["upload"]>[0]): Promise<boolean>;
|
|
15
|
+
cancelPurge: () => void | undefined;
|
|
16
|
+
confirmPurge: () => Promise<void> | undefined;
|
|
17
|
+
t: {
|
|
18
|
+
readonly media: "Media";
|
|
19
|
+
readonly all: "All";
|
|
20
|
+
readonly images: "Images";
|
|
21
|
+
readonly videos: "Videos";
|
|
22
|
+
readonly providers: "External Providers";
|
|
23
|
+
readonly upload: "Upload";
|
|
24
|
+
readonly title: "Title";
|
|
25
|
+
readonly alt: "Alt text";
|
|
26
|
+
readonly save: "Save";
|
|
27
|
+
readonly cancel: "Cancel";
|
|
28
|
+
readonly empty: "No media found";
|
|
29
|
+
readonly loading: "Loading media…";
|
|
30
|
+
readonly choose: "Choose media";
|
|
31
|
+
readonly trash: "Trash";
|
|
32
|
+
readonly purge: "Delete permanently";
|
|
33
|
+
readonly purgeWarning: "This permanently deletes the file. This cannot be undone.";
|
|
34
|
+
readonly edit: "Edit metadata";
|
|
35
|
+
readonly preview: "View larger";
|
|
36
|
+
readonly replace: "Replace file";
|
|
37
|
+
readonly unavailable: "Provider service unavailable";
|
|
38
|
+
readonly untyped: "Some assets have no recorded content type and only appear under All.";
|
|
39
|
+
};
|
|
40
|
+
loading: boolean;
|
|
41
|
+
busy: boolean;
|
|
42
|
+
untyped: boolean;
|
|
10
43
|
statusFilter: string;
|
|
44
|
+
orderBy: import("../../models.js").MediaOrderBy;
|
|
45
|
+
search: string;
|
|
11
46
|
onStatus: ({ value }: {
|
|
12
47
|
value: string;
|
|
13
48
|
}) => void;
|
|
49
|
+
onSearch: ({ value: search }: {
|
|
50
|
+
value: string;
|
|
51
|
+
}) => void;
|
|
52
|
+
onOrder: ({ value }: {
|
|
53
|
+
value: string;
|
|
54
|
+
}) => void;
|
|
55
|
+
emptyLabel: string;
|
|
56
|
+
canUpload: boolean;
|
|
57
|
+
success: string | null;
|
|
58
|
+
gridRef: RefObject<HTMLDivElement | null>;
|
|
59
|
+
onRetry: () => void;
|
|
14
60
|
canPurge: boolean;
|
|
15
61
|
controller: {
|
|
16
|
-
getSnapshot: () => Readonly<
|
|
62
|
+
getSnapshot: () => Readonly<LibraryState>;
|
|
17
63
|
subscribe: ({ listener }: {
|
|
18
64
|
listener: () => void;
|
|
19
65
|
}) => () => void;
|
|
@@ -44,7 +90,7 @@ export declare function useLibraryTab({ params, permissions }: TabViewProps, _op
|
|
|
44
90
|
}, _optional?: Record<string, never>): Promise<boolean>;
|
|
45
91
|
dispose(_required?: Record<string, never>, _optional?: Record<string, never>): void;
|
|
46
92
|
} | null;
|
|
47
|
-
snapshot:
|
|
93
|
+
snapshot: LibraryState | null;
|
|
48
94
|
actions: {
|
|
49
95
|
onPurge?: () => void | undefined;
|
|
50
96
|
onRestore?: () => void;
|
|
@@ -55,7 +101,7 @@ export declare function useLibraryTab({ params, permissions }: TabViewProps, _op
|
|
|
55
101
|
busy: boolean;
|
|
56
102
|
}[];
|
|
57
103
|
items: readonly MediaAsset[];
|
|
58
|
-
mediaApi:
|
|
104
|
+
mediaApi: MediaApiPort;
|
|
59
105
|
editing: MediaAsset | null;
|
|
60
106
|
closeEdit: () => void;
|
|
61
107
|
saved: ({ message }?: {
|
|
@@ -64,42 +110,6 @@ export declare function useLibraryTab({ params, permissions }: TabViewProps, _op
|
|
|
64
110
|
lightboxIndex: number | null;
|
|
65
111
|
onNavigate: import("react").Dispatch<import("react").SetStateAction<number | null>>;
|
|
66
112
|
closeLightbox: () => void;
|
|
67
|
-
onSearch: ({ value: search }: {
|
|
68
|
-
value: string;
|
|
69
|
-
}) => void;
|
|
70
|
-
orderBy: import("../../models.js").MediaOrderBy;
|
|
71
|
-
onOrder: ({ value }: {
|
|
72
|
-
value: string;
|
|
73
|
-
}) => void;
|
|
74
|
-
search: string;
|
|
75
|
-
loading: boolean;
|
|
76
|
-
busy: boolean;
|
|
77
|
-
untyped: boolean;
|
|
78
|
-
upload({ input, alt }: Parameters<ReturnType<typeof createLibraryController>["upload"]>[0]): Promise<boolean>;
|
|
79
|
-
cancelPurge: () => void | undefined;
|
|
80
|
-
confirmPurge: () => Promise<void> | undefined;
|
|
81
|
-
t: {
|
|
82
|
-
readonly media: "Media";
|
|
83
|
-
readonly all: "All";
|
|
84
|
-
readonly images: "Images";
|
|
85
|
-
readonly videos: "Videos";
|
|
86
|
-
readonly providers: "External Providers";
|
|
87
|
-
readonly upload: "Upload";
|
|
88
|
-
readonly title: "Title";
|
|
89
|
-
readonly alt: "Alt text";
|
|
90
|
-
readonly save: "Save";
|
|
91
|
-
readonly cancel: "Cancel";
|
|
92
|
-
readonly empty: "No media found";
|
|
93
|
-
readonly loading: "Loading media…";
|
|
94
|
-
readonly choose: "Choose media";
|
|
95
|
-
readonly trash: "Trash";
|
|
96
|
-
readonly purge: "Delete permanently";
|
|
97
|
-
readonly purgeWarning: "This permanently deletes the file. This cannot be undone.";
|
|
98
|
-
readonly edit: "Edit metadata";
|
|
99
|
-
readonly preview: "View larger";
|
|
100
|
-
readonly replace: "Replace file";
|
|
101
|
-
readonly unavailable: "Provider service unavailable";
|
|
102
|
-
readonly untyped: "Some assets have no recorded content type and only appear under All.";
|
|
103
|
-
};
|
|
104
113
|
};
|
|
114
|
+
export {};
|
|
105
115
|
//# sourceMappingURL=LibraryTab.hooks.d.ts.map
|