Skip to content

Commit

Permalink
Merge confilct in change log
Browse files Browse the repository at this point in the history
  • Loading branch information
oodarluz committed Jan 17, 2025
2 parents 06796cc + 819a084 commit be269c3
Show file tree
Hide file tree
Showing 12 changed files with 216 additions and 143 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,19 @@
* Addition of ability to append terms to active filter **only** when `commitOnChage:false`
* Column header filtering functionality now similar to Excel on Windows

### 🐞 Bug Fixes

* Fixed `ViewManagerModel` unique name validation.

### ⚙️ Technical

* Added support for providing custom `PersistenceProvider` implementations to `PersistOptions`.


### ⚙️ Typescript API Adjustments

* Improved signature of `HoistBase.markPersist`.

## v71.0.0 - 2025-01-08

### 💥 Breaking Changes (upgrade difficulty: 🟠 MEDIUM - Hoist core update, import adjustments)
Expand Down
3 changes: 2 additions & 1 deletion cmp/viewmanager/ViewManagerModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,8 @@ export class ViewManagerModel<T = PlainObject> extends HoistModel {
if (name.length > maxLength) {
return `Name cannot be longer than ${maxLength} characters`;
}
if (this.ownedViews.some(view => view.name === name && view.token != existing?.token)) {
const views = existing?.isGlobal ? this.globalViews : this.ownedViews;
if (views.some(view => view.name === name && view.token != existing?.token)) {
return `A ${this.typeDisplayName} with name '${name}' already exists.`;
}
return null;
Expand Down
2 changes: 1 addition & 1 deletion core/HoistBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ export abstract class HoistBase {
* @param options - options governing the persistence of this object. These will be applied
* on top of any default persistWith options defined on the instance itself.
*/
markPersist(property: keyof this & string, options: PersistOptions = {}) {
markPersist<P extends keyof this & string>(property: P, options: PersistOptions = {}) {
// Read from and attach to Provider, failing gently
PersistenceProvider.create({
persistOptions: {
Expand Down
24 changes: 19 additions & 5 deletions core/persist/PersistOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,22 @@
* Copyright © 2025 Extremely Heavy Industries Inc.
*/

import {DebounceSpec} from '../';
import {Class} from 'type-fest';
import {DebounceSpec, PersistenceProvider, PersistenceProviderConfig} from '../';
import type {DashViewModel} from '@xh/hoist/desktop/cmp/dash'; // Import type only
import type {ViewManagerModel} from '@xh/hoist/cmp/viewmanager'; // Import type only

/**
* Built-in Hoist PersistenceProviders.
*/
export type PersistenceProviderType =
| 'pref'
| 'localStorage'
| 'sessionStorage'
| 'dashView'
| 'viewManager'
| 'custom';

export interface PersistOptions {
/** Dot delimited path to store state. */
path?: string;
Expand All @@ -17,11 +29,13 @@ export interface PersistOptions {
debounce?: DebounceSpec;

/**
* Type of PersistenceProvider to create. If not provided, defaulted based
* on the presence of `prefKey`, `localStorageKey`, `dashViewModel`, 'viewManagerModel',
* `getData` and `setData`.
* Type of PersistenceProvider to create. Specify as one of the built-in string types,
* or a subclass of PersistenceProvider.
*
* If not provided, defaulted to one of the built-in string types based on the presence of
* `prefKey`, `localStorageKey`, `dashViewModel`, 'viewManagerModel', or `getData/setData`.
*/
type?: 'pref' | 'localStorage' | 'sessionStorage' | 'dashView' | 'viewManager' | 'custom';
type?: PersistenceProviderType | Class<PersistenceProvider, [PersistenceProviderConfig]>;

/** Predefined Hoist application Preference key used to store state. */
prefKey?: string;
Expand Down
103 changes: 48 additions & 55 deletions core/persist/PersistenceProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,29 @@ import {
get,
isEmpty,
isNumber,
isString,
isUndefined,
set,
toPath
} from 'lodash';
import {IReactionDisposer, reaction} from 'mobx';
import {DebounceSpec, HoistBase, Persistable, PersistableState, XH} from '../';
import {Class} from 'type-fest';
import {DebounceSpec, HoistBase, Persistable, PersistableState} from '../';
import {
CustomProvider,
DashViewProvider,
LocalStorageProvider,
SessionStorageProvider,
PersistOptions,
PrefProvider,
SessionStorageProvider,
ViewManagerProvider
} from './';

export type PersistenceProviderConfig<S> =
| {
persistOptions: PersistOptions;
target: Persistable<S>;
owner: HoistBase;
}
| {
persistOptions: PersistOptions;
target: Persistable<S> & HoistBase;
owner?: HoistBase;
};
export type PersistenceProviderConfig<S = any> = {
persistOptions: PersistOptions;
target: Persistable<S>;
owner?: HoistBase;
};

/**
* Abstract superclass for adaptor objects used by models and components to (re)store state to and
Expand All @@ -57,7 +53,7 @@ export type PersistenceProviderConfig<S> =
* - {@link ViewManagerProvider} - persists to saved views managed by {@link ViewManagerModel}.
* - {@link CustomProvider} - API for app and components to provide their own storage mechanism.
*/
export abstract class PersistenceProvider<S> {
export abstract class PersistenceProvider<S = any> {
readonly path: string;
readonly debounce: DebounceSpec;
readonly owner: HoistBase;
Expand All @@ -79,49 +75,14 @@ export abstract class PersistenceProvider<S> {
* target without thrashing.
*/
static create<S>(cfg: PersistenceProviderConfig<S>): PersistenceProvider<S> {
cfg = {
owner: cfg.target instanceof HoistBase ? cfg.target : cfg.owner,
...cfg
};
const {target, persistOptions} = cfg;

let {type, ...rest} = persistOptions,
ret: PersistenceProvider<S>;

let ret: PersistenceProvider<S>;
try {
if (!type) {
if (rest.prefKey) type = 'pref';
if (rest.localStorageKey) type = 'localStorage';
if (rest.sessionStorageKey) type = 'sessionStorage';
if (rest.dashViewModel) type = 'dashView';
if (rest.viewManagerModel) type = 'viewManager';
if (rest.getData || rest.setData) type = 'custom';
}

switch (type) {
case 'pref':
ret = new PrefProvider(cfg);
break;
case 'localStorage':
ret = new LocalStorageProvider(cfg);
break;
case 'sessionStorage':
ret = new SessionStorageProvider(cfg);
break;
case `dashView`:
ret = new DashViewProvider(cfg);
break;
case `viewManager`:
ret = new ViewManagerProvider(cfg);
break;
case 'custom':
ret = new CustomProvider(cfg);
break;
default:
throw XH.exception(`Unknown Persistence Provider for type: ${type}`);
}
// default owner to target
cfg = {owner: cfg.target instanceof HoistBase ? cfg.target : cfg.owner, ...cfg};

ret.bindToTarget(target);
const providerClass = this.parseProviderClass<S>(cfg.persistOptions);
ret = new providerClass(cfg);
ret.bindToTarget(cfg.target);
return ret;
} catch (e) {
logError(e, cfg.owner);
Expand Down Expand Up @@ -211,7 +172,39 @@ export abstract class PersistenceProvider<S> {
}

protected writeRaw(obj: Record<typeof this.path, S>) {}

protected readRaw(): Record<typeof this.path, S> {
return null;
}

private static parseProviderClass<S>(
opts: PersistOptions
): Class<PersistenceProvider<S>, [PersistenceProviderConfig<S>]> {
// 1) Recognize shortcut form
const {type, ...rest} = opts;
if (!type) {
if (rest.prefKey) return PrefProvider;
if (rest.localStorageKey) return LocalStorageProvider;
if (rest.sessionStorageKey) return SessionStorageProvider;
if (rest.dashViewModel) return DashViewProvider;
if (rest.viewManagerModel) return ViewManagerProvider;
if (rest.getData || rest.setData) return CustomProvider;
}

// 2) Map any string to known Provider Class, or return raw class
const ret = isString(type)
? {
pref: PrefProvider,
localStorage: LocalStorageProvider,
sessionStorage: SessionStorageProvider,
dashView: DashViewProvider,
viewManager: ViewManagerProvider,
custom: CustomProvider
}[type]
: type;

throwIf(!ret, `Unknown Persistence Provider: ${type}`);

return ret;
}
}
1 change: 0 additions & 1 deletion desktop/cmp/grid/editors/DateEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ export const [DateEditor, dateEditor] = hoistCmp.withFactory<DateEditorProps>({
...props,
inputProps: {
rightElement: null,

enablePicker: !!portalContainer,
showPickerOnFocus: !!portalContainer,
portalContainer,
Expand Down
61 changes: 36 additions & 25 deletions desktop/cmp/input/DateInput.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,46 @@
* Copyright © 2025 Extremely Heavy Industries Inc.
*/

.xh-date-input {
// Style input in picker-only mode
&--picker-only {
input {
color: var(--xh-input-text-color) !important;
background-color: var(--xh-input-bg) !important;
cursor: pointer !important;
}

.bp5-input-group.bp5-disabled {
cursor: pointer !important;
}
.xh-date-input__wrapper {
.bp5-input-action {
height: 100%;
}

// Style picker icon in input-only mode
&__picker-icon--disabled:hover {
background-color: transparent !important;
cursor: not-allowed;
.bp5-input-group .xh-icon {
position: relative;
margin: 0 !important;
}

// Style buttons when disabled
&.xh-input-disabled:not(.xh-date-input--picker-only) button:hover {
background-color: transparent !important;
cursor: not-allowed;
}
.xh-date-input {
// Style input in picker-only mode
&--picker-only {
input {
color: var(--xh-input-text-color) !important;
background-color: var(--xh-input-bg) !important;
cursor: pointer !important;
}

.bp5-input-group.bp5-disabled {
cursor: pointer !important;
}
}

// Prevent browser from capturing click events when input is disabled due to use of
// enableTextInput: false prop. See https://github.com/xh/hoist-react/issues/3460
input[disabled] {
pointer-events: none;
// Style picker icon in input-only mode
&__picker-icon--disabled:hover {
background-color: transparent !important;
cursor: not-allowed;
}

// Style buttons when disabled
&.xh-input-disabled:not(.xh-date-input--picker-only) button:hover {
background-color: transparent !important;
cursor: not-allowed;
}

// Prevent browser from capturing click events when input is disabled due to use of
// enableTextInput: false prop. See https://github.com/xh/hoist-react/issues/3460
input[disabled] {
pointer-events: none;
}
}
}
Loading

0 comments on commit be269c3

Please sign in to comment.