@xh/hoist 76.0.0-SNAPSHOT.1756991850787 → 76.0.0-SNAPSHOT.1757113228632
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/CHANGELOG.md +5 -1
- package/admin/AppModel.ts +54 -6
- package/admin/tabs/cluster/index.ts +2 -0
- package/admin/tabs/general/index.ts +3 -0
- package/admin/tabs/userData/index.ts +4 -0
- package/build/types/admin/tabs/cluster/index.d.ts +2 -0
- package/build/types/admin/tabs/general/index.d.ts +3 -0
- package/build/types/admin/tabs/userData/index.d.ts +4 -0
- package/build/types/cmp/tab/TabContainerModel.d.ts +14 -4
- package/build/types/cmp/tab/TabModel.d.ts +11 -11
- package/cmp/grid/GridModel.ts +1 -1
- package/cmp/tab/TabContainerModel.ts +23 -20
- package/cmp/tab/TabModel.ts +73 -31
- package/desktop/cmp/tab/impl/Tab.ts +1 -1
- package/package.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/admin/tabs/cluster/ClusterTab.ts +0 -24
- package/admin/tabs/general/GeneralTab.ts +0 -26
- package/admin/tabs/userData/UserDataTab.ts +0 -52
- package/build/types/admin/tabs/cluster/ClusterTab.d.ts +0 -1
- package/build/types/admin/tabs/general/GeneralTab.d.ts +0 -1
- package/build/types/admin/tabs/userData/UserDataTab.d.ts +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
## 76.0.0-SNAPSHOT - unreleased
|
|
4
4
|
|
|
5
|
-
### 💥 Breaking Changes (upgrade difficulty: 🟢 LOW - upgrade to Hoist Core)
|
|
5
|
+
### 💥 Breaking Changes (upgrade difficulty: 🟢 LOW - upgrade to Hoist Core, change to Tab constructor)
|
|
6
|
+
* The constructor for `TabModel` has changed to take its owning container as a second argument.
|
|
7
|
+
(Most applications do not create `TabModels` directly, but it is possible.)
|
|
6
8
|
|
|
7
9
|
### 🎁 New Features
|
|
8
10
|
|
|
@@ -11,6 +13,8 @@
|
|
|
11
13
|
or disruptive action.
|
|
12
14
|
* Updated grid column filters to apply on `Enter` / dismiss on `Esc` and tweaked the filter popup
|
|
13
15
|
toolbar for clarity.
|
|
16
|
+
* Added new ability to specify nested tab containers in a single declarative config. Apps may now
|
|
17
|
+
provide a spec for a nested tab container directly to the `TabConfig.content` property.
|
|
14
18
|
|
|
15
19
|
### 🐞 Bug Fixes
|
|
16
20
|
|
package/admin/AppModel.ts
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Copyright © 2025 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
|
-
import {clusterTab} from '@xh/hoist/admin/tabs/cluster/ClusterTab';
|
|
8
7
|
import {GridModel} from '@xh/hoist/cmp/grid';
|
|
9
8
|
import {TabConfig, TabContainerModel} from '@xh/hoist/cmp/tab';
|
|
10
9
|
import {ViewManagerModel} from '@xh/hoist/cmp/viewmanager';
|
|
@@ -14,9 +13,15 @@ import {without} from 'lodash';
|
|
|
14
13
|
import {Route} from 'router5';
|
|
15
14
|
import {activityTrackingPanel} from './tabs/activity/tracking/ActivityTrackingPanel';
|
|
16
15
|
import {clientsPanel} from './tabs/clients/ClientsPanel';
|
|
17
|
-
import {generalTab} from './tabs/general/GeneralTab';
|
|
18
16
|
import {monitorTab} from './tabs/monitor/MonitorTab';
|
|
19
|
-
import {
|
|
17
|
+
import {instancesTab, clusterObjectsPanel} from '@xh/hoist/admin/tabs/cluster';
|
|
18
|
+
import {aboutPanel, alertBannerPanel, configPanel} from '@xh/hoist/admin/tabs/general';
|
|
19
|
+
import {
|
|
20
|
+
jsonBlobPanel,
|
|
21
|
+
userPreferencePanel,
|
|
22
|
+
rolePanel,
|
|
23
|
+
userPanel
|
|
24
|
+
} from '@xh/hoist/admin/tabs/userData';
|
|
20
25
|
|
|
21
26
|
export class AppModel extends HoistAppModel {
|
|
22
27
|
tabModel: TabContainerModel;
|
|
@@ -118,16 +123,31 @@ export class AppModel extends HoistAppModel {
|
|
|
118
123
|
}
|
|
119
124
|
|
|
120
125
|
createTabs(): TabConfig[] {
|
|
126
|
+
const conf = XH.getConf('xhAdminAppConfig', {});
|
|
127
|
+
|
|
121
128
|
return [
|
|
122
129
|
{
|
|
123
130
|
id: 'general',
|
|
124
131
|
icon: Icon.info(),
|
|
125
|
-
content:
|
|
132
|
+
content: {
|
|
133
|
+
switcher: {orientation: 'left', testId: 'general-tab-switcher'},
|
|
134
|
+
tabs: [
|
|
135
|
+
{id: 'about', icon: Icon.info(), content: aboutPanel},
|
|
136
|
+
{id: 'config', icon: Icon.settings(), content: configPanel},
|
|
137
|
+
{id: 'alertBanner', icon: Icon.bullhorn(), content: alertBannerPanel}
|
|
138
|
+
]
|
|
139
|
+
}
|
|
126
140
|
},
|
|
127
141
|
{
|
|
128
142
|
id: 'servers',
|
|
129
143
|
icon: Icon.server(),
|
|
130
|
-
content:
|
|
144
|
+
content: {
|
|
145
|
+
switcher: {orientation: 'left', testId: 'cluster-tab-switcher'},
|
|
146
|
+
tabs: [
|
|
147
|
+
{id: 'instances', icon: Icon.server(), content: instancesTab},
|
|
148
|
+
{id: 'objects', icon: Icon.boxFull(), content: clusterObjectsPanel}
|
|
149
|
+
]
|
|
150
|
+
}
|
|
131
151
|
},
|
|
132
152
|
{
|
|
133
153
|
id: 'clients',
|
|
@@ -142,7 +162,35 @@ export class AppModel extends HoistAppModel {
|
|
|
142
162
|
{
|
|
143
163
|
id: 'userData',
|
|
144
164
|
icon: Icon.users(),
|
|
145
|
-
content:
|
|
165
|
+
content: {
|
|
166
|
+
switcher: {orientation: 'left', testId: 'user-data-tab-switcher'},
|
|
167
|
+
refreshMode: 'onShowAlways',
|
|
168
|
+
tabs: [
|
|
169
|
+
{
|
|
170
|
+
id: 'users',
|
|
171
|
+
icon: Icon.users(),
|
|
172
|
+
content: userPanel,
|
|
173
|
+
omit: conf['hideUsersTab']
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
id: 'roles',
|
|
177
|
+
icon: Icon.idBadge(),
|
|
178
|
+
content: rolePanel
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
id: 'prefs',
|
|
182
|
+
title: 'Preferences',
|
|
183
|
+
icon: Icon.bookmark(),
|
|
184
|
+
content: userPreferencePanel
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
id: 'jsonBlobs',
|
|
188
|
+
title: 'JSON Blobs',
|
|
189
|
+
icon: Icon.json(),
|
|
190
|
+
content: jsonBlobPanel
|
|
191
|
+
}
|
|
192
|
+
]
|
|
193
|
+
}
|
|
146
194
|
},
|
|
147
195
|
{
|
|
148
196
|
id: 'activity',
|
|
@@ -4,7 +4,7 @@ import { TabConfig, TabModel } from './TabModel';
|
|
|
4
4
|
import { TabSwitcherProps } from './TabSwitcherProps';
|
|
5
5
|
export interface TabContainerConfig {
|
|
6
6
|
/** Tabs to be displayed. */
|
|
7
|
-
tabs
|
|
7
|
+
tabs: TabConfig[];
|
|
8
8
|
/**
|
|
9
9
|
* ID of Tab to be shown initially if routing does not specify otherwise. If not set,
|
|
10
10
|
* will default to first tab in the provided collection.
|
|
@@ -74,10 +74,18 @@ export declare class TabContainerModel extends HoistModel implements Persistable
|
|
|
74
74
|
setTabs(tabs: Array<TabModel | TabConfig>): void;
|
|
75
75
|
/** Add a single tab to the container. */
|
|
76
76
|
addTab(tab: TabModel | TabConfig, opts?: AddTabOptions): TabModel;
|
|
77
|
-
/**
|
|
77
|
+
/**
|
|
78
|
+
* Remove a single tab from the container.
|
|
79
|
+
* Supported for tabs that are immediate children of this container.
|
|
80
|
+
**/
|
|
78
81
|
removeTab(tab: TabModel | string): void;
|
|
79
|
-
/**
|
|
82
|
+
/**
|
|
83
|
+
* Update the title of an existing tab.
|
|
84
|
+
* Supported for tabs that are immediate children of this container.
|
|
85
|
+
* Logs failures quietly on debug if not found.
|
|
86
|
+
* */
|
|
80
87
|
setTabTitle(tabId: string, title: ReactNode): void;
|
|
88
|
+
/** Find a tab that is an immediate child of this container. */
|
|
81
89
|
findTab(id: string): TabModel;
|
|
82
90
|
get activeTab(): TabModel;
|
|
83
91
|
/** The tab immediately before the active tab in the model's tab list. */
|
|
@@ -88,9 +96,11 @@ export declare class TabContainerModel extends HoistModel implements Persistable
|
|
|
88
96
|
* Set the currently active Tab.
|
|
89
97
|
*
|
|
90
98
|
* If using routing, this method will navigate to the new tab via the router and the active Tab
|
|
91
|
-
* will only be updated once the router state changes. Otherwise the active Tab will be updated
|
|
99
|
+
* will only be updated once the router state changes. Otherwise, the active Tab will be updated
|
|
92
100
|
* immediately.
|
|
93
101
|
*
|
|
102
|
+
* Supported for tabs that are immediate children of this container.
|
|
103
|
+
*
|
|
94
104
|
* @param tab - TabModel or id of TabModel to be activated.
|
|
95
105
|
*/
|
|
96
106
|
activateTab(tab: TabModel | string): void;
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
import { HoistModel, RefreshMode, RenderMode, Content, RefreshContextModel, Thunkable } from '@xh/hoist/core';
|
|
2
|
-
import { TabContainerModel } from '@xh/hoist/cmp/tab
|
|
2
|
+
import { TabContainerConfig, TabContainerModel } from '@xh/hoist/cmp/tab';
|
|
3
3
|
import { ReactElement, ReactNode } from 'react';
|
|
4
4
|
export interface TabConfig {
|
|
5
5
|
/** Unique ID, used by container for locating tabs and generating routes. */
|
|
6
6
|
id: string;
|
|
7
|
-
/**
|
|
8
|
-
* Parent TabContainerModel. Provided by the container when constructing these models -
|
|
9
|
-
* no need for application to specify directly.
|
|
10
|
-
*/
|
|
11
|
-
containerModel?: TabContainerModel;
|
|
12
7
|
/** Display title for the Tab in the container's TabSwitcher. */
|
|
13
8
|
title?: ReactNode;
|
|
14
9
|
/** Display icon for the Tab in the container's TabSwitcher. */
|
|
@@ -24,8 +19,10 @@ export interface TabConfig {
|
|
|
24
19
|
excludeFromSwitcher?: boolean;
|
|
25
20
|
/** Display an affordance to allow the user to remove this tab from its container.*/
|
|
26
21
|
showRemoveAction?: boolean;
|
|
27
|
-
/**
|
|
28
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Item to be rendered by this tab, or specification for a child tab container for this tab.
|
|
24
|
+
*/
|
|
25
|
+
content?: Content | TabConfig[] | TabContainerConfig;
|
|
29
26
|
/**
|
|
30
27
|
* Strategy for rendering this tab. If null, will default to its container's mode. See enum
|
|
31
28
|
* for description of supported modes.
|
|
@@ -57,15 +54,18 @@ export declare class TabModel extends HoistModel {
|
|
|
57
54
|
excludeFromSwitcher: boolean;
|
|
58
55
|
showRemoveAction: boolean;
|
|
59
56
|
content: Content;
|
|
60
|
-
private _renderMode;
|
|
61
|
-
private _refreshMode;
|
|
62
57
|
containerModel: TabContainerModel;
|
|
63
58
|
refreshContextModel: RefreshContextModel;
|
|
59
|
+
/** Child TabContainerModel. For nested TabContainers only. */
|
|
60
|
+
childContainerModel: TabContainerModel;
|
|
61
|
+
private _renderMode;
|
|
62
|
+
private _refreshMode;
|
|
64
63
|
get isTabModel(): boolean;
|
|
65
|
-
constructor({ id,
|
|
64
|
+
constructor({ id, title, icon, tooltip, disabled, excludeFromSwitcher, showRemoveAction, content, refreshMode, renderMode, xhImpl }: TabConfig, containerModel: TabContainerModel);
|
|
66
65
|
activate(): void;
|
|
67
66
|
get renderMode(): RenderMode;
|
|
68
67
|
get refreshMode(): RefreshMode;
|
|
69
68
|
get isActive(): boolean;
|
|
70
69
|
setDisabled(disabled: boolean): void;
|
|
70
|
+
private parseContent;
|
|
71
71
|
}
|
package/cmp/grid/GridModel.ts
CHANGED
|
@@ -1066,7 +1066,7 @@ export class GridModel extends HoistModel {
|
|
|
1066
1066
|
const {maxDepth, levelLabels} = this,
|
|
1067
1067
|
ret = executeIfFunction(levelLabels);
|
|
1068
1068
|
if (ret && ret.length < maxDepth + 1) {
|
|
1069
|
-
this.
|
|
1069
|
+
this.logDebug('Value produced by `GridModel.levelLabels` has insufficient length.');
|
|
1070
1070
|
return null;
|
|
1071
1071
|
}
|
|
1072
1072
|
return ret ? take(ret, maxDepth + 1) : null;
|
|
@@ -27,7 +27,7 @@ import {TabSwitcherProps} from './TabSwitcherProps';
|
|
|
27
27
|
|
|
28
28
|
export interface TabContainerConfig {
|
|
29
29
|
/** Tabs to be displayed. */
|
|
30
|
-
tabs
|
|
30
|
+
tabs: TabConfig[];
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* ID of Tab to be shown initially if routing does not specify otherwise. If not set,
|
|
@@ -157,13 +157,14 @@ export class TabContainerModel extends HoistModel implements Persistable<{active
|
|
|
157
157
|
|
|
158
158
|
this.forwardRouterToTab(this.activeTabId);
|
|
159
159
|
} else if (persistWith) {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
160
|
+
((this.persistWith = {
|
|
161
|
+
path: 'tabContainer',
|
|
162
|
+
...persistWith
|
|
163
|
+
}),
|
|
164
|
+
PersistenceProvider.create({
|
|
165
|
+
persistOptions: this.persistWith,
|
|
166
|
+
target: this
|
|
167
|
+
}));
|
|
167
168
|
}
|
|
168
169
|
|
|
169
170
|
if (track) {
|
|
@@ -202,13 +203,7 @@ export class TabContainerModel extends HoistModel implements Persistable<{active
|
|
|
202
203
|
this.activeTabId = this.calculateActiveTabId(tabs);
|
|
203
204
|
}
|
|
204
205
|
this.tabs = tabs.map(t =>
|
|
205
|
-
t instanceof TabModel
|
|
206
|
-
? t
|
|
207
|
-
: new TabModel({
|
|
208
|
-
...t,
|
|
209
|
-
containerModel: this,
|
|
210
|
-
xhImpl: this.xhImpl
|
|
211
|
-
})
|
|
206
|
+
t instanceof TabModel ? t : new TabModel({...t, xhImpl: this.xhImpl}, this)
|
|
212
207
|
);
|
|
213
208
|
|
|
214
209
|
if (oldTabs) {
|
|
@@ -228,7 +223,10 @@ export class TabContainerModel extends HoistModel implements Persistable<{active
|
|
|
228
223
|
return this.findTab(tab.id);
|
|
229
224
|
}
|
|
230
225
|
|
|
231
|
-
/**
|
|
226
|
+
/**
|
|
227
|
+
* Remove a single tab from the container.
|
|
228
|
+
* Supported for tabs that are immediate children of this container.
|
|
229
|
+
**/
|
|
232
230
|
@action
|
|
233
231
|
removeTab(tab: TabModel | string) {
|
|
234
232
|
const {tabs, activeTab} = this,
|
|
@@ -250,16 +248,19 @@ export class TabContainerModel extends HoistModel implements Persistable<{active
|
|
|
250
248
|
this.setTabs(without(tabs, toRemove));
|
|
251
249
|
}
|
|
252
250
|
|
|
253
|
-
/**
|
|
251
|
+
/**
|
|
252
|
+
* Update the title of an existing tab.
|
|
253
|
+
* Supported for tabs that are immediate children of this container.
|
|
254
|
+
* Logs failures quietly on debug if not found.
|
|
255
|
+
* */
|
|
254
256
|
setTabTitle(tabId: string, title: ReactNode) {
|
|
255
257
|
const tab = this.findTab(tabId);
|
|
256
258
|
if (tab) {
|
|
257
259
|
tab.title = title;
|
|
258
|
-
} else {
|
|
259
|
-
this.logDebug(`Failed to setTabTitle`, `Tab ${tabId} not found`);
|
|
260
260
|
}
|
|
261
261
|
}
|
|
262
262
|
|
|
263
|
+
/** Find a tab that is an immediate child of this container. */
|
|
263
264
|
findTab(id: string): TabModel {
|
|
264
265
|
return find(this.tabs, {id});
|
|
265
266
|
}
|
|
@@ -284,9 +285,11 @@ export class TabContainerModel extends HoistModel implements Persistable<{active
|
|
|
284
285
|
* Set the currently active Tab.
|
|
285
286
|
*
|
|
286
287
|
* If using routing, this method will navigate to the new tab via the router and the active Tab
|
|
287
|
-
* will only be updated once the router state changes. Otherwise the active Tab will be updated
|
|
288
|
+
* will only be updated once the router state changes. Otherwise, the active Tab will be updated
|
|
288
289
|
* immediately.
|
|
289
290
|
*
|
|
291
|
+
* Supported for tabs that are immediate children of this container.
|
|
292
|
+
*
|
|
290
293
|
* @param tab - TabModel or id of TabModel to be activated.
|
|
291
294
|
*/
|
|
292
295
|
activateTab(tab: TabModel | string) {
|
package/cmp/tab/TabModel.ts
CHANGED
|
@@ -17,20 +17,14 @@ import {
|
|
|
17
17
|
} from '@xh/hoist/core';
|
|
18
18
|
import {action, computed, observable, makeObservable, bindable} from '@xh/hoist/mobx';
|
|
19
19
|
import {throwIf} from '@xh/hoist/utils/js';
|
|
20
|
-
import {startCase} from 'lodash';
|
|
21
|
-
import {TabContainerModel} from '@xh/hoist/cmp/tab
|
|
20
|
+
import {isArray, isUndefined, startCase} from 'lodash';
|
|
21
|
+
import {TabContainerConfig, TabContainerModel, tabContainer} from '@xh/hoist/cmp/tab';
|
|
22
22
|
import {ReactElement, ReactNode} from 'react';
|
|
23
23
|
|
|
24
24
|
export interface TabConfig {
|
|
25
25
|
/** Unique ID, used by container for locating tabs and generating routes. */
|
|
26
26
|
id: string;
|
|
27
27
|
|
|
28
|
-
/**
|
|
29
|
-
* Parent TabContainerModel. Provided by the container when constructing these models -
|
|
30
|
-
* no need for application to specify directly.
|
|
31
|
-
*/
|
|
32
|
-
containerModel?: TabContainerModel;
|
|
33
|
-
|
|
34
28
|
/** Display title for the Tab in the container's TabSwitcher. */
|
|
35
29
|
title?: ReactNode;
|
|
36
30
|
|
|
@@ -52,8 +46,10 @@ export interface TabConfig {
|
|
|
52
46
|
/** Display an affordance to allow the user to remove this tab from its container.*/
|
|
53
47
|
showRemoveAction?: boolean;
|
|
54
48
|
|
|
55
|
-
/**
|
|
56
|
-
|
|
49
|
+
/**
|
|
50
|
+
* Item to be rendered by this tab, or specification for a child tab container for this tab.
|
|
51
|
+
*/
|
|
52
|
+
content?: Content | TabConfig[] | TabContainerConfig;
|
|
57
53
|
|
|
58
54
|
/**
|
|
59
55
|
* Strategy for rendering this tab. If null, will default to its container's mode. See enum
|
|
@@ -91,30 +87,35 @@ export class TabModel extends HoistModel {
|
|
|
91
87
|
showRemoveAction: boolean;
|
|
92
88
|
content: Content;
|
|
93
89
|
|
|
94
|
-
private _renderMode: RenderMode;
|
|
95
|
-
private _refreshMode: RefreshMode;
|
|
96
|
-
|
|
97
90
|
containerModel: TabContainerModel;
|
|
98
91
|
@managed refreshContextModel: RefreshContextModel;
|
|
99
92
|
|
|
93
|
+
/** Child TabContainerModel. For nested TabContainers only. */
|
|
94
|
+
@managed childContainerModel: TabContainerModel;
|
|
95
|
+
|
|
96
|
+
private _renderMode: RenderMode;
|
|
97
|
+
private _refreshMode: RefreshMode;
|
|
98
|
+
|
|
100
99
|
get isTabModel() {
|
|
101
100
|
return true;
|
|
102
101
|
}
|
|
103
102
|
|
|
104
|
-
constructor(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
103
|
+
constructor(
|
|
104
|
+
{
|
|
105
|
+
id,
|
|
106
|
+
title = startCase(id),
|
|
107
|
+
icon = null,
|
|
108
|
+
tooltip = null,
|
|
109
|
+
disabled = false,
|
|
110
|
+
excludeFromSwitcher = false,
|
|
111
|
+
showRemoveAction = false,
|
|
112
|
+
content,
|
|
113
|
+
refreshMode,
|
|
114
|
+
renderMode,
|
|
115
|
+
xhImpl = false
|
|
116
|
+
}: TabConfig,
|
|
117
|
+
containerModel: TabContainerModel
|
|
118
|
+
) {
|
|
118
119
|
super();
|
|
119
120
|
makeObservable(this);
|
|
120
121
|
this.xhImpl = xhImpl;
|
|
@@ -125,20 +126,18 @@ export class TabModel extends HoistModel {
|
|
|
125
126
|
);
|
|
126
127
|
|
|
127
128
|
this.id = id.toString();
|
|
128
|
-
this.containerModel = containerModel;
|
|
129
129
|
this.title = title;
|
|
130
130
|
this.icon = icon;
|
|
131
131
|
this.tooltip = tooltip;
|
|
132
132
|
this.disabled = !!disabled;
|
|
133
133
|
this.excludeFromSwitcher = excludeFromSwitcher;
|
|
134
134
|
this.showRemoveAction = showRemoveAction;
|
|
135
|
-
this.
|
|
136
|
-
|
|
135
|
+
this.containerModel = containerModel;
|
|
137
136
|
this._renderMode = renderMode;
|
|
138
137
|
this._refreshMode = refreshMode;
|
|
139
|
-
|
|
140
138
|
this.refreshContextModel = new ManagedRefreshContextModel(this);
|
|
141
139
|
this.refreshContextModel.xhImpl = true;
|
|
140
|
+
this.content = this.parseContent(content);
|
|
142
141
|
}
|
|
143
142
|
|
|
144
143
|
activate() {
|
|
@@ -170,4 +169,47 @@ export class TabModel extends HoistModel {
|
|
|
170
169
|
|
|
171
170
|
this.disabled = disabled;
|
|
172
171
|
}
|
|
172
|
+
|
|
173
|
+
//------------------
|
|
174
|
+
// Implementation
|
|
175
|
+
//------------------
|
|
176
|
+
private parseContent(content: Content | TabContainerConfig | TabConfig[]): Content {
|
|
177
|
+
// Recognize if content is a child container spec.
|
|
178
|
+
let childConfig: TabContainerConfig = null;
|
|
179
|
+
if (isArray(content)) {
|
|
180
|
+
childConfig = {tabs: content};
|
|
181
|
+
} else if ('tabs' in content) {
|
|
182
|
+
childConfig = content;
|
|
183
|
+
} else {
|
|
184
|
+
// ...otherwise just pass through
|
|
185
|
+
return content;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// It's a child container, create model and return
|
|
189
|
+
throwIf(XH.isMobileApp, 'Child Tabs not supported for Mobile TabContainer');
|
|
190
|
+
const {id} = this,
|
|
191
|
+
parent = this.containerModel;
|
|
192
|
+
|
|
193
|
+
childConfig = {
|
|
194
|
+
renderMode: parent.renderMode,
|
|
195
|
+
refreshMode: parent.refreshMode,
|
|
196
|
+
emptyText: parent.emptyText,
|
|
197
|
+
switcher: parent.switcher,
|
|
198
|
+
track: parent.track,
|
|
199
|
+
...childConfig
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
// Trampoline nested routing OR persistence (TCM supports one or the other)
|
|
203
|
+
if (parent.route && !childConfig.route) {
|
|
204
|
+
childConfig.route = `${parent.route}.${id}`;
|
|
205
|
+
} else if (parent.persistWith && isUndefined(childConfig.persistWith)) {
|
|
206
|
+
childConfig.persistWith = {
|
|
207
|
+
...parent.persistWith,
|
|
208
|
+
path: `${parent.persistWith.path}.${id}`
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
this.childContainerModel = new TabContainerModel(childConfig);
|
|
213
|
+
return tabContainer({model: this.childContainerModel});
|
|
214
|
+
}
|
|
173
215
|
}
|
|
@@ -27,7 +27,7 @@ export const tab = hoistCmp.factory({
|
|
|
27
27
|
model: uses(TabModel, {publishMode: 'limited'}),
|
|
28
28
|
|
|
29
29
|
render({model, className, testId}) {
|
|
30
|
-
|
|
30
|
+
const {content, isActive, renderMode, refreshContextModel} = model,
|
|
31
31
|
wasActivated = useRef(false);
|
|
32
32
|
|
|
33
33
|
if (!wasActivated.current && isActive) wasActivated.current = true;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xh/hoist",
|
|
3
|
-
"version": "76.0.0-SNAPSHOT.
|
|
3
|
+
"version": "76.0.0-SNAPSHOT.1757113228632",
|
|
4
4
|
"description": "Hoist add-on for building and deploying React Applications.",
|
|
5
5
|
"repository": "github:xh/hoist-react",
|
|
6
6
|
"homepage": "https://xh.io",
|