@platforma-sdk/ui-vue 1.10.18 → 1.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platforma-sdk/ui-vue",
3
- "version": "1.10.18",
3
+ "version": "1.11.1",
4
4
  "type": "module",
5
5
  "main": "dist/lib.umd.cjs",
6
6
  "module": "dist/lib.js",
@@ -37,8 +37,8 @@
37
37
  "@ag-grid-community/theming": "^32.3.3",
38
38
  "@ag-grid-enterprise/side-bar": "^32.3.3",
39
39
  "@ag-grid-enterprise/column-tool-panel": "^32.3.3",
40
- "@milaboratories/uikit": "^2.2.9",
41
- "@platforma-sdk/model": "^1.10.12"
40
+ "@platforma-sdk/model": "^1.10.12",
41
+ "@milaboratories/uikit": "^2.2.9"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@faker-js/faker": "^8.4.1",
@@ -61,7 +61,7 @@
61
61
  "vue-tsc": "^2.1.6",
62
62
  "zod": "^3.23.8",
63
63
  "yarpm": "^1.2.0",
64
- "@milaboratories/helpers": "^1.6.6"
64
+ "@milaboratories/helpers": "^1.6.7"
65
65
  },
66
66
  "scripts": {
67
67
  "test": "vitest run --passWithNoTests",
package/src/aggrid.ts CHANGED
@@ -13,7 +13,8 @@ import { MenuModule } from '@ag-grid-enterprise/menu';
13
13
  import { ExcelExportModule } from '@ag-grid-enterprise/excel-export';
14
14
  import { SideBarModule } from '@ag-grid-enterprise/side-bar';
15
15
  import { ColumnsToolPanelModule } from '@ag-grid-enterprise/column-tool-panel';
16
- import { type Theme, themeQuartz } from '@ag-grid-community/theming';
16
+ import { type Theme, themeQuartz, createPart } from '@ag-grid-community/theming';
17
+ import OverrideCss from './components/PlAgDataTable/ag-override.css?raw';
17
18
 
18
19
  export function activateAgGrid() {
19
20
  ModuleRegistry.registerModules([
@@ -38,33 +39,37 @@ export function activateAgGrid() {
38
39
  }
39
40
  }
40
41
 
41
- export const AgGridTheme: Theme = themeQuartz.withParams({
42
- headerColumnResizeHandleColor: 'transparent',
43
- accentColor: '#110529',
44
- borderColor: '#E1E3EB',
45
- cellHorizontalPaddingScale: 1,
46
- checkboxBorderRadius: '3px',
47
- checkboxUncheckedBorderColor: '#CFD1DB',
48
- columnBorder: true,
49
- columnHoverColor: '#9BABCC16',
50
- fontFamily: 'inherit',
51
- foregroundColor: '#110529',
52
- headerBackgroundColor: '#F7F8FA',
53
- headerColumnBorder: true,
54
- headerFontWeight: 600,
55
- headerRowBorder: true,
56
- headerVerticalPaddingScale: 0.8,
57
- iconButtonHoverColor: '#9BABCC32',
58
- iconSize: '16px',
59
- menuBackgroundColor: '#FFFFFF',
60
- menuBorder: true,
61
- menuTextColor: '#110529',
62
- rowHoverColor: '#9BABCC16',
63
- rowVerticalPaddingScale: 1,
64
- selectedRowBackgroundColor: '#63E02424',
65
- sidePanelBorder: false,
66
- spacing: '8px',
67
- tooltipBackgroundColor: '#110529',
68
- tooltipTextColor: '#FFFFFF',
69
- wrapperBorderRadius: '6px',
70
- });
42
+ const agGridOverrideStyles = createPart('headerBottomBorder').withCSS(OverrideCss);
43
+
44
+ export const AgGridTheme: Theme = themeQuartz
45
+ .withParams({
46
+ headerColumnResizeHandleColor: 'transparent',
47
+ accentColor: '#110529',
48
+ borderColor: '#E1E3EB',
49
+ cellHorizontalPaddingScale: 1,
50
+ checkboxBorderRadius: '3px',
51
+ checkboxUncheckedBorderColor: '#CFD1DB',
52
+ columnBorder: true,
53
+ columnHoverColor: '#9BABCC16',
54
+ fontFamily: 'inherit',
55
+ foregroundColor: '#110529',
56
+ headerBackgroundColor: '#F7F8FA',
57
+ headerColumnBorder: true,
58
+ headerFontWeight: 600,
59
+ headerRowBorder: true,
60
+ headerVerticalPaddingScale: 0.8,
61
+ iconButtonHoverColor: '#9BABCC32',
62
+ iconSize: '16px',
63
+ menuBackgroundColor: '#FFFFFF',
64
+ menuBorder: true,
65
+ menuTextColor: '#110529',
66
+ rowHoverColor: '#9BABCC16',
67
+ rowVerticalPaddingScale: 1,
68
+ selectedRowBackgroundColor: '#63E02424',
69
+ sidePanelBorder: false,
70
+ spacing: '8px',
71
+ tooltipBackgroundColor: '#110529',
72
+ tooltipTextColor: '#FFFFFF',
73
+ wrapperBorderRadius: '6px',
74
+ })
75
+ .withPart(agGridOverrideStyles);
@@ -0,0 +1,3 @@
1
+ .ag-header {
2
+ border-bottom: 1px solid var(--border-color-default);
3
+ }
package/src/defineApp.ts CHANGED
@@ -3,7 +3,7 @@ import { type BlockOutputsBase, type Platforma } from '@platforma-sdk/model';
3
3
  import type { Component, Reactive } from 'vue';
4
4
  import { inject, markRaw, reactive } from 'vue';
5
5
  import { createApp, type BaseApp } from './internal/createApp';
6
- import type { BaseSettings, Routes } from './types';
6
+ import type { AppSettings, ExtendSettings, Routes } from './types';
7
7
  import { activateAgGrid } from './aggrid';
8
8
 
9
9
  const pluginKey = Symbol('sdk-vue');
@@ -18,12 +18,13 @@ export function defineApp<
18
18
  Outputs extends BlockOutputsBase = BlockOutputsBase,
19
19
  UiState = unknown,
20
20
  Href extends `/${string}` = `/${string}`,
21
- Local extends BaseSettings<Href> = BaseSettings<Href>,
21
+ Extend extends ExtendSettings<Href> = ExtendSettings<Href>,
22
22
  >(
23
23
  platforma: Platforma<Args, Outputs, UiState, Href>,
24
- extendApp: (app: BaseApp<Args, Outputs, UiState, Href>) => Local,
25
- ): SdkPlugin<Args, Outputs, UiState, Href, Local> {
26
- let app: undefined | App<Args, Outputs, UiState, Href, Local> = undefined;
24
+ extendApp: (app: BaseApp<Args, Outputs, UiState, Href>) => Extend,
25
+ settings: AppSettings = {},
26
+ ): SdkPlugin<Args, Outputs, UiState, Href, Extend> {
27
+ let app: undefined | App<Args, Outputs, UiState, Href, Extend> = undefined;
27
28
 
28
29
  activateAgGrid();
29
30
 
@@ -32,7 +33,7 @@ export function defineApp<
32
33
  .loadBlockState()
33
34
  .then((state) => {
34
35
  plugin.loaded = true;
35
- const baseApp = createApp<Args, Outputs, UiState, Href>(state, platforma);
36
+ const baseApp = createApp<Args, Outputs, UiState, Href>(state, platforma, settings);
36
37
 
37
38
  const localState = extendApp(baseApp);
38
39
 
@@ -48,7 +49,7 @@ export function defineApp<
48
49
  getRoute(href: Href): Component | undefined {
49
50
  return routes[href];
50
51
  },
51
- } as unknown as App<Args, Outputs, UiState, Href, Local>);
52
+ } as unknown as App<Args, Outputs, UiState, Href, Extend>);
52
53
  })
53
54
  .catch((err) => {
54
55
  console.error('load initial state error', err);
@@ -61,7 +62,7 @@ export function defineApp<
61
62
  error: undefined as unknown,
62
63
  // Href to get typed query parameters for a specific route
63
64
  useApp<PageHref extends Href = Href>() {
64
- return notEmpty(app, 'App is not loaded') as App<Args, Outputs, UiState, PageHref, Local>;
65
+ return notEmpty(app, 'App is not loaded') as App<Args, Outputs, UiState, PageHref, Extend>;
65
66
  },
66
67
  // @todo type portability issue with Vue
67
68
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -79,7 +80,7 @@ export type App<
79
80
  Outputs extends BlockOutputsBase = BlockOutputsBase,
80
81
  UiState = unknown,
81
82
  Href extends `/${string}` = `/${string}`,
82
- Local extends BaseSettings<Href> = BaseSettings<Href>,
83
+ Local extends ExtendSettings<Href> = ExtendSettings<Href>,
83
84
  > = BaseApp<Args, Outputs, UiState, Href> & Reactive<Omit<Local, 'routes'>> & { getRoute(href: Href): Component | undefined };
84
85
 
85
86
  export type SdkPlugin<
@@ -87,7 +88,7 @@ export type SdkPlugin<
87
88
  Outputs extends BlockOutputsBase = BlockOutputsBase,
88
89
  UiState = unknown,
89
90
  Href extends `/${string}` = `/${string}`,
90
- Local extends BaseSettings<Href> = BaseSettings<Href>,
91
+ Local extends ExtendSettings<Href> = ExtendSettings<Href>,
91
92
  > = {
92
93
  loaded: boolean;
93
94
  error: unknown;
@@ -2,7 +2,7 @@ import { deepClone, throttle } from '@milaboratories/helpers';
2
2
  import type { Mutable } from '@milaboratories/helpers';
3
3
  import type { NavigationState, BlockOutputsBase, BlockState, Platforma } from '@platforma-sdk/model';
4
4
  import { reactive, nextTick, computed, watch } from 'vue';
5
- import type { UnwrapValueOrErrors, StateModelOptions, UnwrapOutputs, OptionalResult, OutputValues, OutputErrors } from '../types';
5
+ import type { UnwrapValueOrErrors, StateModelOptions, UnwrapOutputs, OptionalResult, OutputValues, OutputErrors, AppSettings } from '../types';
6
6
  import { createModel } from '../createModel';
7
7
  import { createAppModel } from './createAppModel';
8
8
  import { parseQuery } from '../urls';
@@ -13,12 +13,18 @@ export function createApp<
13
13
  Outputs extends BlockOutputsBase = BlockOutputsBase,
14
14
  UiState = unknown,
15
15
  Href extends `/${string}` = `/${string}`,
16
- >(state: BlockState<Args, Outputs, UiState, Href>, platforma: Platforma<Args, Outputs, UiState, Href>) {
16
+ >(state: BlockState<Args, Outputs, UiState, Href>, platforma: Platforma<Args, Outputs, UiState, Href>, settings: AppSettings) {
17
17
  type AppModel = {
18
18
  args: Args;
19
19
  ui: UiState;
20
20
  };
21
21
 
22
+ const log = (msg: string, ...rest: unknown[]) => {
23
+ if (settings.debug) {
24
+ console.log(`%c>>> %c${msg}`, 'color: orange; font-weight: bold', 'color: orange', ...rest);
25
+ }
26
+ };
27
+
22
28
  const throttleSpan = 100; // @todo settings and more flexible
23
29
 
24
30
  const setBlockArgs = throttle(platforma.setBlockArgs, throttleSpan);
@@ -43,18 +49,22 @@ export function createApp<
43
49
  updates.forEach((patch) => {
44
50
  if (patch.key === 'args') {
45
51
  snapshot.args = Object.freeze(patch.value);
52
+ log('args patch', snapshot.args);
46
53
  }
47
54
 
48
55
  if (patch.key === 'ui') {
49
56
  snapshot.ui = Object.freeze(patch.value);
57
+ log('ui patch', snapshot.ui);
50
58
  }
51
59
 
52
60
  if (patch.key === 'outputs') {
53
61
  snapshot.outputs = Object.freeze(patch.value);
62
+ log('outputs patch', snapshot.outputs);
54
63
  }
55
64
 
56
65
  if (patch.key === 'navigationState') {
57
66
  snapshot.navigationState = Object.freeze(patch.value);
67
+ log('navigationState patch', snapshot.navigationState);
58
68
  }
59
69
  });
60
70
 
@@ -101,23 +111,6 @@ export function createApp<
101
111
  },
102
112
  });
103
113
  },
104
- // @TODO currently disabled but will be used
105
- // createAppModel<T extends AppModel = AppModel>(options: StateModelOptions<AppModel, T> = {}) {
106
- // return createAppModel<T, AppModel>({
107
- // get() {
108
- // if (options.transform) {
109
- // return options.transform(snapshot);
110
- // }
111
-
112
- // return { args: snapshot.args, ui: snapshot.ui } as T;
113
- // },
114
- // validate: options.validate,
115
- // autoSave: true,
116
- // onSave(newData) {
117
- // setBlockArgsAndUiState(newData.args, newData.ui);
118
- // },
119
- // });
120
- // },
121
114
  /**
122
115
  * Note: Don't forget to list the output names, like: useOutputs('output1', 'output2', ...etc)
123
116
  * @param keys - List of output names
@@ -277,6 +270,7 @@ export function createApp<
277
270
  outputs,
278
271
  outputErrors,
279
272
  },
273
+ settings,
280
274
  );
281
275
 
282
276
  return reactive(Object.assign(appModel, methods, getters));
@@ -1,13 +1,13 @@
1
1
  import { reactive, computed, ref, watch, unref, type ComputedRef, type UnwrapNestedRefs } from 'vue';
2
- import type { ModelOptions, Model } from '../types';
3
- import { deepClone } from '@milaboratories/helpers';
2
+ import type { ModelOptions, Model, AppSettings } from '../types';
3
+ import { deepClone, deepPatch } from '@milaboratories/helpers';
4
4
  import { isJsonEqual, identity, ensureError, isZodError, formatZodError } from '../utils';
5
5
 
6
6
  export function createAppModel<
7
7
  M extends { args: unknown; ui: unknown },
8
8
  V = unknown,
9
9
  E extends Record<string, ComputedRef<unknown>> = Record<string, ComputedRef<unknown>>,
10
- >(options: ModelOptions<M, V>, extended?: E): Model<M & UnwrapNestedRefs<E>> {
10
+ >(options: ModelOptions<M, V>, extended: E, settings: AppSettings): Model<M & UnwrapNestedRefs<E>> {
11
11
  type R = M & UnwrapNestedRefs<E>;
12
12
 
13
13
  const validate = options.validate ?? identity;
@@ -19,10 +19,21 @@ export function createAppModel<
19
19
  const local = ref<{ model: R; readonly stage: symbol }>();
20
20
 
21
21
  const setSource = (v: M) => {
22
- local.value = {
23
- model: Object.assign(deepClone(v), extended ?? {}) as R,
24
- stage: Symbol(),
25
- };
22
+ if (settings.deepPatchModel) {
23
+ // deep patch
24
+ const model = local.value?.model;
25
+ const updated = Object.assign(deepClone(v), extended ?? {}) as R;
26
+ local.value = {
27
+ model: model ? deepPatch(model, updated) : updated,
28
+ stage: Symbol(),
29
+ };
30
+ } else {
31
+ // shallow replace
32
+ local.value = {
33
+ model: Object.assign(deepClone(v), extended ?? {}) as R,
34
+ stage: Symbol(),
35
+ };
36
+ }
26
37
  };
27
38
 
28
39
  watch(
package/src/types.ts CHANGED
@@ -51,7 +51,18 @@ export type RouteParams<Href extends `/${string}` = `/${string}`> = {
51
51
  [P in Href as ParsePathnamePart<P>]: ParseQuery<P>;
52
52
  };
53
53
 
54
- export type BaseSettings<Href extends `/${string}` = `/${string}`> = {
54
+ export type AppSettings = {
55
+ /**
56
+ * Deep patch `model.` This parameter affects how you listen to model changes; a deep watcher is required if you use the `source` function.
57
+ */
58
+ deepPatchModel?: boolean;
59
+ /**
60
+ * Enables some debug logs
61
+ */
62
+ debug?: boolean;
63
+ };
64
+
65
+ export type ExtendSettings<Href extends `/${string}` = `/${string}`> = {
55
66
  showErrorsNotification?: boolean;
56
67
  routes: Routes<Href>;
57
68
  };