@platforma-sdk/ui-vue 1.66.1 → 1.67.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 (65) hide show
  1. package/.turbo/turbo-build.log +21 -15
  2. package/.turbo/turbo-formatter$colon$check.log +2 -2
  3. package/.turbo/turbo-linter$colon$check.log +2 -2
  4. package/.turbo/turbo-types$colon$check.log +1 -1
  5. package/CHANGELOG.md +26 -0
  6. package/dist/__tests__/setup.d.ts +2 -0
  7. package/dist/__tests__/setup.d.ts.map +1 -0
  8. package/dist/components/PlAdvancedFilter/FilterEditor.vue2.js +20 -20
  9. package/dist/components/PlAgColumnHeader/PlAgColumnHeader.js.map +1 -1
  10. package/dist/components/PlAgColumnHeader/PlAgColumnHeader.vue.d.ts.map +1 -1
  11. package/dist/components/PlAgColumnHeader/PlAgColumnHeader.vue2.js +43 -33
  12. package/dist/components/PlAgColumnHeader/PlAgColumnHeader.vue2.js.map +1 -1
  13. package/dist/components/PlAgColumnHeader/types.d.ts +1 -0
  14. package/dist/components/PlAgColumnHeader/types.d.ts.map +1 -1
  15. package/dist/components/PlAgDataTable/compositions/useFilterableColumns.js +5 -5
  16. package/dist/components/PlAgDataTable/sources/table-source-v2.d.ts.map +1 -1
  17. package/dist/components/PlAgDataTable/sources/table-source-v2.js +10 -11
  18. package/dist/components/PlAgDataTable/sources/table-source-v2.js.map +1 -1
  19. package/dist/components/PlAgDataTable/sources/table-state-v2.js +13 -13
  20. package/dist/components/PlDatasetSelector/PlDatasetSelector.js +9 -0
  21. package/dist/components/PlDatasetSelector/PlDatasetSelector.js.map +1 -0
  22. package/dist/components/PlDatasetSelector/PlDatasetSelector.style.css +1 -0
  23. package/dist/components/PlDatasetSelector/PlDatasetSelector.vue.d.ts +105 -0
  24. package/dist/components/PlDatasetSelector/PlDatasetSelector.vue.d.ts.map +1 -0
  25. package/dist/components/PlDatasetSelector/PlDatasetSelector.vue2.js +111 -0
  26. package/dist/components/PlDatasetSelector/PlDatasetSelector.vue2.js.map +1 -0
  27. package/dist/components/PlDatasetSelector/__tests__/PlDatasetSelector.jsdomtest.d.ts +2 -0
  28. package/dist/components/PlDatasetSelector/__tests__/PlDatasetSelector.jsdomtest.d.ts.map +1 -0
  29. package/dist/components/PlDatasetSelector/index.d.ts +2 -0
  30. package/dist/components/PlDatasetSelector/index.d.ts.map +1 -0
  31. package/dist/components/PlDatasetSelector/index.js +1 -0
  32. package/dist/components/PlTableFilters/PlTableFiltersV2.vue2.js +8 -8
  33. package/dist/index.js +15 -14
  34. package/dist/index.js.map +1 -1
  35. package/dist/internal/createAppV3.d.ts.map +1 -1
  36. package/dist/internal/createAppV3.js +74 -83
  37. package/dist/internal/createAppV3.js.map +1 -1
  38. package/dist/internal/getServices.d.ts +5 -0
  39. package/dist/internal/getServices.d.ts.map +1 -0
  40. package/dist/internal/getServices.js +19 -0
  41. package/dist/internal/getServices.js.map +1 -0
  42. package/dist/internal/service_factories.d.ts +2 -2
  43. package/dist/internal/service_factories.d.ts.map +1 -1
  44. package/dist/internal/service_factories.js.map +1 -1
  45. package/dist/internal/utils.d.ts +3 -0
  46. package/dist/internal/utils.d.ts.map +1 -0
  47. package/dist/internal/utils.js +16 -0
  48. package/dist/internal/utils.js.map +1 -0
  49. package/dist/lib.d.ts +1 -0
  50. package/dist/lib.d.ts.map +1 -1
  51. package/dist/lib.js +2 -0
  52. package/package.json +8 -6
  53. package/src/__tests__/setup.ts +10 -0
  54. package/src/components/PlAgColumnHeader/PlAgColumnHeader.vue +13 -7
  55. package/src/components/PlAgColumnHeader/types.ts +1 -0
  56. package/src/components/PlAgDataTable/sources/table-source-v2.ts +23 -21
  57. package/src/components/PlDatasetSelector/PlDatasetSelector.vue +164 -0
  58. package/src/components/PlDatasetSelector/__tests__/PlDatasetSelector.jsdomtest.ts +257 -0
  59. package/src/components/PlDatasetSelector/index.ts +1 -0
  60. package/src/internal/createAppV3.ts +10 -37
  61. package/src/internal/getServices.ts +36 -0
  62. package/src/internal/service_factories.ts +2 -2
  63. package/src/internal/utils.ts +25 -0
  64. package/src/lib.ts +2 -0
  65. package/vitest.config.mts +22 -0
@@ -5,148 +5,139 @@ import "../lib/util/helpers/dist/index.js";
5
5
  import { MultiError as r, ensureOutputHasStableFlag as i } from "../utils.js";
6
6
  import { parseQuery as a } from "../urls.js";
7
7
  import { UpdateSerializer as o } from "./UpdateSerializer.js";
8
- import { createUiServiceRegistry as s } from "./service_factories.js";
9
- import { computed as c, markRaw as l, reactive as u, ref as d } from "vue";
10
- import { buildServices as f, createNodeServiceProxy as p, deriveDataFromStorage as m, getPluginData as h, hasAbortError as g, isPluginOutputKey as _, pluginOutputPrefix as v, unwrapResult as y } from "@platforma-sdk/model";
8
+ import { logDebug as s, logError as c } from "./utils.js";
9
+ import { getServices as l } from "./getServices.js";
10
+ import { computed as u, markRaw as d, reactive as f, ref as p } from "vue";
11
+ import { deriveDataFromStorage as m, getPluginData as h, hasAbortError as g, isPluginOutputKey as _, pluginOutputPrefix as v, unwrapResult as y } from "@platforma-sdk/model";
11
12
  import { watchIgnorable as b } from "@vueuse/core";
12
13
  import { applyPatch as x } from "fast-json-patch";
13
14
  var S = (e) => ({
14
15
  authorId: e?.authorId ?? t(),
15
16
  localVersion: (e?.localVersion ?? 0) + 1
16
- }), C = (e) => {
17
- try {
18
- return JSON.stringify(e, null, 2);
19
- } catch (e) {
20
- return e instanceof Error ? e.message : String(e);
21
- }
22
- };
23
- function w(w, T, E) {
24
- let D = (e, ...t) => {
25
- E.debug && console.log(`%c>>> %c${e}`, "color: orange; font-weight: bold", "color: orange", ...t.map((e) => C(e)));
26
- }, O = (e, ...t) => {
27
- console.error(`%c>>> %c${e}`, "color: red; font-weight: bold", "color: red", ...t.map((e) => C(e)));
28
- }, k = {
17
+ });
18
+ function C(C, w, T) {
19
+ let E = T.debug ? s : () => {}, D = c, O = {
29
20
  isExternalSnapshot: !1,
30
21
  author: {
31
22
  authorId: t(),
32
23
  localVersion: 0
33
24
  }
34
- }, A = () => (k.author = S(k.author), D("nextAuthorMarker", k.author), k.author), j = d(!1), M = d(w.uTag), N = E.debounceSpan ?? 200, P = new o({ debounceSpan: N }), F = /* @__PURE__ */ new Map(), I = (e) => {
35
- let t = F.get(e);
36
- return t || (t = new o({ debounceSpan: N }), F.set(e, t)), t;
37
- }, L = new o({ debounceSpan: N }), R = /* @__PURE__ */ new Map(), z = d(w.value), B = async (e) => T.mutateStorage({
25
+ }, k = () => (O.author = S(O.author), E("nextAuthorMarker", O.author), O.author), A = p(!1), j = p(C.uTag), M = T.debounceSpan ?? 200, N = new o({ debounceSpan: M }), P = /* @__PURE__ */ new Map(), F = (e) => {
26
+ let t = P.get(e);
27
+ return t || (t = new o({ debounceSpan: M }), P.set(e, t)), t;
28
+ }, I = new o({ debounceSpan: M }), L = /* @__PURE__ */ new Map(), R = p(C.value), z = async (e) => w.mutateStorage({
38
29
  operation: "update-block-data",
39
30
  value: e
40
- }, A()), V = async (e, t) => T.mutateStorage({
31
+ }, k()), B = async (e, t) => w.mutateStorage({
41
32
  operation: "update-plugin-data",
42
33
  pluginId: e,
43
34
  value: t
44
- }, A()), H = async (e) => T.setNavigationState(e), U = c(() => {
45
- let e = Object.entries(z.value.outputs).filter(([e]) => !_(e)).map(([e, t]) => T.blockModelInfo.outputs[e]?.withStatus ? [e, i(t)] : [e, t.ok && t.value !== void 0 ? t.value : void 0]);
35
+ }, k()), V = async (e) => w.setNavigationState(e), H = u(() => {
36
+ let e = Object.entries(R.value.outputs).filter(([e]) => !_(e)).map(([e, t]) => w.blockModelInfo.outputs[e]?.withStatus ? [e, i(t)] : [e, t.ok && t.value !== void 0 ? t.value : void 0]);
46
37
  return Object.fromEntries(e);
47
- }), W = c(() => {
48
- let e = Object.entries(z.value.outputs).filter(([e]) => !_(e)).map(([e, t]) => [e, t && t.ok === !1 ? new r(t.errors) : void 0]);
38
+ }), U = u(() => {
39
+ let e = Object.entries(R.value.outputs).filter(([e]) => !_(e)).map(([e, t]) => [e, t && t.ok === !1 ? new r(t.errors) : void 0]);
49
40
  return Object.fromEntries(e);
50
- }), G = u({
41
+ }), W = f({
51
42
  apiVersion: 3,
52
43
  error: "",
53
44
  model: {
54
- data: n(m(z.value.blockStorage)),
55
- outputs: U,
56
- outputErrors: W
45
+ data: n(m(R.value.blockStorage)),
46
+ outputs: H,
47
+ outputErrors: U
57
48
  }
58
- }), { ignoreUpdates: K } = b(() => G.model, (e) => {
49
+ }), { ignoreUpdates: G } = b(() => W.model, (e) => {
59
50
  let t = n(e);
60
- D("setDataQueue appModel.model, data", t.data), P.run(() => B(t.data).then(y));
61
- }, { deep: !0 }), q = (e) => {
62
- D("updateAppModel", e), G.model.data = n(e.data);
51
+ E("setDataQueue appModel.model, data", t.data), N.run(() => z(t.data).then(y));
52
+ }, { deep: !0 }), K = (e) => {
53
+ E("updateAppModel", e), W.model.data = n(e.data);
63
54
  };
64
55
  (async () => {
65
56
  for (window.addEventListener("beforeunload", () => {
66
- j.value = !0, Promise.allSettled([Z.dispose(), T.dispose().then(y)]).catch((e) => {
67
- O("error in dispose", e);
57
+ A.value = !0, w.dispose().then(y).catch((e) => {
58
+ D("error in dispose", e);
68
59
  });
69
- }); !j.value;) try {
70
- let e = await T.getPatches(M.value).then(y);
71
- if (D("patches.length", e.value.length), D("uTagRef.value", M.value), D("patches.uTag", e.uTag), D("patches.author", e.author), D("data.author", k.author), M.value = e.uTag, e.value.length === 0) {
60
+ }); !A.value;) try {
61
+ let e = await w.getPatches(j.value).then(y);
62
+ if (E("patches.length", e.value.length), E("uTagRef.value", j.value), E("patches.uTag", e.uTag), E("patches.author", e.author), E("data.author", O.author), j.value = e.uTag, e.value.length === 0) {
72
63
  await new Promise((e) => setTimeout(e, 150));
73
64
  continue;
74
65
  }
75
- let t = k.author?.authorId !== e.author?.authorId;
76
- t || k.isExternalSnapshot ? (D("got external changes, applying them to the snapshot", e.value), K(() => {
77
- z.value = x(z.value, e.value, !1, !1).newDocument, q({ data: m(z.value.blockStorage) });
78
- for (let [e, t] of R) t.ignoreUpdates(() => {
79
- t.model.data = n(h(z.value.blockStorage, e));
66
+ let t = O.author?.authorId !== e.author?.authorId;
67
+ t || O.isExternalSnapshot ? (E("got external changes, applying them to the snapshot", e.value), G(() => {
68
+ R.value = x(R.value, e.value, !1, !1).newDocument, K({ data: m(R.value.blockStorage) });
69
+ for (let [e, t] of L) t.ignoreUpdates(() => {
70
+ t.model.data = n(h(R.value.blockStorage, e));
80
71
  });
81
- k.isExternalSnapshot = t;
82
- })) : (D("outputs changed", e.value), K(() => {
83
- z.value = x(z.value, e.value).newDocument;
72
+ O.isExternalSnapshot = t;
73
+ })) : (E("outputs changed", e.value), G(() => {
74
+ R.value = x(R.value, e.value).newDocument;
84
75
  })), await new Promise((e) => setTimeout(e, 150));
85
76
  } catch (e) {
86
- g(e) ? (D("patches loop aborted"), j.value = !0) : (O("error in patches loop", e), await new Promise((e) => setTimeout(e, 1e3)));
77
+ g(e) ? (E("patches loop aborted"), A.value = !0) : (D("error in patches loop", e), await new Promise((e) => setTimeout(e, 1e3)));
87
78
  }
88
79
  })();
89
- let J = () => n(G.model.data), Y = () => n(z.value.navigationState), X = {
90
- cloneData: J,
91
- cloneNavigationState: Y,
80
+ let q = () => n(W.model.data), J = () => n(R.value.navigationState), Y = {
81
+ cloneData: q,
82
+ cloneNavigationState: J,
92
83
  updateData(e) {
93
- let t = e(J());
94
- return D("updateData", t), G.model.data = t, P.run(() => B(t).then(y));
84
+ let t = e(q());
85
+ return E("updateData", t), W.model.data = t, N.run(() => z(t).then(y));
95
86
  },
96
87
  navigateTo(e) {
97
- let t = Y();
98
- return t.href = e, L.run(() => H(t).then(y));
88
+ let t = J();
89
+ return t.href = e, I.run(() => V(t).then(y));
99
90
  },
100
91
  async allSettled() {
101
92
  await e(0);
102
- let t = [P.allSettled(), ...Array.from(F.values()).map((e) => e.allSettled())];
93
+ let t = [N.allSettled(), ...Array.from(P.values()).map((e) => e.allSettled())];
103
94
  await Promise.all(t);
104
95
  }
105
- }, Z = s({ proxy: p(T.serviceDispatch) }), Q = f(T.serviceDispatch, Z), ee = (e) => {
106
- let t = v(e), a = c(() => {
96
+ }, X = l({ platforma: w }), Z = (e) => {
97
+ let t = v(e), a = u(() => {
107
98
  let e = {};
108
- for (let [n, r] of Object.entries(z.value.outputs)) {
99
+ for (let [n, r] of Object.entries(R.value.outputs)) {
109
100
  if (!n.startsWith(t)) continue;
110
101
  let a = n.slice(t.length);
111
- T.blockModelInfo.outputs[n]?.withStatus ? e[a] = r ? i(r) : void 0 : e[a] = r.ok && r.value !== void 0 ? r.value : void 0;
102
+ w.blockModelInfo.outputs[n]?.withStatus ? e[a] = r ? i(r) : void 0 : e[a] = r.ok && r.value !== void 0 ? r.value : void 0;
112
103
  }
113
104
  return e;
114
- }), o = c(() => {
105
+ }), o = u(() => {
115
106
  let e = {};
116
- for (let [n, i] of Object.entries(z.value.outputs)) n.startsWith(t) && (e[n.slice(t.length)] = i && i.ok === !1 ? new r(i.errors) : void 0);
107
+ for (let [n, i] of Object.entries(R.value.outputs)) n.startsWith(t) && (e[n.slice(t.length)] = i && i.ok === !1 ? new r(i.errors) : void 0);
117
108
  return e;
118
- }), s = u({
119
- data: n(h(z.value.blockStorage, e)),
109
+ }), s = f({
110
+ data: n(h(R.value.blockStorage, e)),
120
111
  outputs: a,
121
112
  outputErrors: o
122
- }), { ignoreUpdates: d } = b(() => s.data, (t) => {
123
- t !== void 0 && (D("plugin setData", e, t), I(e).run(() => V(e, n(t)).then(y)));
113
+ }), { ignoreUpdates: c } = b(() => s.data, (t) => {
114
+ t !== void 0 && (E("plugin setData", e, t), F(e).run(() => B(e, n(t)).then(y)));
124
115
  }, { deep: !0 });
125
116
  return {
126
117
  model: s,
127
- services: l(Q),
128
- ignoreUpdates: d
118
+ services: d(X),
119
+ ignoreUpdates: c
129
120
  };
130
- }, te = { getOrCreatePluginState(e) {
131
- let t = R.get(e);
121
+ }, Q = { getOrCreatePluginState(e) {
122
+ let t = L.get(e);
132
123
  if (t) return t;
133
- let n = ee(e);
134
- return R.set(e, n), n;
135
- } }, ne = {
136
- closedRef: j,
137
- snapshot: z,
138
- plugins: Object.fromEntries(T.blockModelInfo.pluginIds.map((e) => [e, { handle: e }])),
139
- services: l(Q),
140
- queryParams: c(() => a(z.value.navigationState.href)),
141
- href: c(() => z.value.navigationState.href),
142
- hasErrors: c(() => Object.values(z.value.outputs).some((e) => !e?.ok))
143
- }, $ = Object.assign(u(Object.assign(G, ne)), X);
144
- return E.debug && (globalThis.__block_app__ = $), {
124
+ let n = Z(e);
125
+ return L.set(e, n), n;
126
+ } }, ee = {
127
+ closedRef: A,
128
+ snapshot: R,
129
+ plugins: Object.fromEntries(w.blockModelInfo.pluginIds.map((e) => [e, { handle: e }])),
130
+ services: d(X),
131
+ queryParams: u(() => a(R.value.navigationState.href)),
132
+ href: u(() => R.value.navigationState.href),
133
+ hasErrors: u(() => Object.values(R.value.outputs).some((e) => !e?.ok))
134
+ }, $ = Object.assign(f(Object.assign(W, ee)), Y);
135
+ return T.debug && (globalThis.__block_app__ = $), {
145
136
  app: $,
146
- pluginAccess: te
137
+ pluginAccess: Q
147
138
  };
148
139
  }
149
140
  //#endregion
150
- export { w as createAppV3 };
141
+ export { C as createAppV3 };
151
142
 
152
143
  //# sourceMappingURL=createAppV3.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"createAppV3.js","names":[],"sources":["../../src/internal/createAppV3.ts"],"sourcesContent":["import { deepClone, delay, uniqueId } from \"@milaboratories/helpers\";\nimport type { Mutable } from \"@milaboratories/helpers\";\nimport type {\n NavigationState,\n BlockOutputsBase,\n BlockStateV3,\n PlatformaV3,\n ValueWithUTag,\n AuthorMarker,\n PlatformaExtended,\n InferPluginHandles,\n PluginHandle,\n InferFactoryData,\n InferFactoryOutputs,\n InferFactoryUiServices,\n PluginFactoryLike,\n} from \"@platforma-sdk/model\";\nimport {\n hasAbortError,\n unwrapResult,\n deriveDataFromStorage,\n getPluginData,\n isPluginOutputKey,\n pluginOutputPrefix,\n createNodeServiceProxy,\n buildServices,\n} from \"@platforma-sdk/model\";\nimport { type UiServices as AllUiServices } from \"@milaboratories/pl-model-common\";\nimport { createUiServiceRegistry } from \"./service_factories\";\nimport type { Ref } from \"vue\";\nimport { reactive, computed, ref, markRaw } from \"vue\";\nimport type { OutputValues, OutputErrors, AppSettings } from \"../types\";\nimport { parseQuery } from \"../urls\";\nimport { ensureOutputHasStableFlag, MultiError } from \"../utils\";\nimport { applyPatch } from \"fast-json-patch\";\nimport { UpdateSerializer } from \"./UpdateSerializer\";\nimport { watchIgnorable } from \"@vueuse/core\";\nimport type { PluginState, PluginAccess } from \"../usePlugin\";\n\nexport const patchPoolingDelay = 150;\n\n/** Internal per-plugin state with reconciliation support. */\ninterface InternalPluginState<\n Data = unknown,\n Outputs = unknown,\n Services = Record<string, unknown>,\n> extends PluginState<Data, Outputs, Services> {\n readonly ignoreUpdates: (fn: () => void) => void;\n}\n\nexport const createNextAuthorMarker = (marker: AuthorMarker | undefined): AuthorMarker => ({\n authorId: marker?.authorId ?? uniqueId(),\n localVersion: (marker?.localVersion ?? 0) + 1,\n});\n\nconst stringifyForDebug = (v: unknown) => {\n try {\n return JSON.stringify(v, null, 2);\n } catch (err) {\n return err instanceof Error ? err.message : String(err);\n }\n};\n\n/**\n * Creates an application instance with reactive state management, outputs, and methods for state updates and navigation.\n *\n * @template Args - The type of arguments used in the application.\n * @template Outputs - The type of block outputs extending `BlockOutputsBase`.\n * @template Data - The type of the block data.\n * @template Href - The type of navigation href, defaulting to a string starting with `/`.\n *\n * @param state - Initial state of the application, including args, outputs, UI state, and navigation state.\n * @param platforma - A platform interface for interacting with block states.\n * @param settings - Application settings, such as debug flags.\n *\n * @returns A reactive application object with methods, getters, and state.\n */\nexport function createAppV3<\n Data = unknown,\n Args = unknown,\n Outputs extends BlockOutputsBase = BlockOutputsBase,\n Href extends `/${string}` = `/${string}`,\n Plugins extends Record<string, unknown> = Record<string, unknown>,\n UiServices extends Partial<AllUiServices> = Partial<AllUiServices>,\n>(\n state: ValueWithUTag<BlockStateV3<Data, Outputs, Href>>,\n platforma: PlatformaExtended<PlatformaV3<Data, Args, Outputs, Href, Plugins, UiServices>>,\n settings: AppSettings,\n) {\n const debug = (msg: string, ...rest: unknown[]) => {\n if (settings.debug) {\n console.log(\n `%c>>> %c${msg}`,\n \"color: orange; font-weight: bold\",\n \"color: orange\",\n ...rest.map((r) => stringifyForDebug(r)),\n );\n }\n };\n\n const error = (msg: string, ...rest: unknown[]) => {\n console.error(\n `%c>>> %c${msg}`,\n \"color: red; font-weight: bold\",\n \"color: red\",\n ...rest.map((r) => stringifyForDebug(r)),\n );\n };\n\n const data = {\n isExternalSnapshot: false,\n author: {\n authorId: uniqueId(),\n localVersion: 0,\n },\n };\n\n const nextAuthorMarker = () => {\n data.author = createNextAuthorMarker(data.author);\n debug(\"nextAuthorMarker\", data.author);\n return data.author;\n };\n\n const closedRef = ref(false);\n\n const uTagRef = ref(state.uTag);\n\n const debounceSpan = settings.debounceSpan ?? 200;\n\n const setDataQueue = new UpdateSerializer({ debounceSpan });\n const pluginDataQueues = new Map<PluginHandle, UpdateSerializer>();\n const getPluginDataQueue = (handle: PluginHandle): UpdateSerializer => {\n let queue = pluginDataQueues.get(handle);\n if (!queue) {\n queue = new UpdateSerializer({ debounceSpan });\n pluginDataQueues.set(handle, queue);\n }\n return queue;\n };\n const setNavigationStateQueue = new UpdateSerializer({ debounceSpan });\n\n /** Lazily-created per-plugin reactive states. */\n const pluginStates = new Map<PluginHandle, InternalPluginState>();\n /**\n * Reactive snapshot of the application state, including args, outputs, UI state, and navigation state.\n */\n const snapshot = ref<{\n outputs: Partial<Outputs>;\n blockStorage: unknown;\n navigationState: NavigationState<Href>;\n }>(state.value) as Ref<{\n outputs: Partial<Outputs>;\n blockStorage: unknown;\n navigationState: NavigationState<Href>;\n }>;\n\n const updateData = async (value: Data) => {\n return platforma.mutateStorage({ operation: \"update-block-data\", value }, nextAuthorMarker());\n };\n\n const updatePluginData = async (handle: PluginHandle, value: unknown) => {\n return platforma.mutateStorage(\n { operation: \"update-plugin-data\", pluginId: handle, value },\n nextAuthorMarker(),\n );\n };\n\n const setNavigationState = async (state: NavigationState<Href>) => {\n return platforma.setNavigationState(state);\n };\n\n const outputs = computed<OutputValues<Outputs>>(() => {\n const entries = Object.entries(snapshot.value.outputs as Partial<Readonly<Outputs>>)\n .filter(([k]) => !isPluginOutputKey(k))\n .map(([k, outputWithStatus]) =>\n platforma.blockModelInfo.outputs[k]?.withStatus\n ? [k, ensureOutputHasStableFlag(outputWithStatus)]\n : [\n k,\n outputWithStatus.ok && outputWithStatus.value !== undefined\n ? outputWithStatus.value\n : undefined,\n ],\n );\n return Object.fromEntries(entries);\n });\n\n const outputErrors = computed<OutputErrors<Outputs>>(() => {\n const entries = Object.entries(snapshot.value.outputs as Partial<Readonly<Outputs>>)\n .filter(([k]) => !isPluginOutputKey(k))\n .map(([k, vOrErr]) => [\n k,\n vOrErr && vOrErr.ok === false ? new MultiError(vOrErr.errors) : undefined,\n ]);\n return Object.fromEntries(entries);\n });\n\n const appModel = reactive({\n apiVersion: 3,\n error: \"\",\n model: {\n data: deepClone(deriveDataFromStorage<Data>(snapshot.value.blockStorage)) as Data,\n outputs,\n outputErrors,\n },\n }) as {\n error: string;\n model: {\n data: Data;\n outputs: OutputValues<Outputs>;\n outputErrors: OutputErrors<Outputs>;\n };\n };\n\n const { ignoreUpdates } = watchIgnorable(\n () => appModel.model,\n (_newData) => {\n const newData = deepClone(_newData);\n debug(\"setDataQueue appModel.model, data\", newData.data);\n setDataQueue.run(() => updateData(newData.data).then(unwrapResult));\n },\n { deep: true },\n );\n\n const updateAppModel = (newData: { data: Data }) => {\n debug(\"updateAppModel\", newData);\n appModel.model.data = deepClone(newData.data) as Data;\n };\n\n (async () => {\n window.addEventListener(\"beforeunload\", () => {\n closedRef.value = true;\n Promise.allSettled([uiRegistry.dispose(), platforma.dispose().then(unwrapResult)]).catch(\n (err) => {\n error(\"error in dispose\", err);\n },\n );\n });\n\n while (!closedRef.value) {\n try {\n const patches = await platforma.getPatches(uTagRef.value).then(unwrapResult);\n\n debug(\"patches.length\", patches.value.length);\n debug(\"uTagRef.value\", uTagRef.value);\n debug(\"patches.uTag\", patches.uTag);\n debug(\"patches.author\", patches.author);\n debug(\"data.author\", data.author);\n\n uTagRef.value = patches.uTag;\n\n if (patches.value.length === 0) {\n await new Promise((resolve) => setTimeout(resolve, patchPoolingDelay));\n continue;\n }\n\n const isAuthorChanged = data.author?.authorId !== patches.author?.authorId;\n\n // Immutable behavior, apply external changes to the snapshot\n if (isAuthorChanged || data.isExternalSnapshot) {\n debug(\"got external changes, applying them to the snapshot\", patches.value);\n ignoreUpdates(() => {\n snapshot.value = applyPatch(snapshot.value, patches.value, false, false).newDocument;\n updateAppModel({ data: deriveDataFromStorage<Data>(snapshot.value.blockStorage) });\n // Reconcile plugin data from external source\n for (const [handle, pluginState] of pluginStates) {\n pluginState.ignoreUpdates(() => {\n pluginState.model.data = deepClone(\n getPluginData(snapshot.value.blockStorage, handle),\n );\n });\n }\n data.isExternalSnapshot = isAuthorChanged;\n });\n } else {\n // Mutable behavior\n debug(\"outputs changed\", patches.value);\n ignoreUpdates(() => {\n snapshot.value = applyPatch(snapshot.value, patches.value).newDocument;\n });\n }\n\n await new Promise((resolve) => setTimeout(resolve, patchPoolingDelay));\n } catch (err) {\n if (hasAbortError(err)) {\n debug(\"patches loop aborted\");\n closedRef.value = true;\n } else {\n error(\"error in patches loop\", err);\n await new Promise((resolve) => setTimeout(resolve, 1000));\n }\n }\n }\n })();\n\n const cloneData = () => deepClone(appModel.model.data) as Data;\n const cloneNavigationState = () =>\n deepClone(snapshot.value.navigationState) as Mutable<NavigationState<Href>>;\n\n const methods = {\n cloneData,\n cloneNavigationState,\n /**\n * Updates the UI state by applying a callback.\n *\n * @param cb - Callback to modify the current UI state.\n * @returns A promise resolving after the update is applied.\n * @todo Make it mutable since there is already an initial one\n */\n updateData(cb: (data: Data) => Data): Promise<boolean> {\n const newData = cb(cloneData());\n debug(\"updateData\", newData);\n appModel.model.data = newData;\n return setDataQueue.run(() => updateData(newData).then(unwrapResult));\n },\n /**\n * Navigates to a specific href by updating the navigation state.\n *\n * @param href - The target href to navigate to.\n * @returns A promise resolving after the navigation state is updated.\n */\n navigateTo(href: Href) {\n const newState = cloneNavigationState();\n newState.href = href;\n return setNavigationStateQueue.run(() => setNavigationState(newState).then(unwrapResult));\n },\n async allSettled() {\n await delay(0);\n const allQueues = [\n setDataQueue.allSettled(),\n ...Array.from(pluginDataQueues.values()).map((q) => q.allSettled()),\n ];\n await Promise.all(allQueues);\n },\n };\n\n const proxy = createNodeServiceProxy(platforma.serviceDispatch);\n const uiRegistry = createUiServiceRegistry({ proxy });\n const services = buildServices<UiServices>(platforma.serviceDispatch, uiRegistry);\n\n /** Creates a lazily-cached per-plugin reactive state. */\n const createPluginState = <F extends PluginFactoryLike>(\n handle: PluginHandle<F>,\n ): InternalPluginState<InferFactoryData<F>, InferFactoryOutputs<F>> => {\n const prefix = pluginOutputPrefix(handle);\n\n const pluginOutputs = computed(() => {\n const result: Record<string, unknown> = {};\n for (const [key, outputWithStatus] of Object.entries(\n snapshot.value.outputs as Partial<Readonly<Outputs>>,\n )) {\n if (!key.startsWith(prefix)) continue;\n const outputKey = key.slice(prefix.length);\n if (platforma.blockModelInfo.outputs[key]?.withStatus) {\n result[outputKey] = outputWithStatus\n ? ensureOutputHasStableFlag(outputWithStatus)\n : undefined;\n } else {\n result[outputKey] =\n outputWithStatus.ok && outputWithStatus.value !== undefined\n ? outputWithStatus.value\n : undefined;\n }\n }\n return result;\n });\n\n const pluginOutputErrors = computed(() => {\n const result: Record<string, Error | undefined> = {};\n for (const [key, vOrErr] of Object.entries(\n snapshot.value.outputs as Partial<Readonly<Outputs>>,\n )) {\n if (!key.startsWith(prefix)) continue;\n result[key.slice(prefix.length)] =\n vOrErr && vOrErr.ok === false ? new MultiError(vOrErr.errors) : undefined;\n }\n return result;\n });\n\n const pluginModel = reactive({\n data: deepClone(getPluginData(snapshot.value.blockStorage, handle)),\n outputs: pluginOutputs,\n outputErrors: pluginOutputErrors,\n }) as InternalPluginState<InferFactoryData<F>, InferFactoryOutputs<F>>[\"model\"];\n\n const { ignoreUpdates } = watchIgnorable(\n () => pluginModel.data,\n (newData) => {\n if (newData === undefined) return;\n debug(\"plugin setData\", handle, newData);\n getPluginDataQueue(handle).run(() =>\n updatePluginData(handle, deepClone(newData)).then(unwrapResult),\n );\n },\n { deep: true },\n );\n\n return {\n model: pluginModel,\n services: markRaw(services),\n ignoreUpdates,\n };\n };\n\n /** Plugin internals — provided via separate injection key, not exposed on useApp(). */\n const pluginAccess: PluginAccess = {\n getOrCreatePluginState<F extends PluginFactoryLike>(handle: PluginHandle<F>) {\n const existing = pluginStates.get(handle);\n if (existing) {\n return existing as unknown as PluginState<\n InferFactoryData<F>,\n InferFactoryOutputs<F>,\n InferFactoryUiServices<F>\n >;\n }\n const state = createPluginState(handle);\n pluginStates.set(handle, state);\n return state as unknown as PluginState<\n InferFactoryData<F>,\n InferFactoryOutputs<F>,\n InferFactoryUiServices<F>\n >;\n },\n };\n\n const plugins = Object.fromEntries(\n platforma.blockModelInfo.pluginIds.map((id) => [id, { handle: id }]),\n ) as InferPluginHandles<Plugins>;\n\n const getters = {\n closedRef,\n snapshot,\n plugins,\n services: markRaw(services),\n queryParams: computed(() => parseQuery<Href>(snapshot.value.navigationState.href as Href)),\n href: computed(() => snapshot.value.navigationState.href),\n hasErrors: computed(() =>\n Object.values(snapshot.value.outputs as Partial<Readonly<Outputs>>).some((v) => !v?.ok),\n ),\n };\n\n const app = Object.assign(reactive(Object.assign(appModel, getters)), methods);\n\n if (settings.debug) {\n // @ts-expect-error (to inspect in console in debug mode)\n globalThis.__block_app__ = app;\n }\n\n return { app, pluginAccess };\n}\n\nexport type BaseAppV3<\n Data = unknown,\n Args = unknown,\n Outputs extends BlockOutputsBase = BlockOutputsBase,\n Href extends `/${string}` = `/${string}`,\n Plugins extends Record<string, unknown> = Record<string, unknown>,\n UiServices extends Partial<AllUiServices> = Partial<AllUiServices>,\n> = ReturnType<typeof createAppV3<Data, Args, Outputs, Href, Plugins, UiServices>>[\"app\"];\n"],"mappings":"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"}
1
+ {"version":3,"file":"createAppV3.js","names":[],"sources":["../../src/internal/createAppV3.ts"],"sourcesContent":["import { deepClone, delay, uniqueId } from \"@milaboratories/helpers\";\nimport type { Mutable } from \"@milaboratories/helpers\";\nimport type {\n NavigationState,\n BlockOutputsBase,\n BlockStateV3,\n PlatformaV3,\n ValueWithUTag,\n AuthorMarker,\n PlatformaExtended,\n InferPluginHandles,\n PluginHandle,\n InferFactoryData,\n InferFactoryOutputs,\n InferFactoryUiServices,\n PluginFactoryLike,\n} from \"@platforma-sdk/model\";\nimport {\n hasAbortError,\n unwrapResult,\n deriveDataFromStorage,\n getPluginData,\n isPluginOutputKey,\n pluginOutputPrefix,\n} from \"@platforma-sdk/model\";\nimport { type UiServices as AllUiServices } from \"@milaboratories/pl-model-common\";\nimport type { Ref } from \"vue\";\nimport { reactive, computed, ref, markRaw } from \"vue\";\nimport type { OutputValues, OutputErrors, AppSettings } from \"../types\";\nimport { parseQuery } from \"../urls\";\nimport { ensureOutputHasStableFlag, MultiError } from \"../utils\";\nimport { applyPatch } from \"fast-json-patch\";\nimport { UpdateSerializer } from \"./UpdateSerializer\";\nimport { watchIgnorable } from \"@vueuse/core\";\nimport type { PluginState, PluginAccess } from \"../usePlugin\";\nimport { logDebug, logError } from \"./utils\";\nimport { getServices } from \"./getServices\";\n\nexport const patchPoolingDelay = 150;\n\n/** Internal per-plugin state with reconciliation support. */\ninterface InternalPluginState<\n Data = unknown,\n Outputs = unknown,\n Services = Record<string, unknown>,\n> extends PluginState<Data, Outputs, Services> {\n readonly ignoreUpdates: (fn: () => void) => void;\n}\n\nexport const createNextAuthorMarker = (marker: AuthorMarker | undefined): AuthorMarker => ({\n authorId: marker?.authorId ?? uniqueId(),\n localVersion: (marker?.localVersion ?? 0) + 1,\n});\n\n/**\n * Creates an application instance with reactive state management, outputs, and methods for state updates and navigation.\n *\n * @template Args - The type of arguments used in the application.\n * @template Outputs - The type of block outputs extending `BlockOutputsBase`.\n * @template Data - The type of the block data.\n * @template Href - The type of navigation href, defaulting to a string starting with `/`.\n *\n * @param state - Initial state of the application, including args, outputs, UI state, and navigation state.\n * @param platforma - A platform interface for interacting with block states.\n * @param settings - Application settings, such as debug flags.\n *\n * @returns A reactive application object with methods, getters, and state.\n */\nexport function createAppV3<\n Data = unknown,\n Args = unknown,\n Outputs extends BlockOutputsBase = BlockOutputsBase,\n Href extends `/${string}` = `/${string}`,\n Plugins extends Record<string, unknown> = Record<string, unknown>,\n UiServices extends Partial<AllUiServices> = Partial<AllUiServices>,\n>(\n state: ValueWithUTag<BlockStateV3<Data, Outputs, Href>>,\n platforma: PlatformaExtended<PlatformaV3<Data, Args, Outputs, Href, Plugins, UiServices>>,\n settings: AppSettings,\n) {\n const debug = settings.debug ? logDebug : () => {};\n const error = logError;\n\n const data = {\n isExternalSnapshot: false,\n author: {\n authorId: uniqueId(),\n localVersion: 0,\n },\n };\n\n const nextAuthorMarker = () => {\n data.author = createNextAuthorMarker(data.author);\n debug(\"nextAuthorMarker\", data.author);\n return data.author;\n };\n\n const closedRef = ref(false);\n\n const uTagRef = ref(state.uTag);\n\n const debounceSpan = settings.debounceSpan ?? 200;\n\n const setDataQueue = new UpdateSerializer({ debounceSpan });\n const pluginDataQueues = new Map<PluginHandle, UpdateSerializer>();\n const getPluginDataQueue = (handle: PluginHandle): UpdateSerializer => {\n let queue = pluginDataQueues.get(handle);\n if (!queue) {\n queue = new UpdateSerializer({ debounceSpan });\n pluginDataQueues.set(handle, queue);\n }\n return queue;\n };\n const setNavigationStateQueue = new UpdateSerializer({ debounceSpan });\n\n /** Lazily-created per-plugin reactive states. */\n const pluginStates = new Map<PluginHandle, InternalPluginState>();\n /**\n * Reactive snapshot of the application state, including args, outputs, UI state, and navigation state.\n */\n const snapshot = ref<{\n outputs: Partial<Outputs>;\n blockStorage: unknown;\n navigationState: NavigationState<Href>;\n }>(state.value) as Ref<{\n outputs: Partial<Outputs>;\n blockStorage: unknown;\n navigationState: NavigationState<Href>;\n }>;\n\n const updateData = async (value: Data) => {\n return platforma.mutateStorage({ operation: \"update-block-data\", value }, nextAuthorMarker());\n };\n\n const updatePluginData = async (handle: PluginHandle, value: unknown) => {\n return platforma.mutateStorage(\n { operation: \"update-plugin-data\", pluginId: handle, value },\n nextAuthorMarker(),\n );\n };\n\n const setNavigationState = async (state: NavigationState<Href>) => {\n return platforma.setNavigationState(state);\n };\n\n const outputs = computed<OutputValues<Outputs>>(() => {\n const entries = Object.entries(snapshot.value.outputs as Partial<Readonly<Outputs>>)\n .filter(([k]) => !isPluginOutputKey(k))\n .map(([k, outputWithStatus]) =>\n platforma.blockModelInfo.outputs[k]?.withStatus\n ? [k, ensureOutputHasStableFlag(outputWithStatus)]\n : [\n k,\n outputWithStatus.ok && outputWithStatus.value !== undefined\n ? outputWithStatus.value\n : undefined,\n ],\n );\n return Object.fromEntries(entries);\n });\n\n const outputErrors = computed<OutputErrors<Outputs>>(() => {\n const entries = Object.entries(snapshot.value.outputs as Partial<Readonly<Outputs>>)\n .filter(([k]) => !isPluginOutputKey(k))\n .map(([k, vOrErr]) => [\n k,\n vOrErr && vOrErr.ok === false ? new MultiError(vOrErr.errors) : undefined,\n ]);\n return Object.fromEntries(entries);\n });\n\n const appModel = reactive({\n apiVersion: 3,\n error: \"\",\n model: {\n data: deepClone(deriveDataFromStorage<Data>(snapshot.value.blockStorage)) as Data,\n outputs,\n outputErrors,\n },\n }) as {\n error: string;\n model: {\n data: Data;\n outputs: OutputValues<Outputs>;\n outputErrors: OutputErrors<Outputs>;\n };\n };\n\n const { ignoreUpdates } = watchIgnorable(\n () => appModel.model,\n (_newData) => {\n const newData = deepClone(_newData);\n debug(\"setDataQueue appModel.model, data\", newData.data);\n setDataQueue.run(() => updateData(newData.data).then(unwrapResult));\n },\n { deep: true },\n );\n\n const updateAppModel = (newData: { data: Data }) => {\n debug(\"updateAppModel\", newData);\n appModel.model.data = deepClone(newData.data) as Data;\n };\n\n (async () => {\n window.addEventListener(\"beforeunload\", () => {\n closedRef.value = true;\n platforma\n .dispose()\n .then(unwrapResult)\n .catch((err) => {\n error(\"error in dispose\", err);\n });\n });\n\n while (!closedRef.value) {\n try {\n const patches = await platforma.getPatches(uTagRef.value).then(unwrapResult);\n\n debug(\"patches.length\", patches.value.length);\n debug(\"uTagRef.value\", uTagRef.value);\n debug(\"patches.uTag\", patches.uTag);\n debug(\"patches.author\", patches.author);\n debug(\"data.author\", data.author);\n\n uTagRef.value = patches.uTag;\n\n if (patches.value.length === 0) {\n await new Promise((resolve) => setTimeout(resolve, patchPoolingDelay));\n continue;\n }\n\n const isAuthorChanged = data.author?.authorId !== patches.author?.authorId;\n\n // Immutable behavior, apply external changes to the snapshot\n if (isAuthorChanged || data.isExternalSnapshot) {\n debug(\"got external changes, applying them to the snapshot\", patches.value);\n ignoreUpdates(() => {\n snapshot.value = applyPatch(snapshot.value, patches.value, false, false).newDocument;\n updateAppModel({ data: deriveDataFromStorage<Data>(snapshot.value.blockStorage) });\n // Reconcile plugin data from external source\n for (const [handle, pluginState] of pluginStates) {\n pluginState.ignoreUpdates(() => {\n pluginState.model.data = deepClone(\n getPluginData(snapshot.value.blockStorage, handle),\n );\n });\n }\n data.isExternalSnapshot = isAuthorChanged;\n });\n } else {\n // Mutable behavior\n debug(\"outputs changed\", patches.value);\n ignoreUpdates(() => {\n snapshot.value = applyPatch(snapshot.value, patches.value).newDocument;\n });\n }\n\n await new Promise((resolve) => setTimeout(resolve, patchPoolingDelay));\n } catch (err) {\n if (hasAbortError(err)) {\n debug(\"patches loop aborted\");\n closedRef.value = true;\n } else {\n error(\"error in patches loop\", err);\n await new Promise((resolve) => setTimeout(resolve, 1000));\n }\n }\n }\n })();\n\n const cloneData = () => deepClone(appModel.model.data) as Data;\n const cloneNavigationState = () =>\n deepClone(snapshot.value.navigationState) as Mutable<NavigationState<Href>>;\n\n const methods = {\n cloneData,\n cloneNavigationState,\n /**\n * Updates the UI state by applying a callback.\n *\n * @param cb - Callback to modify the current UI state.\n * @returns A promise resolving after the update is applied.\n * @todo Make it mutable since there is already an initial one\n */\n updateData(cb: (data: Data) => Data): Promise<boolean> {\n const newData = cb(cloneData());\n debug(\"updateData\", newData);\n appModel.model.data = newData;\n return setDataQueue.run(() => updateData(newData).then(unwrapResult));\n },\n /**\n * Navigates to a specific href by updating the navigation state.\n *\n * @param href - The target href to navigate to.\n * @returns A promise resolving after the navigation state is updated.\n */\n navigateTo(href: Href) {\n const newState = cloneNavigationState();\n newState.href = href;\n return setNavigationStateQueue.run(() => setNavigationState(newState).then(unwrapResult));\n },\n async allSettled() {\n await delay(0);\n const allQueues = [\n setDataQueue.allSettled(),\n ...Array.from(pluginDataQueues.values()).map((q) => q.allSettled()),\n ];\n await Promise.all(allQueues);\n },\n };\n\n const services = getServices<UiServices>({ platforma });\n\n /** Creates a lazily-cached per-plugin reactive state. */\n const createPluginState = <F extends PluginFactoryLike>(\n handle: PluginHandle<F>,\n ): InternalPluginState<InferFactoryData<F>, InferFactoryOutputs<F>> => {\n const prefix = pluginOutputPrefix(handle);\n\n const pluginOutputs = computed(() => {\n const result: Record<string, unknown> = {};\n for (const [key, outputWithStatus] of Object.entries(\n snapshot.value.outputs as Partial<Readonly<Outputs>>,\n )) {\n if (!key.startsWith(prefix)) continue;\n const outputKey = key.slice(prefix.length);\n if (platforma.blockModelInfo.outputs[key]?.withStatus) {\n result[outputKey] = outputWithStatus\n ? ensureOutputHasStableFlag(outputWithStatus)\n : undefined;\n } else {\n result[outputKey] =\n outputWithStatus.ok && outputWithStatus.value !== undefined\n ? outputWithStatus.value\n : undefined;\n }\n }\n return result;\n });\n\n const pluginOutputErrors = computed(() => {\n const result: Record<string, Error | undefined> = {};\n for (const [key, vOrErr] of Object.entries(\n snapshot.value.outputs as Partial<Readonly<Outputs>>,\n )) {\n if (!key.startsWith(prefix)) continue;\n result[key.slice(prefix.length)] =\n vOrErr && vOrErr.ok === false ? new MultiError(vOrErr.errors) : undefined;\n }\n return result;\n });\n\n const pluginModel = reactive({\n data: deepClone(getPluginData(snapshot.value.blockStorage, handle)),\n outputs: pluginOutputs,\n outputErrors: pluginOutputErrors,\n }) as InternalPluginState<InferFactoryData<F>, InferFactoryOutputs<F>>[\"model\"];\n\n const { ignoreUpdates } = watchIgnorable(\n () => pluginModel.data,\n (newData) => {\n if (newData === undefined) return;\n debug(\"plugin setData\", handle, newData);\n getPluginDataQueue(handle).run(() =>\n updatePluginData(handle, deepClone(newData)).then(unwrapResult),\n );\n },\n { deep: true },\n );\n\n return {\n model: pluginModel,\n services: markRaw(services),\n ignoreUpdates,\n };\n };\n\n /** Plugin internals — provided via separate injection key, not exposed on useApp(). */\n const pluginAccess: PluginAccess = {\n getOrCreatePluginState<F extends PluginFactoryLike>(handle: PluginHandle<F>) {\n const existing = pluginStates.get(handle);\n if (existing) {\n return existing as unknown as PluginState<\n InferFactoryData<F>,\n InferFactoryOutputs<F>,\n InferFactoryUiServices<F>\n >;\n }\n const state = createPluginState(handle);\n pluginStates.set(handle, state);\n return state as unknown as PluginState<\n InferFactoryData<F>,\n InferFactoryOutputs<F>,\n InferFactoryUiServices<F>\n >;\n },\n };\n\n const plugins = Object.fromEntries(\n platforma.blockModelInfo.pluginIds.map((id) => [id, { handle: id }]),\n ) as InferPluginHandles<Plugins>;\n\n const getters = {\n closedRef,\n snapshot,\n plugins,\n services: markRaw(services),\n queryParams: computed(() => parseQuery<Href>(snapshot.value.navigationState.href as Href)),\n href: computed(() => snapshot.value.navigationState.href),\n hasErrors: computed(() =>\n Object.values(snapshot.value.outputs as Partial<Readonly<Outputs>>).some((v) => !v?.ok),\n ),\n };\n\n const app = Object.assign(reactive(Object.assign(appModel, getters)), methods);\n\n if (settings.debug) {\n // @ts-expect-error (to inspect in console in debug mode)\n globalThis.__block_app__ = app;\n }\n\n return { app, pluginAccess };\n}\n\nexport type BaseAppV3<\n Data = unknown,\n Args = unknown,\n Outputs extends BlockOutputsBase = BlockOutputsBase,\n Href extends `/${string}` = `/${string}`,\n Plugins extends Record<string, unknown> = Record<string, unknown>,\n UiServices extends Partial<AllUiServices> = Partial<AllUiServices>,\n> = ReturnType<typeof createAppV3<Data, Args, Outputs, Href, Plugins, UiServices>>[\"app\"];\n"],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { BlockDefaultUiServices, PlatformaV3, UiServices } from '@platforma-sdk/model';
2
+ export declare function getServices<Services extends Partial<UiServices> = BlockDefaultUiServices>(deps?: {
3
+ platforma?: PlatformaV3<any, any, any, any, any, Services>;
4
+ }): Services;
5
+ //# sourceMappingURL=getServices.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getServices.d.ts","sourceRoot":"","sources":["../../src/internal/getServices.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EAItB,WAAW,EACX,UAAU,EACX,MAAM,sBAAsB,CAAC;AAO9B,wBAAgB,WAAW,CAAC,QAAQ,SAAS,OAAO,CAAC,UAAU,CAAC,GAAG,sBAAsB,EAAE,IAAI,CAAC,EAAE;IAChG,SAAS,CAAC,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;CAC5D,GAAG,QAAQ,CAmBX"}
@@ -0,0 +1,19 @@
1
+ import { logError as e } from "./utils.js";
2
+ import { createUiServiceRegistry as t } from "./service_factories.js";
3
+ import { buildServices as n, createServiceProxy as r, getRawPlatformaInstance as i } from "@platforma-sdk/model";
4
+ import { isNil as a } from "es-toolkit";
5
+ //#region src/internal/getServices.ts
6
+ var o = null;
7
+ function s(s) {
8
+ if (!a(o)) return o;
9
+ let c = s?.platforma ?? i(), l = t({ proxy: r(c.serviceDispatch) }), u = n(c.serviceDispatch, l);
10
+ return window.addEventListener("beforeunload", () => {
11
+ l.dispose().catch((t) => {
12
+ e("uiRegistry error in dispose", t);
13
+ });
14
+ }), o = u;
15
+ }
16
+ //#endregion
17
+ export { s as getServices };
18
+
19
+ //# sourceMappingURL=getServices.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getServices.js","names":[],"sources":["../../src/internal/getServices.ts"],"sourcesContent":["import {\n BlockDefaultUiServices,\n buildServices,\n createServiceProxy,\n getRawPlatformaInstance,\n PlatformaV3,\n UiServices,\n} from \"@platforma-sdk/model\";\nimport { createUiServiceRegistry } from \"./service_factories\";\nimport { isNil } from \"es-toolkit\";\nimport { logError } from \"./utils\";\n\nlet cachedServices: null | Partial<UiServices> = null;\n\nexport function getServices<Services extends Partial<UiServices> = BlockDefaultUiServices>(deps?: {\n platforma?: PlatformaV3<any, any, any, any, any, Services>;\n}): Services {\n if (!isNil(cachedServices)) {\n return cachedServices as Services;\n }\n\n const platforma =\n deps?.platforma ??\n (getRawPlatformaInstance() as PlatformaV3<any, any, any, any, any, Services>);\n const proxy = createServiceProxy(platforma.serviceDispatch);\n const uiRegistry = createUiServiceRegistry({ proxy });\n const services = buildServices<Services>(platforma.serviceDispatch, uiRegistry);\n\n window.addEventListener(\"beforeunload\", () => {\n uiRegistry.dispose().catch((err) => {\n logError(\"uiRegistry error in dispose\", err);\n });\n });\n\n return (cachedServices = services) as Services;\n}\n"],"mappings":";;;;;AAYA,IAAI,IAA6C;AAEjD,SAAgB,EAA2E,GAE9E;AACX,KAAI,CAAC,EAAM,EAAe,CACxB,QAAO;CAGT,IAAM,IACJ,GAAM,aACL,GAAyB,EAEtB,IAAa,EAAwB,EAAE,OAD/B,EAAmB,EAAU,gBAAgB,EACP,CAAC,EAC/C,IAAW,EAAwB,EAAU,iBAAiB,EAAW;AAQ/E,QANA,OAAO,iBAAiB,sBAAsB;AAC5C,IAAW,SAAS,CAAC,OAAO,MAAQ;AAClC,KAAS,+BAA+B,EAAI;IAC5C;GACF,EAEM,IAAiB"}
@@ -1,7 +1,7 @@
1
1
  import { UiServiceRegistry } from '@milaboratories/pl-model-common';
2
- import { NodeServiceProxy } from '@platforma-sdk/model';
2
+ import { ServiceProxy } from '@platforma-sdk/model';
3
3
  export type UiServiceOptions = {
4
- proxy: NodeServiceProxy;
4
+ proxy: ServiceProxy;
5
5
  };
6
6
  export declare function createUiServiceRegistry(options: UiServiceOptions): UiServiceRegistry<{
7
7
  PFrameSpec: import('@milaboratories/pl-model-common').Branded<"pframeSpec", import('@milaboratories/pl-model-common').ServiceTypesLike<import('@milaboratories/pl-model-common').PFrameSpecDriver, import('@milaboratories/pl-model-common').PFrameSpecDriver, "wasm">>;
@@ -1 +1 @@
1
- {"version":3,"file":"service_factories.d.ts","sourceRoot":"","sources":["../../src/internal/service_factories.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAY,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAE9E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,gBAAgB,CAAC;CACzB,CAAC;AAEF,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,gBAAgB;;;GAKhE"}
1
+ {"version":3,"file":"service_factories.d.ts","sourceRoot":"","sources":["../../src/internal/service_factories.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAY,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAE9E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,YAAY,CAAC;CACrB,CAAC;AAEF,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,gBAAgB;;;GAKhE"}
@@ -1 +1 @@
1
- {"version":3,"file":"service_factories.js","names":[],"sources":["../../src/internal/service_factories.ts"],"sourcesContent":["/**\n * UI service factories — add a factory for each new service here.\n *\n * Each entry maps a Services key to a factory function that creates the\n * UI-side driver instance:\n * - WASM services: instantiated directly (e.g. SpecDriver)\n * - Node services: proxied via IPC using NodeServiceProxy\n */\n\nimport { Services, UiServiceRegistry } from \"@milaboratories/pl-model-common\";\nimport { SpecDriver } from \"@milaboratories/pf-spec-driver\";\nimport type { NodeServiceProxy } from \"@platforma-sdk/model\";\n\nexport type UiServiceOptions = {\n proxy: NodeServiceProxy;\n};\n\nexport function createUiServiceRegistry(options: UiServiceOptions) {\n return new UiServiceRegistry(Services, {\n PFrameSpec: () => new SpecDriver(),\n PFrame: () => options.proxy(Services.PFrame),\n });\n}\n"],"mappings":";;;AAiBA,SAAgB,EAAwB,GAA2B;AACjE,QAAO,IAAI,EAAkB,GAAU;EACrC,kBAAkB,IAAI,GAAY;EAClC,cAAc,EAAQ,MAAM,EAAS,OAAO;EAC7C,CAAC"}
1
+ {"version":3,"file":"service_factories.js","names":[],"sources":["../../src/internal/service_factories.ts"],"sourcesContent":["/**\n * UI service factories — add a factory for each new service here.\n *\n * Each entry maps a Services key to a factory function that creates the\n * UI-side driver instance:\n * - WASM services: instantiated directly (e.g. SpecDriver)\n * - Node services: proxied via IPC using NodeServiceProxy\n */\n\nimport { Services, UiServiceRegistry } from \"@milaboratories/pl-model-common\";\nimport { SpecDriver } from \"@milaboratories/pf-spec-driver\";\nimport type { ServiceProxy } from \"@platforma-sdk/model\";\n\nexport type UiServiceOptions = {\n proxy: ServiceProxy;\n};\n\nexport function createUiServiceRegistry(options: UiServiceOptions) {\n return new UiServiceRegistry(Services, {\n PFrameSpec: () => new SpecDriver(),\n PFrame: () => options.proxy(Services.PFrame),\n });\n}\n"],"mappings":";;;AAiBA,SAAgB,EAAwB,GAA2B;AACjE,QAAO,IAAI,EAAkB,GAAU;EACrC,kBAAkB,IAAI,GAAY;EAClC,cAAc,EAAQ,MAAM,EAAS,OAAO;EAC7C,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare const logDebug: (msg: string, ...rest: unknown[]) => void;
2
+ export declare const logError: (msg: string, ...rest: unknown[]) => void;
3
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/internal/utils.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,QAAQ,GAAI,KAAK,MAAM,EAAE,GAAG,MAAM,OAAO,EAAE,SAOvD,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,KAAK,MAAM,EAAE,GAAG,MAAM,OAAO,EAAE,SAOvD,CAAC"}
@@ -0,0 +1,16 @@
1
+ //#region src/internal/utils.ts
2
+ var e = (e, ...t) => {
3
+ console.log(`%c>>> %c${e}`, "color: orange; font-weight: bold", "color: orange", ...t.map((e) => n(e)));
4
+ }, t = (e, ...t) => {
5
+ console.error(`%c>>> %c${e}`, "color: red; font-weight: bold", "color: red", ...t.map((e) => n(e)));
6
+ }, n = (e) => {
7
+ try {
8
+ return JSON.stringify(e, null, 2);
9
+ } catch (e) {
10
+ return e instanceof Error ? e.message : String(e);
11
+ }
12
+ };
13
+ //#endregion
14
+ export { e as logDebug, t as logError };
15
+
16
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","names":[],"sources":["../../src/internal/utils.ts"],"sourcesContent":["export const logDebug = (msg: string, ...rest: unknown[]) => {\n console.log(\n `%c>>> %c${msg}`,\n \"color: orange; font-weight: bold\",\n \"color: orange\",\n ...rest.map((r) => stringifyForDebug(r)),\n );\n};\n\nexport const logError = (msg: string, ...rest: unknown[]) => {\n console.error(\n `%c>>> %c${msg}`,\n \"color: red; font-weight: bold\",\n \"color: red\",\n ...rest.map((r) => stringifyForDebug(r)),\n );\n};\n\nconst stringifyForDebug = (v: unknown) => {\n try {\n return JSON.stringify(v, null, 2);\n } catch (err) {\n return err instanceof Error ? err.message : String(err);\n }\n};\n"],"mappings":";AAAA,IAAa,KAAY,GAAa,GAAG,MAAoB;AAC3D,SAAQ,IACN,WAAW,KACX,oCACA,iBACA,GAAG,EAAK,KAAK,MAAM,EAAkB,EAAE,CAAC,CACzC;GAGU,KAAY,GAAa,GAAG,MAAoB;AAC3D,SAAQ,MACN,WAAW,KACX,iCACA,cACA,GAAG,EAAK,KAAK,MAAM,EAAkB,EAAE,CAAC,CACzC;GAGG,KAAqB,MAAe;AACxC,KAAI;AACF,SAAO,KAAK,UAAU,GAAG,MAAM,EAAE;UAC1B,GAAK;AACZ,SAAO,aAAe,QAAQ,EAAI,UAAU,OAAO,EAAI"}
package/dist/lib.d.ts CHANGED
@@ -18,6 +18,7 @@ export * from './components/PlTableFilters';
18
18
  export * from './components/PlAnnotations';
19
19
  export * from './components/PlBtnExportArchive';
20
20
  export * from './components/PlAdvancedFilter';
21
+ export * from './components/PlDatasetSelector';
21
22
  export * from './defineApp';
22
23
  export { usePlugin } from './usePlugin';
23
24
  export type { PluginState } from './usePlugin';
package/dist/lib.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,gDAAgD,CAAC;AAC5F,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,mDAAmD,CAAC;AAClG,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,kDAAkD,CAAC;AAEhG,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,cAAc,aAAa,CAAC;AAE5B,cAAc,+BAA+B,CAAC;AAE9C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,qCAAqC,CAAC;AACpD,cAAc,sCAAsC,CAAC;AAErD,cAAc,4BAA4B,CAAC;AAE3C,cAAc,8BAA8B,CAAC;AAE7C,cAAc,oCAAoC,CAAC;AAEnD,cAAc,oCAAoC,CAAC;AAEnD,cAAc,6BAA6B,CAAC;AAE5C,cAAc,4BAA4B,CAAC;AAE3C,cAAc,iCAAiC,CAAC;AAEhD,cAAc,+BAA+B,CAAC;AAE9C,cAAc,aAAa,CAAC;AAE5B,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,YAAY,EACV,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,sBAAsB,CAAC;AAE9B,cAAc,eAAe,CAAC;AAE9B,cAAc,SAAS,CAAC;AAExB,cAAc,eAAe,CAAC;AAE9B,cAAc,sBAAsB,CAAC;AAErC,cAAc,SAAS,CAAC;AAExB,cAAc,cAAc,CAAC;AAE7B,cAAc,kBAAkB,CAAC;AAEjC,cAAc,2BAA2B,CAAC;AAE1C,cAAc,uBAAuB,CAAC;AAEtC,mBAAmB,uBAAuB,CAAC"}
1
+ {"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,gDAAgD,CAAC;AAC5F,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,mDAAmD,CAAC;AAClG,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,kDAAkD,CAAC;AAEhG,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,cAAc,aAAa,CAAC;AAE5B,cAAc,+BAA+B,CAAC;AAE9C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,qCAAqC,CAAC;AACpD,cAAc,sCAAsC,CAAC;AAErD,cAAc,4BAA4B,CAAC;AAE3C,cAAc,8BAA8B,CAAC;AAE7C,cAAc,oCAAoC,CAAC;AAEnD,cAAc,oCAAoC,CAAC;AAEnD,cAAc,6BAA6B,CAAC;AAE5C,cAAc,4BAA4B,CAAC;AAE3C,cAAc,iCAAiC,CAAC;AAEhD,cAAc,+BAA+B,CAAC;AAE9C,cAAc,gCAAgC,CAAC;AAE/C,cAAc,aAAa,CAAC;AAE5B,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,YAAY,EACV,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,sBAAsB,CAAC;AAE9B,cAAc,eAAe,CAAC;AAE9B,cAAc,SAAS,CAAC;AAExB,cAAc,eAAe,CAAC;AAE9B,cAAc,sBAAsB,CAAC;AAErC,cAAc,SAAS,CAAC;AAExB,cAAc,cAAc,CAAC;AAE7B,cAAc,kBAAkB,CAAC;AAEjC,cAAc,2BAA2B,CAAC;AAE1C,cAAc,uBAAuB,CAAC;AAEtC,mBAAmB,uBAAuB,CAAC"}
package/dist/lib.js CHANGED
@@ -44,6 +44,8 @@ import "./components/PlAnnotations/components/PlAnnotationsModal.js";
44
44
  import "./components/PlAnnotations/index.js";
45
45
  import "./components/PlBtnExportArchive/PlBtnExportArchive.js";
46
46
  import "./components/PlBtnExportArchive/index.js";
47
+ import "./components/PlDatasetSelector/PlDatasetSelector.js";
48
+ import "./components/PlDatasetSelector/index.js";
47
49
  import "./usePlugin.js";
48
50
  import "./defineStore.js";
49
51
  import "./composition/AgGrid/index.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platforma-sdk/ui-vue",
3
- "version": "1.66.1",
3
+ "version": "1.67.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "exports": {
@@ -26,10 +26,10 @@
26
26
  "lru-cache": "^11.2.2",
27
27
  "vue": "^3.5.24",
28
28
  "zod": "~3.25.76",
29
- "@milaboratories/pf-spec-driver": "1.3.1",
30
- "@milaboratories/uikit": "2.12.7",
31
- "@platforma-sdk/model": "1.65.10",
32
- "@milaboratories/pl-model-common": "1.34.0"
29
+ "@milaboratories/pf-spec-driver": "1.3.3",
30
+ "@milaboratories/pl-model-common": "1.35.0",
31
+ "@platforma-sdk/model": "1.67.0",
32
+ "@milaboratories/uikit": "2.12.9"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@faker-js/faker": "^9.2.0",
@@ -37,14 +37,16 @@
37
37
  "@vitest/coverage-istanbul": "^4.1.3",
38
38
  "@vue/test-utils": "^2.4.6",
39
39
  "fast-json-patch": "^3.1.1",
40
+ "jsdom": "^25.0.1",
41
+ "resize-observer-polyfill": "^1.5.1",
40
42
  "rollup-plugin-sourcemaps2": "^0.5.2",
41
43
  "sass": "~1.83.4",
42
44
  "semver": "^7.7.2",
43
45
  "typescript": "~5.9.3",
44
46
  "vite": "^8.0.6",
45
47
  "vitest": "^4.1.3",
46
- "@milaboratories/build-configs": "2.0.0",
47
48
  "@milaboratories/helpers": "1.14.1",
49
+ "@milaboratories/build-configs": "2.0.0",
48
50
  "@milaboratories/ts-configs": "1.2.3",
49
51
  "@milaboratories/ts-builder": "1.3.2"
50
52
  },
@@ -0,0 +1,10 @@
1
+ import ResizeObserver from "resize-observer-polyfill";
2
+ globalThis.ResizeObserver = ResizeObserver;
3
+
4
+ // CSS.paintWorklet is not available in jsdom — uikit's PlPlaceholder
5
+ // accesses it at module load time.
6
+ if (typeof globalThis.CSS === "undefined") {
7
+ (globalThis as Record<string, unknown>).CSS = { paintWorklet: { addModule: () => {} } };
8
+ } else if (!("paintWorklet" in globalThis.CSS)) {
9
+ (globalThis.CSS as Record<string, unknown>).paintWorklet = { addModule: () => {} };
10
+ }
@@ -64,14 +64,20 @@ function showMenu() {
64
64
 
65
65
  <template>
66
66
  <div class="pl-ag-column-header d-flex align-center gap-6" @click="onSortRequested">
67
- <PlTooltip>
68
- <template v-if="params.tooltip" #tooltip>{{ params.tooltip }}</template>
69
- <div class="pl-ag-column-header__title d-flex align-center gap-6 flex-grow-1">
70
- <PlMaskIcon16 :name="icon" class="pl-ag-column-header__type-icon" />
67
+ <div class="pl-ag-column-header__title d-flex align-center gap-6 flex-grow-1">
68
+ <PlMaskIcon16 :name="icon" class="pl-ag-column-header__type-icon" />
69
+ <PlTooltip>
70
+ <template v-if="params.tooltip" #tooltip>{{ params.tooltip }}</template>
71
71
  <span>{{ params.displayName }}</span>
72
- <PlMaskIcon16 v-if="sortIcon" :name="sortIcon" />
73
- </div>
74
- </PlTooltip>
72
+ </PlTooltip>
73
+ <PlTooltip v-if="params.info" max-width="500px" position="bottom" :close-delay="10000000000">
74
+ <template #tooltip>
75
+ <span style="white-space: pre-wrap">{{ params.info }}</span>
76
+ </template>
77
+ <PlMaskIcon16 name="info" />
78
+ </PlTooltip>
79
+ <PlMaskIcon16 v-if="sortIcon" :name="sortIcon" />
80
+ </div>
75
81
  <div
76
82
  v-if="params.enableMenu"
77
83
  ref="menuActivatorBtn"
@@ -3,4 +3,5 @@ export type PlAgHeaderComponentType = "Text" | "Number" | "File" | "Date" | "Dur
3
3
  export type PlAgHeaderComponentParams = {
4
4
  type?: PlAgHeaderComponentType;
5
5
  tooltip?: string;
6
+ info?: string;
6
7
  };