@openrails/contentkit-ui 0.85.1 → 0.86.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.
Files changed (154) hide show
  1. package/README.md +7 -4
  2. package/dist/client/beacons.d.ts +13 -4
  3. package/dist/client/beacons.js +14 -7
  4. package/dist/client/beacons.js.map +1 -1
  5. package/dist/client/client.d.ts +3 -0
  6. package/dist/client/client.js +29 -27
  7. package/dist/client/client.js.map +1 -1
  8. package/dist/client/codes.d.ts +6 -1
  9. package/dist/client/codes.js +4 -1
  10. package/dist/client/codes.js.map +1 -1
  11. package/dist/client/generated/error-codes.js +1 -1
  12. package/dist/client/generated/error-codes.js.map +1 -1
  13. package/dist/client/generated/routes.d.ts +14 -1
  14. package/dist/client/generated/routes.js +17 -1
  15. package/dist/client/generated/routes.js.map +1 -1
  16. package/dist/client/generated/wire.d.ts +29 -0
  17. package/dist/client/generated/wire.js.map +1 -1
  18. package/dist/client/index.d.ts +2 -1
  19. package/dist/client/media/queue.d.ts +4 -2
  20. package/dist/client/media/queue.js +18 -12
  21. package/dist/client/media/queue.js.map +1 -1
  22. package/dist/client/media/rules.d.ts +7 -1
  23. package/dist/client/media/rules.js +27 -21
  24. package/dist/client/media/rules.js.map +1 -1
  25. package/dist/client/stats.d.ts +32 -0
  26. package/dist/client/stats.js +35 -0
  27. package/dist/client/stats.js.map +1 -0
  28. package/dist/client.js +30 -29
  29. package/dist/components/admin/content-manager.js +206 -206
  30. package/dist/components/admin/content-manager.js.map +1 -1
  31. package/dist/components/admin/group-manager.js +71 -70
  32. package/dist/components/admin/group-manager.js.map +1 -1
  33. package/dist/components/admin/media-item-panel.d.ts +24 -7
  34. package/dist/components/admin/media-item-panel.js +209 -197
  35. package/dist/components/admin/media-item-panel.js.map +1 -1
  36. package/dist/components/admin/poll-manager.js +25 -25
  37. package/dist/components/admin/stats-dashboard.d.ts +22 -0
  38. package/dist/components/admin/stats-dashboard.js +257 -0
  39. package/dist/components/admin/stats-dashboard.js.map +1 -0
  40. package/dist/components/content/card.js +42 -42
  41. package/dist/components/content/card.js.map +1 -1
  42. package/dist/components/content/editors.js +455 -427
  43. package/dist/components/content/editors.js.map +1 -1
  44. package/dist/components/content/grid.js +47 -47
  45. package/dist/components/content/index.d.ts +2 -1
  46. package/dist/components/content/listing.js +34 -34
  47. package/dist/components/content/listing.js.map +1 -1
  48. package/dist/components/content/paywall.d.ts +17 -5
  49. package/dist/components/content/paywall.js +115 -100
  50. package/dist/components/content/paywall.js.map +1 -1
  51. package/dist/components/content/reader-stats.d.ts +12 -0
  52. package/dist/components/content/reader-stats.js +47 -0
  53. package/dist/components/content/reader-stats.js.map +1 -0
  54. package/dist/components/groups/banner.js +33 -33
  55. package/dist/components/groups/directory.js +11 -11
  56. package/dist/components/groups/editor.js +293 -293
  57. package/dist/components/groups/editor.js.map +1 -1
  58. package/dist/components/groups/header.js +27 -27
  59. package/dist/components/groups/header.js.map +1 -1
  60. package/dist/components/groups/memberships.js +180 -180
  61. package/dist/components/groups/parts.d.ts +0 -2
  62. package/dist/components/groups/parts.js +9 -27
  63. package/dist/components/groups/parts.js.map +1 -1
  64. package/dist/components/media-folder-editor.js +239 -189
  65. package/dist/components/media-folder-editor.js.map +1 -1
  66. package/dist/components/notifications.js +17 -17
  67. package/dist/components/slot-upload.d.ts +2 -2
  68. package/dist/components/slot-upload.js +84 -79
  69. package/dist/components/slot-upload.js.map +1 -1
  70. package/dist/components/social/bans.js +34 -34
  71. package/dist/components/social/moderation.js +52 -48
  72. package/dist/components/social/moderation.js.map +1 -1
  73. package/dist/components/video-player.d.ts +2 -0
  74. package/dist/components/video-player.js +318 -314
  75. package/dist/components/video-player.js.map +1 -1
  76. package/dist/i18n/context.d.ts +2 -0
  77. package/dist/i18n/context.js +23 -5
  78. package/dist/i18n/context.js.map +1 -1
  79. package/dist/index.d.ts +2 -1
  80. package/dist/index.js +12 -10
  81. package/dist/locales/admin/de.js +27 -0
  82. package/dist/locales/admin/de.js.map +1 -1
  83. package/dist/locales/admin/en.d.ts +27 -0
  84. package/dist/locales/admin/en.js +27 -0
  85. package/dist/locales/admin/en.js.map +1 -1
  86. package/dist/locales/admin/es.js +27 -0
  87. package/dist/locales/admin/es.js.map +1 -1
  88. package/dist/locales/admin/ja.js +27 -0
  89. package/dist/locales/admin/ja.js.map +1 -1
  90. package/dist/locales/admin/ko.js +27 -0
  91. package/dist/locales/admin/ko.js.map +1 -1
  92. package/dist/locales/admin/zh.js +27 -0
  93. package/dist/locales/admin/zh.js.map +1 -1
  94. package/dist/locales/content/de.js +6 -0
  95. package/dist/locales/content/de.js.map +1 -1
  96. package/dist/locales/content/en.d.ts +6 -0
  97. package/dist/locales/content/en.js +6 -0
  98. package/dist/locales/content/en.js.map +1 -1
  99. package/dist/locales/content/es.js +6 -0
  100. package/dist/locales/content/es.js.map +1 -1
  101. package/dist/locales/content/ja.js +6 -0
  102. package/dist/locales/content/ja.js.map +1 -1
  103. package/dist/locales/content/ko.js +6 -0
  104. package/dist/locales/content/ko.js.map +1 -1
  105. package/dist/locales/content/zh.js +6 -0
  106. package/dist/locales/content/zh.js.map +1 -1
  107. package/dist/locales/de.js +1 -0
  108. package/dist/locales/de.js.map +1 -1
  109. package/dist/locales/en.d.ts +34 -0
  110. package/dist/locales/en.js +1 -0
  111. package/dist/locales/en.js.map +1 -1
  112. package/dist/locales/es.js +1 -0
  113. package/dist/locales/es.js.map +1 -1
  114. package/dist/locales/ja.js +1 -0
  115. package/dist/locales/ja.js.map +1 -1
  116. package/dist/locales/ko.js +1 -0
  117. package/dist/locales/ko.js.map +1 -1
  118. package/dist/locales/zh.js +1 -0
  119. package/dist/locales/zh.js.map +1 -1
  120. package/dist/react/admin.js +22 -23
  121. package/dist/react/admin.js.map +1 -1
  122. package/dist/react/canonical.d.ts +4 -3
  123. package/dist/react/canonical.js +34 -33
  124. package/dist/react/canonical.js.map +1 -1
  125. package/dist/react/contents.js +144 -144
  126. package/dist/react/contents.js.map +1 -1
  127. package/dist/react/detail.d.ts +12 -6
  128. package/dist/react/detail.js +31 -24
  129. package/dist/react/detail.js.map +1 -1
  130. package/dist/react/folder.d.ts +7 -2
  131. package/dist/react/folder.js +165 -147
  132. package/dist/react/folder.js.map +1 -1
  133. package/dist/react/groups.d.ts +0 -1
  134. package/dist/react/groups.js +13 -12
  135. package/dist/react/groups.js.map +1 -1
  136. package/dist/react/index.d.ts +4 -2
  137. package/dist/react/location.d.ts +11 -0
  138. package/dist/react/location.js +18 -0
  139. package/dist/react/location.js.map +1 -0
  140. package/dist/react/public.d.ts +8 -0
  141. package/dist/react/public.js +32 -27
  142. package/dist/react/public.js.map +1 -1
  143. package/dist/react/stats.d.ts +24 -0
  144. package/dist/react/stats.js +28 -0
  145. package/dist/react/stats.js.map +1 -0
  146. package/dist/react/use-resource.js +8 -7
  147. package/dist/react/use-resource.js.map +1 -1
  148. package/dist/react/versions.js +20 -20
  149. package/dist/react.js +26 -24
  150. package/dist/styles.css +1 -1
  151. package/dist/urls/index.d.ts +35 -10
  152. package/dist/urls.js +100 -70
  153. package/dist/urls.js.map +1 -1
  154. package/package.json +1 -1
@@ -1,42 +1,49 @@
1
1
  import { keyOf as e, useContentScope as t, useResource as n } from "./use-resource.js";
2
- import { useMemo as r } from "react";
2
+ import { parseVersionCode as r } from "../urls.js";
3
+ import { useVersionParam as i } from "./location.js";
4
+ import { useMemo as a } from "react";
3
5
  //#region src/react/detail.ts
4
- function i(e) {
6
+ function o(e) {
5
7
  return (e?.versions ?? []).filter((e) => e.live).sort((e, t) => e.position - t.position);
6
8
  }
7
- function a(e, t) {
8
- let n = i(e);
9
+ function s(e, t) {
10
+ let n = o(e);
9
11
  return (t ? n.find((e) => e.languages.includes(t)) : void 0) ?? n[0] ?? null;
10
12
  }
11
- function o(o, s = {}) {
12
- let { client: c, store: l, scope: u, language: d } = t(s.client), f = s.language ?? d, p = o ? e("content-detail", u, o, f) : null, m = n(l, p, {
13
+ function c(e, t) {
14
+ if (!t) return;
15
+ let n = r(t);
16
+ return e.find((e) => e.id === t) ?? (n ? e.find((e) => e.code === n) : void 0);
17
+ }
18
+ function l(r, l = {}) {
19
+ let { client: u, store: d, scope: f, language: p } = t(l.client), m = l.language ?? p, [h] = i({ location: l.location }), g = l.version === void 0 ? h : l.version, _ = r ? e("content-detail", f, r, m) : null, v = n(d, _, {
13
20
  type: "content-detail",
14
- id: o ?? void 0
15
- }, (e) => c.contents.get(o, f, e)), h = m.data ?? null;
16
- return r(() => {
17
- let e = i(h), t = e.find((e) => e.id === s.version) ?? a(h, f);
21
+ id: r ?? void 0
22
+ }, (e) => u.contents.get(r, m, e)), y = v.data ?? null;
23
+ return a(() => {
24
+ let e = o(y), t = c(e, g) ?? s(y, m);
18
25
  return {
19
- content: h,
26
+ content: y,
20
27
  versions: e,
21
28
  version: t,
22
- decision: t?.decision ?? h?.decision ?? null,
29
+ decision: t?.decision ?? y?.decision ?? null,
23
30
  languages: [...new Set(e.flatMap((e) => e.languages))],
24
- loading: !!p && (m.loading || !m.loaded),
25
- error: m.error,
26
- reload: m.reload
31
+ loading: !!_ && (v.loading || !v.loaded),
32
+ error: v.error,
33
+ reload: v.reload
27
34
  };
28
35
  }, [
29
- h,
30
- s.version,
31
- f,
32
- p,
33
- m.loading,
34
- m.loaded,
35
- m.error,
36
- m.reload
36
+ y,
37
+ g,
38
+ m,
39
+ _,
40
+ v.loading,
41
+ v.loaded,
42
+ v.error,
43
+ v.reload
37
44
  ]);
38
45
  }
39
46
  //#endregion
40
- export { a as defaultVersion, i as liveVersions, o as useContentDetail };
47
+ export { s as defaultVersion, c as findVersion, o as liveVersions, l as useContentDetail };
41
48
 
42
49
  //# sourceMappingURL=detail.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"detail.js","names":[],"sources":["../../src/react/detail.ts"],"sourcesContent":["import { useMemo } from \"react\";\nimport type { ContentKitClient } from \"../client/client.js\";\nimport type { ContentKitError } from \"../client/errors.js\";\nimport type { Content, Decision, Version } from \"../client/generated/wire.js\";\nimport { keyOf, useContentScope, useResource } from \"./use-resource.js\";\n\n/** A content's live versions, first first. */\nexport function liveVersions(c: Content | null | undefined): Version[] {\n return (c?.versions ?? []).filter((v) => v.live).sort((a, b) => a.position - b.position);\n}\n\n/** The version a reader of language opens by default: the first live one serving it, else the first live one. */\nexport function defaultVersion(c: Content | null | undefined, language?: string): Version | null {\n const live = liveVersions(c);\n return (language ? live.find((v) => v.languages.includes(language)) : undefined) ?? live[0] ?? null;\n}\n\nexport interface UseContentDetail {\n content: Content | null;\n /** Live versions, first first. */\n versions: Version[];\n /** The version shown: the one asked for when live, else the language's default. */\n version: Version | null;\n /** The shown version's access decision: allowed, what is sold, previews. */\n decision: Decision | null;\n /** Every language a live version serves, in version order. */\n languages: string[];\n loading: boolean;\n error?: ContentKitError;\n reload: () => void;\n}\n\n/**\n * A content page's data: text in the reader's language, live versions with\n * their segments and access decisions, groups, attributes and the version to show.\n */\nexport function useContentDetail(id: string | null | undefined, o: { language?: string; version?: string | null; client?: ContentKitClient } = {}): UseContentDetail {\n const { client, store, scope, language: provided } = useContentScope(o.client);\n const language = o.language ?? provided;\n const key = id ? keyOf(\"content-detail\", scope, id, language) : null;\n const r = useResource<Content>(store, key, { type: \"content-detail\", id: id ?? undefined }, (s) => client.contents.get(id!, language, s));\n const content = r.data ?? null;\n return useMemo(() => {\n const versions = liveVersions(content);\n const version = versions.find((v) => v.id === o.version) ?? defaultVersion(content, language);\n return {\n content,\n versions,\n version,\n decision: version?.decision ?? content?.decision ?? null,\n languages: [...new Set(versions.flatMap((v) => v.languages))],\n loading: !!key && (r.loading || !r.loaded),\n error: r.error,\n reload: r.reload,\n };\n }, [content, o.version, language, key, r.loading, r.loaded, r.error, r.reload]);\n}\n"],"mappings":";;;AAOA,SAAgB,EAAa,GAA0C;CACrE,QAAQ,GAAG,YAAY,CAAC,EAAA,CAAG,QAAQ,MAAM,EAAE,IAAI,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ;AACzF;AAGA,SAAgB,EAAe,GAA+B,GAAmC;CAC/F,IAAM,IAAO,EAAa,CAAC;CAC3B,QAAQ,IAAW,EAAK,MAAM,MAAM,EAAE,UAAU,SAAS,CAAQ,CAAC,IAAI,KAAA,MAAc,EAAK,MAAM;AACjG;AAqBA,SAAgB,EAAiB,GAA+B,IAA+E,CAAC,GAAqB;CACnK,IAAM,EAAE,WAAQ,UAAO,UAAO,UAAU,MAAa,EAAgB,EAAE,MAAM,GACvE,IAAW,EAAE,YAAY,GACzB,IAAM,IAAK,EAAM,kBAAkB,GAAO,GAAI,CAAQ,IAAI,MAC1D,IAAI,EAAqB,GAAO,GAAK;EAAE,MAAM;EAAkB,IAAI,KAAM,KAAA;CAAU,IAAI,MAAM,EAAO,SAAS,IAAI,GAAK,GAAU,CAAC,CAAC,GAClI,IAAU,EAAE,QAAQ;CAC1B,OAAO,QAAc;EACnB,IAAM,IAAW,EAAa,CAAO,GAC/B,IAAU,EAAS,MAAM,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,EAAe,GAAS,CAAQ;EAC5F,OAAO;GACL;GACA;GACA;GACA,UAAU,GAAS,YAAY,GAAS,YAAY;GACpD,WAAW,CAAC,GAAG,IAAI,IAAI,EAAS,SAAS,MAAM,EAAE,SAAS,CAAC,CAAC;GAC5D,SAAS,CAAC,CAAC,MAAQ,EAAE,WAAW,CAAC,EAAE;GACnC,OAAO,EAAE;GACT,QAAQ,EAAE;EACZ;CACF,GAAG;EAAC;EAAS,EAAE;EAAS;EAAU;EAAK,EAAE;EAAS,EAAE;EAAQ,EAAE;EAAO,EAAE;CAAM,CAAC;AAChF"}
1
+ {"version":3,"file":"detail.js","names":[],"sources":["../../src/react/detail.ts"],"sourcesContent":["import { useMemo } from \"react\";\nimport type { ContentKitClient } from \"../client/client.js\";\nimport type { ContentKitError } from \"../client/errors.js\";\nimport type { Content, Decision, Version } from \"../client/generated/wire.js\";\nimport { parseVersionCode } from \"../urls/index.js\";\nimport { useVersionParam } from \"./location.js\";\nimport { keyOf, useContentScope, useResource } from \"./use-resource.js\";\n\n/** A content's live versions, first first. */\nexport function liveVersions(c: Content | null | undefined): Version[] {\n return (c?.versions ?? []).filter((v) => v.live).sort((a, b) => a.position - b.position);\n}\n\n/** The version a reader of language opens by default: the first live one serving it, else the first live one. */\nexport function defaultVersion(c: Content | null | undefined, language?: string): Version | null {\n const live = liveVersions(c);\n return (language ? live.find((v) => v.languages.includes(language)) : undefined) ?? live[0] ?? null;\n}\n\n/** The version selected names: its code (any spelling, the page's ?v=) or its id; undefined when none. */\nexport function findVersion(versions: readonly Version[], selected: string | null | undefined): Version | undefined {\n if (!selected) return undefined;\n const code = parseVersionCode(selected);\n return versions.find((v) => v.id === selected) ?? (code ? versions.find((v) => v.code === code) : undefined);\n}\n\nexport interface UseContentDetail {\n content: Content | null;\n /** Live versions, first first. */\n versions: Version[];\n /** The version shown: the one asked for (?v=) when live, else the language's default. */\n version: Version | null;\n /** The shown version's access decision: allowed, what is sold, previews. */\n decision: Decision | null;\n /** Every language a live version serves, in version order. */\n languages: string[];\n loading: boolean;\n error?: ContentKitError;\n reload: () => void;\n}\n\nexport interface ContentDetailOptions {\n language?: string;\n /** The version to show, by code or id; default the page's ?v=. Unknown or not live: the language's default. */\n version?: string | null;\n /** The page's location for its ?v=; default window.location. */\n location?: string;\n client?: ContentKitClient;\n}\n\n/**\n * A content page's data: text in the reader's language, live versions with\n * their segments and access decisions, groups, attributes and the version to show.\n */\nexport function useContentDetail(id: string | null | undefined, o: ContentDetailOptions = {}): UseContentDetail {\n const { client, store, scope, language: provided } = useContentScope(o.client);\n const language = o.language ?? provided;\n const [param] = useVersionParam({ location: o.location });\n const selected = o.version === undefined ? param : o.version;\n const key = id ? keyOf(\"content-detail\", scope, id, language) : null;\n const r = useResource<Content>(store, key, { type: \"content-detail\", id: id ?? undefined }, (s) => client.contents.get(id!, language, s));\n const content = r.data ?? null;\n return useMemo(() => {\n const versions = liveVersions(content);\n const version = findVersion(versions, selected) ?? defaultVersion(content, language);\n return {\n content,\n versions,\n version,\n decision: version?.decision ?? content?.decision ?? null,\n languages: [...new Set(versions.flatMap((v) => v.languages))],\n loading: !!key && (r.loading || !r.loaded),\n error: r.error,\n reload: r.reload,\n };\n }, [content, selected, language, key, r.loading, r.loaded, r.error, r.reload]);\n}\n"],"mappings":";;;;;AASA,SAAgB,EAAa,GAA0C;CACrE,QAAQ,GAAG,YAAY,CAAC,EAAA,CAAG,QAAQ,MAAM,EAAE,IAAI,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ;AACzF;AAGA,SAAgB,EAAe,GAA+B,GAAmC;CAC/F,IAAM,IAAO,EAAa,CAAC;CAC3B,QAAQ,IAAW,EAAK,MAAM,MAAM,EAAE,UAAU,SAAS,CAAQ,CAAC,IAAI,KAAA,MAAc,EAAK,MAAM;AACjG;AAGA,SAAgB,EAAY,GAA8B,GAA0D;CAClH,IAAI,CAAC,GAAU;CACf,IAAM,IAAO,EAAiB,CAAQ;CACtC,OAAO,EAAS,MAAM,MAAM,EAAE,OAAO,CAAQ,MAAM,IAAO,EAAS,MAAM,MAAM,EAAE,SAAS,CAAI,IAAI,KAAA;AACpG;AA8BA,SAAgB,EAAiB,GAA+B,IAA0B,CAAC,GAAqB;CAC9G,IAAM,EAAE,WAAQ,UAAO,UAAO,UAAU,MAAa,EAAgB,EAAE,MAAM,GACvE,IAAW,EAAE,YAAY,GACzB,CAAC,KAAS,EAAgB,EAAE,UAAU,EAAE,SAAS,CAAC,GAClD,IAAW,EAAE,YAAY,KAAA,IAAY,IAAQ,EAAE,SAC/C,IAAM,IAAK,EAAM,kBAAkB,GAAO,GAAI,CAAQ,IAAI,MAC1D,IAAI,EAAqB,GAAO,GAAK;EAAE,MAAM;EAAkB,IAAI,KAAM,KAAA;CAAU,IAAI,MAAM,EAAO,SAAS,IAAI,GAAK,GAAU,CAAC,CAAC,GAClI,IAAU,EAAE,QAAQ;CAC1B,OAAO,QAAc;EACnB,IAAM,IAAW,EAAa,CAAO,GAC/B,IAAU,EAAY,GAAU,CAAQ,KAAK,EAAe,GAAS,CAAQ;EACnF,OAAO;GACL;GACA;GACA;GACA,UAAU,GAAS,YAAY,GAAS,YAAY;GACpD,WAAW,CAAC,GAAG,IAAI,IAAI,EAAS,SAAS,MAAM,EAAE,SAAS,CAAC,CAAC;GAC5D,SAAS,CAAC,CAAC,MAAQ,EAAE,WAAW,CAAC,EAAE;GACnC,OAAO,EAAE;GACT,QAAQ,EAAE;EACZ;CACF,GAAG;EAAC;EAAS;EAAU;EAAU;EAAK,EAAE;EAAS,EAAE;EAAQ,EAAE;EAAO,EAAE;CAAM,CAAC;AAC/E"}
@@ -49,6 +49,11 @@ export interface UseMediaFolder {
49
49
  uploads: FileInfo[];
50
50
  /** The upload queue; a file leaves it once the editor read lists it. */
51
51
  queue: UseUploadQueue;
52
+ /**
53
+ * Uploads on the server not yet added and not in the queue: an earlier
54
+ * visit's, or another editor's. commit() adds them; remove() discards them.
55
+ */
56
+ pending: FileInfo[];
52
57
  /**
53
58
  * Files added before the item and its editor read (the upload rules) were
54
59
  * known. They are screened and queued when the rules arrive, or refused
@@ -68,7 +73,7 @@ export interface UseMediaFolder {
68
73
  edit: (path: string, edit: Edit | null) => Promise<void>;
69
74
  /** Uploads file in place of the upload at path (same position and meta, no edit). */
70
75
  replace: (path: string, file: File) => Promise<void>;
71
- /** Commits the uploaded files in queue order. */
76
+ /** Commits the uploaded files in queue order, then the pending ones. */
72
77
  commit: () => Promise<FileInfo[]>;
73
78
  /** Stops every upload, aborts its multipart upload and empties the queue (before deleting a draft). */
74
79
  discard: () => void;
@@ -81,7 +86,7 @@ export interface UseMediaFolder {
81
86
  * Leaving the page now interrupts it.
82
87
  */
83
88
  busy: boolean;
84
- /** The item's uploads plus the files on their way in (waiting, queued, uploading, uploaded, being added); failed uploads are not counted. */
89
+ /** The item's uploads plus the files on their way in (waiting, queued, uploading, uploaded, pending, being added); failed uploads are not counted. */
85
90
  fileCount: number;
86
91
  /** The last update's or commit's failure; cleared by the next success. */
87
92
  error?: ContentKitError;
@@ -4,238 +4,256 @@ import { stem as i } from "../client/media/client.js";
4
4
  import { filesFor as a, isPattern as o, ruleDir as s, ruleFor as c, screenFiles as ee, uniqueName as te, uploadRules as l } from "../client/media/rules.js";
5
5
  import { useContentKitClient as u, useErrorReporter as d } from "./context.js";
6
6
  import { useUploadQueue as ne } from "./upload.js";
7
- import { useMediaRead as re } from "./read.js";
8
- import { useCallback as f, useEffect as p, useMemo as m, useRef as h, useState as g } from "react";
7
+ import { useMediaRead as f } from "./read.js";
8
+ import { useCallback as p, useEffect as m, useMemo as h, useRef as g, useState as _ } from "react";
9
9
  //#region src/react/folder.ts
10
- var ie = {
10
+ var re = {
11
11
  start: 0,
12
12
  end: 2 ** 53 - 1,
13
13
  chunk: 200
14
- }, _ = (e, t) => t.slice(s(e.path).length);
15
- function v(e, t) {
14
+ }, v = (e, t) => t.slice(s(e.path).length);
15
+ function y(e, t) {
16
16
  let n;
17
17
  for (let r of e?.files ?? []) !r.upload && r.from === t.path && r.url && r.type.startsWith("image/") && (!n || (r.w ?? Infinity) < (n.w ?? Infinity)) && (n = r);
18
18
  return n;
19
19
  }
20
- var ae = {
20
+ var ie = {
21
21
  kind: "",
22
22
  id: ""
23
- }, oe = (e) => e ? r(e) : "", y = /* @__PURE__ */ new WeakMap();
24
- function se(t) {
25
- let n = y.get(t);
26
- return n || y.set(t, n = new e("forbidden", "the editor read states no upload rules", { status: 403 })), n;
23
+ }, ae = (e) => e ? r(e) : "", b = /* @__PURE__ */ new WeakMap();
24
+ function oe(t) {
25
+ let n = b.get(t);
26
+ return n || b.set(t, n = new e("forbidden", "the editor read states no upload rules", { status: 403 })), n;
27
27
  }
28
- function ce(e, t) {
28
+ function se(e, t) {
29
29
  return e.filter((e) => e.status !== "failed" && !(e.status === "committed" && t.has(e.path)));
30
30
  }
31
- function b(r, v = {}) {
32
- let y = u(v.client), b = d(v.onError), x = r ?? null, S = oe(x), C = x ?? ae, w = re(C, {
31
+ function x(r, y = {}) {
32
+ let b = u(y.client), x = d(y.onError), S = r ?? null, C = ae(S), w = S ?? ie, T = f(w, {
33
33
  editor: !0,
34
- window: ie,
35
- poll: v.poll,
36
- client: y,
37
- read: x ? void 0 : null
38
- }), T = l(w.read), E = v.paths?.join("\n"), D = m(() => E === void 0 ? T.filter((e) => o(e.path) && !e.named).map((e) => e.path) : E.split("\n").filter(Boolean), [E, T]), O = m(() => {
39
- let e = T.length ? T : D.map((e) => ({ path: e }));
40
- return D.map((t) => ({
34
+ window: re,
35
+ poll: y.poll,
36
+ client: b,
37
+ read: S ? void 0 : null
38
+ }), E = l(T.read), D = y.paths?.join("\n"), O = h(() => D === void 0 ? E.filter((e) => o(e.path) && !e.named).map((e) => e.path) : D.split("\n").filter(Boolean), [D, E]), k = h(() => {
39
+ let e = E.length ? E : O.map((e) => ({ path: e }));
40
+ return O.map((t) => ({
41
41
  path: t,
42
- rule: T.find((e) => e.path === t),
43
- files: a(w.read, { path: t }, e)
42
+ rule: E.find((e) => e.path === t),
43
+ files: a(T.read, { path: t }, e)
44
44
  }));
45
45
  }, [
46
- D,
47
- T,
48
- w.read
49
- ]), k = m(() => O.flatMap((e) => e.files), [O]), A = m(() => new Set(k.map((e) => e.path)), [k]), j = ne({
50
- client: y,
51
- ref: C,
52
- path: `${s(D[0] ?? "{name}")}{name}`,
53
- concurrency: v.concurrency
54
- }), M = j.queue, N = m(() => j.items.filter((e) => !(e.status === "committed" && A.has(e.path))), [j.items, A]), le = {
55
- ...j,
56
- items: N
57
- }, [ue, P] = g([]), [F, I] = g([]), L = h([]), [R, de] = g(0), [z, fe] = g(!1), [pe, B] = g(), [me, V] = g(), H = me?.key === S ? me.error : void 0, U = h(v);
58
- U.current = v;
59
- let W = !!x && !!w.read?.uploads, G = x ? w.read ? w.read.uploads ? void 0 : se(w.read) : w.error : void 0, K = h({
60
- groups: O,
61
- ref: C,
62
- listed: A,
63
- ready: W,
64
- loadError: G
46
+ O,
47
+ E,
48
+ T.read
49
+ ]), A = h(() => k.flatMap((e) => e.files), [k]), j = h(() => new Set(A.map((e) => e.path)), [A]), M = h(() => {
50
+ let e = E.length ? E : O.map((e) => ({ path: e }));
51
+ return (T.read?.files ?? []).filter((t) => t.upload && t.unattached && O.includes(c(e, t.path)?.path ?? ""));
52
+ }, [
53
+ T.read,
54
+ E,
55
+ O
56
+ ]), N = ne({
57
+ client: b,
58
+ ref: w,
59
+ path: `${s(O[0] ?? "{name}")}{name}`,
60
+ concurrency: y.concurrency
61
+ }), P = N.queue, F = h(() => N.items.filter((e) => !(e.status === "committed" && j.has(e.path))), [N.items, j]), ce = {
62
+ ...N,
63
+ items: F
64
+ }, I = h(() => {
65
+ let e = new Set(N.items.map((e) => i(e.path)));
66
+ return M.filter((t) => !e.has(i(t.path)));
67
+ }, [M, N.items]), [le, L] = _([]), [R, z] = _([]), B = g([]), [ue, de] = _(0), [V, fe] = _(!1), [pe, H] = _(), [me, U] = _(), W = me?.key === C ? me.error : void 0, G = g(y);
68
+ G.current = y;
69
+ let K = !!S && !!T.read?.uploads, q = S ? T.read ? T.read.uploads ? void 0 : oe(T.read) : T.error : void 0, J = g({
70
+ groups: k,
71
+ ref: w,
72
+ listed: j,
73
+ unattached: M,
74
+ leftover: I,
75
+ ready: K,
76
+ loadError: q
65
77
  });
66
- K.current = {
67
- groups: O,
68
- ref: C,
69
- listed: A,
70
- ready: W,
71
- loadError: G
78
+ J.current = {
79
+ groups: k,
80
+ ref: w,
81
+ listed: j,
82
+ unattached: M,
83
+ leftover: I,
84
+ ready: K,
85
+ loadError: q
72
86
  };
73
- let he = f((e) => {
74
- let { groups: t, listed: n } = K.current, r = t.map((e) => e.rule ?? {
87
+ let he = p((e) => {
88
+ let { groups: t, listed: n, unattached: r, leftover: i } = J.current, a = t.map((e) => e.rule ?? {
75
89
  path: e.path,
76
90
  types: [],
77
91
  max_bytes: 0
78
- }), i = ce(M.getSnapshot().items, n), a = (e, t) => c(r, e)?.path === t.path, o = ee(e, r, (e) => t.find((t) => t.path === e.path).files.length + i.filter((t) => a(t.path, e)).length), l = /* @__PURE__ */ new Map(), u = (e) => {
79
- let n = l.get(e.path);
92
+ }), o = se(P.getSnapshot().items, n), l = (e, t) => c(a, e)?.path === t.path, u = ee(e, a, (e) => t.find((t) => t.path === e.path).files.length + i.filter((t) => l(t.path, e)).length + o.filter((t) => l(t.path, e)).length), d = /* @__PURE__ */ new Map(), ne = (e) => {
93
+ let n = d.get(e.path);
80
94
  if (!n) {
81
- let r = t.find((t) => t.path === e.path);
82
- n = [...r.files.map((e) => _(r, e.path)), ...i.filter((t) => a(t.path, e)).map((e) => _(r, e.path))], l.set(e.path, n);
95
+ let i = t.find((t) => t.path === e.path);
96
+ n = [i.files, r].flat().filter((t) => l(t.path, e)).map((e) => v(i, e.path)), n.push(...o.filter((t) => l(t.path, e)).map((e) => v(i, e.path))), d.set(e.path, n);
83
97
  }
84
98
  return n;
85
- }, d = /* @__PURE__ */ new Map();
86
- for (let { file: e, rule: t } of o.accepted) {
87
- let n = u(t), r = U.current.name?.(e) ?? te(e.name, n);
88
- n.push(r), d.set(e, s(t.path) + r);
99
+ }, f = /* @__PURE__ */ new Map();
100
+ for (let { file: e, rule: t } of u.accepted) {
101
+ let n = ne(t), r = G.current.name?.(e) ?? te(e.name, n);
102
+ n.push(r), f.set(e, s(t.path) + r);
89
103
  }
90
- d.size && (M.add(d.keys(), { path: (e) => d.get(e) }), M.start(), V(void 0)), P(o.refused);
91
- for (let e of o.refused) b(e.error, "upload", e.file.name);
92
- }, [M, b]), q = f(() => {
93
- let e = L.current, { ready: t, loadError: n } = K.current;
94
- return !e.length || !t && !n ? !1 : (L.current = [], I([]), t ? he(e) : P(e.map((e) => ({
104
+ f.size && (P.add(f.keys(), { path: (e) => f.get(e) }), P.start(), U(void 0)), L(u.refused);
105
+ for (let e of u.refused) x(e.error, "upload", e.file.name);
106
+ }, [P, x]), Y = p(() => {
107
+ let e = B.current, { ready: t, loadError: n } = J.current;
108
+ return !e.length || !t && !n ? !1 : (B.current = [], z([]), t ? he(e) : L(e.map((e) => ({
95
109
  file: e,
96
110
  error: n
97
111
  }))), !0);
98
- }, [he]), ge = f((e) => {
112
+ }, [he]), ge = p((e) => {
99
113
  let t = [...e];
100
- t.length && (L.current = [...L.current, ...t], q() || I(L.current));
101
- }, [q]);
102
- p(() => void q(), [
103
- q,
104
- W,
105
- G
114
+ t.length && (B.current = [...B.current, ...t], Y() || z(B.current));
115
+ }, [Y]);
116
+ m(() => void Y(), [
117
+ Y,
118
+ K,
119
+ q
106
120
  ]);
107
- let J = f(async (e, t) => {
121
+ let X = p(async (e, t) => {
108
122
  de((e) => e + 1);
109
123
  try {
110
- t ? await t() : await y.media.commit(K.current.ref, e), B(void 0);
124
+ t ? await t() : await b.media.commit(J.current.ref, e), H(void 0);
111
125
  } catch (e) {
112
126
  let t = n(e);
113
- throw t.code !== "aborted" && B(t), b(t, "folder.update"), t;
127
+ throw t.code !== "aborted" && H(t), x(t, "folder.update"), t;
114
128
  } finally {
115
129
  de((e) => e - 1);
116
130
  }
117
- }, [y, b]), Y = f(async () => {
131
+ }, [b, x]), Z = p(async () => {
118
132
  fe(!0);
119
133
  try {
120
- let e = await M.commit(void 0, { head: U.current.commit === "auto" });
121
- return B(void 0), e;
134
+ let e = await P.commit(void 0, {
135
+ head: G.current.commit === "auto",
136
+ attach: J.current.leftover.map((e) => e.path)
137
+ });
138
+ return H(void 0), e;
122
139
  } catch (e) {
123
140
  let t = n(e);
124
- throw B(t), b(t, "folder.commit"), t;
141
+ throw H(t), x(t, "folder.commit"), t;
125
142
  } finally {
126
143
  fe(!1);
127
144
  }
128
- }, [M, b]);
129
- p(() => {
130
- for (let e of j.items) e.status === "committed" && (A.has(e.path) || !w.loading) && M.remove(e.id);
145
+ }, [P, x]);
146
+ m(() => {
147
+ for (let e of N.items) e.status === "committed" && (j.has(e.path) || !T.loading) && P.remove(e.id);
131
148
  }, [
132
- j.items,
133
- A,
134
- w.loading,
135
- M
149
+ N.items,
150
+ j,
151
+ T.loading,
152
+ P
136
153
  ]);
137
- let X = v.commit === "auto", Z = N.find((e) => e.status !== "committed")?.status === "uploaded";
138
- p(() => {
139
- X && Z && !z && !H && Y().catch((e) => V({
140
- key: S,
154
+ let _e = y.commit === "auto", ve = F.find((e) => e.status !== "committed")?.status === "uploaded" || I.length > 0 && !T.loading;
155
+ m(() => {
156
+ _e && ve && !V && !W && Z().catch((e) => U({
157
+ key: C,
141
158
  error: n(e)
142
159
  }));
143
160
  }, [
144
- X,
161
+ _e,
162
+ ve,
163
+ V,
164
+ W,
145
165
  Z,
146
- z,
147
- H,
148
- Y,
149
- S
166
+ C
150
167
  ]);
151
- let _e = f(async () => (V(void 0), Y()), [Y]), Q = h(/* @__PURE__ */ new Set());
152
- p(() => {
153
- for (let e of j.items) e.status === "failed" && e.error && !Q.current.has(e.error) && (Q.current.add(e.error), b(e.error, "upload", e.file.name));
154
- j.blocked && !Q.current.has(j.blocked) && (Q.current.add(j.blocked), b(j.blocked, "upload"));
168
+ let ye = p(async () => (U(void 0), Z()), [Z]), Q = g(/* @__PURE__ */ new Set());
169
+ m(() => {
170
+ for (let e of N.items) e.status === "failed" && e.error && !Q.current.has(e.error) && (Q.current.add(e.error), x(e.error, "upload", e.file.name));
171
+ N.blocked && !Q.current.has(N.blocked) && (Q.current.add(N.blocked), x(N.blocked, "upload"));
155
172
  }, [
156
- j.items,
157
- j.blocked,
158
- b
173
+ N.items,
174
+ N.blocked,
175
+ x
159
176
  ]);
160
- let $ = h(null);
161
- p(() => {
162
- if (!w.read) return;
163
- let e = k.filter((e) => e.failed);
164
- if ($.current?.key !== S) {
177
+ let $ = g(null);
178
+ m(() => {
179
+ if (!T.read) return;
180
+ let e = A.filter((e) => e.failed);
181
+ if ($.current?.key !== C) {
165
182
  $.current = {
166
- key: S,
183
+ key: C,
167
184
  seen: new Set(e.map((e) => `${e.path}:${e.failed.of}`))
168
185
  };
169
186
  return;
170
187
  }
171
188
  for (let n of e) {
172
189
  let e = `${n.path}:${n.failed.of}`;
173
- $.current.seen.has(e) || ($.current.seen.add(e), b(t(n.failed), "folder.process", n.path.split("/").pop()));
190
+ $.current.seen.has(e) || ($.current.seen.add(e), x(t(n.failed), "folder.process", n.path.split("/").pop()));
174
191
  }
175
192
  }, [
176
- w.read,
177
- k,
178
- b,
179
- S
180
- ]), p(() => void (w.error && b(w.error, "folder.load")), [w.error, b]);
181
- let ve = F.length > 0 || z || R > 0 || X && Z && !H || N.some((e) => e.status === "uploading" || e.status === "queued" && !j.blocked), ye = k.length + F.length + ce(N, A).length, be = (e) => K.current.groups.find((t) => c([{ path: t.path }], e));
193
+ T.read,
194
+ A,
195
+ x,
196
+ C
197
+ ]), m(() => void (T.error && x(T.error, "folder.load")), [T.error, x]);
198
+ let be = R.length > 0 || V || ue > 0 || _e && ve && !W || F.some((e) => e.status === "uploading" || e.status === "queued" && !N.blocked), xe = A.length + R.length + se(F, j).length + I.length, Se = (e) => J.current.groups.find((t) => c([{ path: t.path }], e));
182
199
  return {
183
- ref: x,
184
- options: v,
185
- read: w,
186
- groups: O,
187
- uploads: k,
188
- queue: le,
189
- waiting: F,
200
+ ref: S,
201
+ options: y,
202
+ read: T,
203
+ groups: k,
204
+ uploads: A,
205
+ queue: ce,
206
+ pending: I,
207
+ waiting: R,
190
208
  add: ge,
191
- refused: ue,
192
- dismiss: f(() => P([]), []),
193
- move: f((e, t) => J([{
209
+ refused: le,
210
+ dismiss: p(() => L([]), []),
211
+ move: p((e, t) => X([{
194
212
  op: "move",
195
213
  path: e,
196
214
  index: t
197
- }]), [J]),
198
- remove: f((e) => J(e.map((e) => ({
215
+ }]), [X]),
216
+ remove: p((e) => X(e.map((e) => ({
199
217
  op: "remove",
200
218
  path: e
201
- }))), [J]),
202
- rename: f((t, n) => {
203
- let r = be(t), a = (r ? s(r.path) : t.slice(0, t.lastIndexOf("/") + 1)) + n.trim();
219
+ }))), [X]),
220
+ rename: p((t, n) => {
221
+ let r = Se(t), a = (r ? s(r.path) : t.slice(0, t.lastIndexOf("/") + 1)) + n.trim();
204
222
  if (i(a) === i(t)) return Promise.resolve();
205
223
  if (r?.files.some((e) => i(e.path) === i(a))) {
206
224
  let t = new e("conflict", `${n} exists`, { status: 409 });
207
- return B(t), Promise.reject(t);
225
+ return H(t), Promise.reject(t);
208
226
  }
209
- return J([{
227
+ return X([{
210
228
  op: "rename",
211
229
  path: t,
212
230
  to: a
213
231
  }]);
214
- }, [J]),
215
- edit: f((e, t) => J([{
232
+ }, [X]),
233
+ edit: p((e, t) => X([{
216
234
  op: "edit",
217
235
  path: e,
218
236
  ...t ? { edit: t } : {}
219
- }]), [J]),
220
- replace: f((e, t) => J([], () => y.media.put(t, {
221
- ref: K.current.ref,
237
+ }]), [X]),
238
+ replace: p((e, t) => X([], () => b.media.put(t, {
239
+ ref: J.current.ref,
222
240
  path: i(e),
223
241
  wait: !1
224
- })), [J, y]),
225
- commit: _e,
226
- discard: f(() => {
227
- L.current = [], I([]);
228
- for (let e of M.getSnapshot().items) M.remove(e.id);
229
- M.pause();
230
- }, [M]),
231
- updating: R > 0,
232
- committing: z,
233
- busy: ve,
234
- fileCount: ye,
235
- error: pe ?? H
242
+ })), [X, b]),
243
+ commit: ye,
244
+ discard: p(() => {
245
+ B.current = [], z([]);
246
+ for (let e of P.getSnapshot().items) P.remove(e.id);
247
+ P.pause();
248
+ }, [P]),
249
+ updating: ue > 0,
250
+ committing: V,
251
+ busy: be,
252
+ fileCount: xe,
253
+ error: pe ?? W
236
254
  };
237
255
  }
238
256
  //#endregion
239
- export { _ as nameIn, v as thumbnailOf, b as useMediaFolder };
257
+ export { v as nameIn, y as thumbnailOf, x as useMediaFolder };
240
258
 
241
259
  //# sourceMappingURL=folder.js.map