From 73b335622b7e45786b6461d0916afb3361c08fa6 Mon Sep 17 00:00:00 2001 From: Lee Wexler Date: Tue, 3 Dec 2024 17:53:48 -0500 Subject: [PATCH] Update to latest view manager (#739) --- .../tests/viewmanager/ViewManagerTestModel.ts | 68 ++++-- .../tests/viewmanager/ViewManagerTestPanel.ts | 202 +++++++++++------- client-app/src/examples/portfolio/AppModel.ts | 6 +- 3 files changed, 173 insertions(+), 103 deletions(-) diff --git a/client-app/src/admin/tests/viewmanager/ViewManagerTestModel.ts b/client-app/src/admin/tests/viewmanager/ViewManagerTestModel.ts index a3bb3cb94..95e3bf8fc 100644 --- a/client-app/src/admin/tests/viewmanager/ViewManagerTestModel.ts +++ b/client-app/src/admin/tests/viewmanager/ViewManagerTestModel.ts @@ -4,13 +4,13 @@ import {GroupingChooserModel} from '@xh/hoist/cmp/grouping'; import {div, frame} from '@xh/hoist/cmp/layout'; import {TabContainerModel} from '@xh/hoist/cmp/tab'; import {creates, hoistCmp, HoistModel, lookup, managed, PersistOptions, XH} from '@xh/hoist/core'; -import {ViewManagerModel} from '@xh/hoist/core/persist/viewmanager'; +import {ViewManagerModel} from '@xh/hoist/cmp/viewmanager'; import {required} from '@xh/hoist/data'; import {DashCanvasModel, DashContainerModel, DashViewModel} from '@xh/hoist/desktop/cmp/dash'; import {filterChooser} from '@xh/hoist/desktop/cmp/filter'; -import {groupingChooser} from '@xh/hoist/desktop/cmp/grouping'; import {PanelModel} from '@xh/hoist/desktop/cmp/panel'; import {Icon} from '@xh/hoist/icon'; +import {groupingChooser} from '@xh/hoist/desktop/cmp/grouping'; import {action, bindable, computed, makeObservable, observable, runInAction} from '@xh/hoist/mobx'; import {get} from 'lodash'; import {sampleGrid, SampleGridModel} from '../../../desktop/common'; @@ -53,7 +53,7 @@ export class ViewManagerTestModel extends HoistModel { get value(): string { const {viewManagerModel, focusedPersistable} = this; if (!viewManagerModel) return '[No ViewManagerModel]'; - const {value} = viewManagerModel; + const value = viewManagerModel.view.value; return JSON.stringify(focusedPersistable ? get(value, focusedPersistable) : value, null, 2); } @@ -61,7 +61,7 @@ export class ViewManagerTestModel extends HoistModel { get pendingValue(): string { const {viewManagerModel, focusedPersistable} = this; if (!viewManagerModel) return '[No ViewManagerModel]'; - const {pendingValue} = viewManagerModel; + const pendingValue = viewManagerModel.getValue(); return JSON.stringify( focusedPersistable ? get(pendingValue, focusedPersistable) : pendingValue, null, @@ -76,12 +76,15 @@ export class ViewManagerTestModel extends HoistModel { .map(it => it.name); return [ 'viewType', - 'viewTypeDisplayName', + 'typeDisplayName', + 'globalDisplayName', 'localStorageKey', - 'enableSharing', - 'enableDefault', + 'sessionStorageKey', + 'manageGlobal', 'enableAutoSave', - 'enableFavorites' + 'enableDefault', + 'enableFavorites', + 'initialViewName' ].some(it => dirtyFields.includes(it)); } @@ -92,22 +95,27 @@ export class ViewManagerTestModel extends HoistModel { this.configFormModel = new FormModel({ fields: [ {name: 'viewType', rules: [required], initialValue: 'testView'}, - {name: 'viewTypeDisplayName', initialValue: 'View'}, + {name: 'typeDisplayName', initialValue: 'view'}, + {name: 'globalDisplayName', initialValue: 'global'}, {name: 'localStorageKey', initialValue: 'viewManagerTest'}, - {name: 'enableSharing', displayName: 'Sharing', initialValue: true}, - {name: 'enableDefault', displayName: 'Default', initialValue: true}, - {name: 'enableAutoSave', displayName: 'AutoSave', initialValue: true}, - {name: 'enableFavorites', displayName: 'Faves', initialValue: true}, + {name: 'sessionStorageKey', initialValue: 'viewManagerTest'}, + {name: 'manageGlobal', initialValue: true}, + {name: 'enableFavorites', initialValue: true}, + {name: 'enableAutoSave', initialValue: true}, + {name: 'enableDefault', initialValue: true}, + {name: 'initialViewName', initialValue: null}, + {name: 'settleTime', initialValue: 250}, {name: 'showSaveButton', initialValue: 'whenDirty'}, {name: 'showRevertButton', initialValue: 'never'}, + {name: 'buttonSide', initialValue: 'right'}, { name: 'showPrivateViewsInSubMenu', displayName: 'Show private views in sub-menu', initialValue: false }, { - name: 'showSharedViewsInSubMenu', - displayName: 'Show shared views in sub-menu', + name: 'showGlobalViewsInSubMenu', + displayName: 'Show global views in sub-menu', initialValue: false }, { @@ -117,7 +125,6 @@ export class ViewManagerTestModel extends HoistModel { } ] }); - this.rebuildViewManagerModelAsync(); } @@ -130,22 +137,33 @@ export class ViewManagerTestModel extends HoistModel { const data = configFormModel.getData(), { viewType, - viewTypeDisplayName, + typeDisplayName, + globalDisplayName, localStorageKey, - enableSharing, + sessionStorageKey, + manageGlobal, enableDefault, enableAutoSave, - enableFavorites + enableFavorites, + initialViewName, + settleTime } = data; + const persistWith = localStorageKey + ? {localStorageKey, persistPendingValue: {sessionStorageKey}} + : null; + const newModel = await ViewManagerModel.createAsync({ viewType, - viewTypeDisplayName, - persistWith: localStorageKey ? {localStorageKey: localStorageKey} : null, - enableSharing, + typeDisplayName, + globalDisplayName, + manageGlobal, enableDefault, enableAutoSave, - enableFavorites + enableFavorites, + persistWith, + settleTime, + initialViewSpec: views => views.find(v => v.name == initialViewName) ?? views[0] }); runInAction(() => { @@ -285,6 +303,7 @@ export class ViewManagerTestModel extends HoistModel { */ class PersistedPropertyModel extends HoistModel { @bindable stringValue = 'Some Default Value'; + constructor({persistWith}: {persistWith: PersistOptions}) { super(); makeObservable(this); @@ -316,6 +335,7 @@ class BaseWidgetModel extends HoistModel { class GroupingChooserWidgetModel extends BaseWidgetModel { groupingChooserModel: GroupingChooserModel; + override onLinked() { super.onLinked(); this.groupingChooserModel = createGroupingChooserModel(this.persistWith); @@ -339,6 +359,7 @@ const createGroupingChooserModel = (persistWith: PersistOptions) => { class FilterChooserWidgetModel extends BaseWidgetModel { filterChooserModel: FilterChooserModel; + override onLinked() { super.onLinked(); this.filterChooserModel = createFilterChooserModel(this.persistWith, this.localStorageKey); @@ -369,6 +390,7 @@ const createFilterChooserModel = (persistWith: PersistOptions, localStorageKey: class gridWidgetModel extends BaseWidgetModel { gridModel: SampleGridModel; + override onLinked() { super.onLinked(); this.gridModel = new SampleGridModel({gridConfig: {persistWith: this.persistWith}}); diff --git a/client-app/src/admin/tests/viewmanager/ViewManagerTestPanel.ts b/client-app/src/admin/tests/viewmanager/ViewManagerTestPanel.ts index 166063c1c..3fff9196c 100644 --- a/client-app/src/admin/tests/viewmanager/ViewManagerTestPanel.ts +++ b/client-app/src/admin/tests/viewmanager/ViewManagerTestPanel.ts @@ -1,6 +1,6 @@ import {badge} from '@xh/hoist/cmp/badge'; import {form} from '@xh/hoist/cmp/form'; -import {div, filler, h3, hbox, hframe, hspacer, placeholder, vframe} from '@xh/hoist/cmp/layout'; +import {div, filler, hbox, hframe, hspacer, placeholder, vframe} from '@xh/hoist/cmp/layout'; import {tabContainer} from '@xh/hoist/cmp/tab'; import {creates, hoistCmp, uses} from '@xh/hoist/core'; import {button} from '@xh/hoist/desktop/cmp/button'; @@ -13,6 +13,7 @@ import {panel} from '@xh/hoist/desktop/cmp/panel'; import {toolbar} from '@xh/hoist/desktop/cmp/toolbar'; import {viewManager} from '@xh/hoist/desktop/cmp/viewmanager'; import {Icon} from '@xh/hoist/icon'; +import {numberInput} from '@xh/hoist/desktop/cmp/input'; import {get, isEqual} from 'lodash'; import {sampleGrid} from '../../../desktop/common'; import {ViewManagerTestModel} from './ViewManagerTestModel'; @@ -23,7 +24,7 @@ export const viewManagerTestPanel = hoistCmp.factory({ className: 'tb-vm-test', model: creates(ViewManagerTestModel), - render({model, className}) { + render({className}) { return panel({ className, item: hframe({ @@ -37,7 +38,7 @@ export const viewManagerTestPanel = hoistCmp.factory({ defaultSize: 500 }, items: [ - modelConFigForm(), + modelConfigForm(), hframe(modelValueDisplay(), modelValueDisplay({showPendingValue: true})) ] }), @@ -48,7 +49,7 @@ export const viewManagerTestPanel = hoistCmp.factory({ } }); -const modelConFigForm = hoistCmp.factory({ +const modelConfigForm = hoistCmp.factory({ render({model}) { const {configFormModel, modelConfigDirty} = model, {isValid} = configFormModel; @@ -56,72 +57,13 @@ const modelConFigForm = hoistCmp.factory({ flex: 'none', item: form({ fieldDefaults: {commitOnChange: true, minimal: true, inline: true, labelWidth: 160}, - item: vframe({ - className: 'xh-pad tb-vm-test__model-conf', - items: [ - h3('ViewManagerModel Configs'), - formField({ - field: 'viewType', - info: 'Determines backing JSONBlob query', - item: textInput() - }), - formField({ - field: 'viewTypeDisplayName', - item: textInput({enableClear: true}) - }), - formField({ - field: 'localStorageKey', - info: 'Persists last-selected view + autoSave/favorites', - item: textInput({enableClear: true}) - }), - hbox( - formField({ - field: 'enableSharing', - item: switchInput() - }), - formField({ - field: 'enableDefault', - item: switchInput() - }), - formField({ - field: 'enableAutoSave', - item: switchInput() - }), - formField({ - field: 'enableFavorites', - item: switchInput() - }) - ), - h3('ViewManager Props'), - formField({ - field: 'showSaveButton', - item: select({ - options: ['always', 'never', 'whenDirty'], - enableFilter: false - }) - }), - formField({ - field: 'showRevertButton', - item: select({ - options: ['always', 'never', 'whenDirty'], - enableFilter: false - }) - }), - hbox( - formField({ - field: 'showPrivateViewsInSubMenu', - item: switchInput() - }), - formField({ - field: 'showSharedViewsInSubMenu', - item: switchInput() - }), - formField({ - field: 'customMenuButtonProps', - item: switchInput() - }) - ) - ] + item: tabContainer({ + modelConfig: { + tabs: [ + {id: 'modelConfig', content: modelConfig()}, + {id: 'cmpProps', content: cmpProps()} + ] + } }) }), bbar: toolbar({ @@ -142,6 +84,107 @@ const modelConFigForm = hoistCmp.factory({ } }); +const cmpProps = hoistCmp.factory({ + render() { + return vframe({ + className: 'xh-pad tb-vm-test__model-conf', + items: [ + formField({ + field: 'showSaveButton', + item: select({ + options: ['always', 'never', 'whenDirty'], + enableFilter: false + }) + }), + formField({ + field: 'showRevertButton', + item: select({ + options: ['always', 'never', 'whenDirty'], + enableFilter: false + }) + }), + formField({ + field: 'buttonSide', + item: select({ + options: ['left', 'right'], + enableFilter: false + }) + }), + hbox( + formField({ + field: 'showPrivateViewsInSubMenu', + item: switchInput() + }), + formField({ + field: 'showGlobalViewsInSubMenu', + item: switchInput() + }), + formField({ + field: 'customMenuButtonProps', + item: switchInput() + }) + ) + ] + }); + } +}); + +const modelConfig = hoistCmp.factory({ + render() { + return vframe({ + className: 'xh-pad tb-vm-test__model-conf', + items: [ + formField({ + field: 'viewType', + item: textInput() + }), + formField({ + field: 'typeDisplayName', + item: textInput({enableClear: true}) + }), + formField({ + field: 'globalDisplayName', + item: textInput({enableClear: true}) + }), + formField({ + field: 'localStorageKey', + item: textInput({enableClear: true}) + }), + formField({ + field: 'sessionStorageKey', + item: textInput({enableClear: true}) + }), + formField({ + field: 'initialViewName', + item: textInput({enableClear: true}) + }), + formField({ + field: 'settleTime', + item: numberInput() + }), + hbox( + formField({ + field: 'manageGlobal', + item: switchInput() + }), + formField({ + field: 'enableAutoSave', + item: switchInput() + }), + formField({ + field: 'enableFavorites', + item: switchInput() + }), + formField({ + field: 'enableDefault', + item: switchInput() + }) + ) + ] + }); + } +}); + const modelValueDisplay = hoistCmp.factory({ render({model, showPendingValue}) { let title = showPendingValue ? 'Pending' : 'Value'; @@ -155,12 +198,12 @@ const modelValueDisplay = hoistCmp.factory({ badge({ intent: 'danger', item: 'Dirty', - omit: !showPendingValue || !model.viewManagerModel?.isDirty + omit: !showPendingValue || !model.viewManagerModel?.isValueDirty }), badge({ intent: 'success', item: 'Clean', - omit: !showPendingValue || model.viewManagerModel?.isDirty + omit: !showPendingValue || model.viewManagerModel?.isValueDirty }), hspacer() ], @@ -184,8 +227,9 @@ const persistablesPanel = hoistCmp.factory({ showSaveButton, showRevertButton, showPrivateViewsInSubMenu, - showSharedViewsInSubMenu, - customMenuButtonProps + showGlobalViewsInSubMenu, + customMenuButtonProps, + buttonSide } = model.configFormModel.values, menuButtonProps = customMenuButtonProps ? ({ @@ -196,12 +240,14 @@ const persistablesPanel = hoistCmp.factory({ return panel({ className: 'tb-vm-test__output', tbar: [ + filler({omit: buttonSide == 'right'}), viewManager({ showSaveButton, showRevertButton, showPrivateViewsInSubMenu, - showSharedViewsInSubMenu, - menuButtonProps + showGlobalViewsInSubMenu, + menuButtonProps, + buttonSide }) ], item: div({ @@ -303,7 +349,9 @@ const persistedComp = hoistCmp.factory({ model: uses(ViewManagerTestModel), render({title, icon, persistPath, children, model, minHeight}) { if (!persistPath) return null; - const {value, pendingValue} = model.viewManagerModel, + const {viewManagerModel} = model, + {value} = viewManagerModel.view, + pendingValue = viewManagerModel.getValue(), compVal = get(value, persistPath), compPendingVal = get(pendingValue, persistPath), atDefault = !compPendingVal, diff --git a/client-app/src/examples/portfolio/AppModel.ts b/client-app/src/examples/portfolio/AppModel.ts index 072a3afb6..cda891222 100644 --- a/client-app/src/examples/portfolio/AppModel.ts +++ b/client-app/src/examples/portfolio/AppModel.ts @@ -1,5 +1,5 @@ import {XH} from '@xh/hoist/core'; -import {ViewManagerModel} from '@xh/hoist/core/persist/viewmanager'; +import {ViewManagerModel} from '@xh/hoist/cmp/viewmanager'; import {sizingModeAppOption, themeAppOption} from '@xh/hoist/desktop/cmp/appOption'; import {Icon} from '@xh/hoist/icon'; import {BaseAppModel} from '../../BaseAppModel'; @@ -19,9 +19,9 @@ export class AppModel extends BaseAppModel { // is used to construct component-level models within PortfolioModel. this.portfolioViewManager = await ViewManagerModel.createAsync({ viewType: 'portfolioLayout', - viewTypeDisplayName: 'Layout', + typeDisplayName: 'Layout', enableDefault: true, - enableSharing: true, + manageGlobal: true, persistWith: {localStorageKey: 'portfolioViewManager'} });