@abpjs/setting-management 0.9.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.
- package/LICENSE +165 -0
- package/README.md +287 -0
- package/dist/index.d.mts +191 -0
- package/dist/index.d.ts +191 -0
- package/dist/index.js +318 -0
- package/dist/index.mjs +287 -0
- package/package.json +86 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
// src/constants/routes.ts
|
|
2
|
+
var SETTING_MANAGEMENT_ROUTES = {
|
|
3
|
+
routes: [
|
|
4
|
+
{
|
|
5
|
+
name: "Settings",
|
|
6
|
+
path: "setting-management",
|
|
7
|
+
layout: "application",
|
|
8
|
+
order: 100
|
|
9
|
+
}
|
|
10
|
+
]
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// src/services/setting-management.service.ts
|
|
14
|
+
var SettingManagementService = class {
|
|
15
|
+
constructor() {
|
|
16
|
+
this._settings = [];
|
|
17
|
+
this._selected = null;
|
|
18
|
+
this._subscribers = /* @__PURE__ */ new Set();
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Get all registered settings tabs sorted by order
|
|
22
|
+
*/
|
|
23
|
+
get settings() {
|
|
24
|
+
return [...this._settings].sort((a, b) => a.order - b.order);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Get the currently selected setting tab
|
|
28
|
+
*/
|
|
29
|
+
get selected() {
|
|
30
|
+
return this._selected;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Register a new setting tab
|
|
34
|
+
* @param tab The setting tab to register
|
|
35
|
+
*/
|
|
36
|
+
addSetting(tab) {
|
|
37
|
+
const exists = this._settings.some((s) => s.name === tab.name);
|
|
38
|
+
if (!exists) {
|
|
39
|
+
this._settings.push(tab);
|
|
40
|
+
this.notifySubscribers();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Register multiple setting tabs at once
|
|
45
|
+
* @param tabs Array of setting tabs to register
|
|
46
|
+
*/
|
|
47
|
+
addSettings(tabs) {
|
|
48
|
+
let changed = false;
|
|
49
|
+
for (const tab of tabs) {
|
|
50
|
+
const exists = this._settings.some((s) => s.name === tab.name);
|
|
51
|
+
if (!exists) {
|
|
52
|
+
this._settings.push(tab);
|
|
53
|
+
changed = true;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (changed) {
|
|
57
|
+
this.notifySubscribers();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Remove a setting tab by name
|
|
62
|
+
* @param name The name of the setting tab to remove
|
|
63
|
+
*/
|
|
64
|
+
removeSetting(name) {
|
|
65
|
+
const index = this._settings.findIndex((s) => s.name === name);
|
|
66
|
+
if (index !== -1) {
|
|
67
|
+
this._settings.splice(index, 1);
|
|
68
|
+
if (this._selected?.name === name) {
|
|
69
|
+
this._selected = null;
|
|
70
|
+
}
|
|
71
|
+
this.notifySubscribers();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Set the currently selected setting tab
|
|
76
|
+
* @param tab The tab to select (or null to clear selection)
|
|
77
|
+
*/
|
|
78
|
+
setSelected(tab) {
|
|
79
|
+
this._selected = tab;
|
|
80
|
+
this.notifySubscribers();
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Select a setting tab by name
|
|
84
|
+
* @param name The name of the tab to select
|
|
85
|
+
*/
|
|
86
|
+
selectByName(name) {
|
|
87
|
+
const tab = this._settings.find((s) => s.name === name);
|
|
88
|
+
if (tab) {
|
|
89
|
+
this.setSelected(tab);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Select a setting tab by URL
|
|
94
|
+
* @param url The URL of the tab to select
|
|
95
|
+
*/
|
|
96
|
+
selectByUrl(url) {
|
|
97
|
+
const tab = this._settings.find((s) => s.url === url);
|
|
98
|
+
if (tab) {
|
|
99
|
+
this.setSelected(tab);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Clear all registered settings
|
|
104
|
+
*/
|
|
105
|
+
clearSettings() {
|
|
106
|
+
this._settings = [];
|
|
107
|
+
this._selected = null;
|
|
108
|
+
this.notifySubscribers();
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Subscribe to changes in settings or selection
|
|
112
|
+
* @param callback Function to call when changes occur
|
|
113
|
+
* @returns Unsubscribe function
|
|
114
|
+
*/
|
|
115
|
+
subscribe(callback) {
|
|
116
|
+
this._subscribers.add(callback);
|
|
117
|
+
return () => {
|
|
118
|
+
this._subscribers.delete(callback);
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
notifySubscribers() {
|
|
122
|
+
this._subscribers.forEach((callback) => callback());
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
var _instance = null;
|
|
126
|
+
function getSettingManagementService() {
|
|
127
|
+
if (!_instance) {
|
|
128
|
+
_instance = new SettingManagementService();
|
|
129
|
+
}
|
|
130
|
+
return _instance;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// src/hooks/useSettingManagement.ts
|
|
134
|
+
import { useState, useEffect, useCallback, useMemo } from "react";
|
|
135
|
+
function useSettingManagement() {
|
|
136
|
+
const service = useMemo(() => getSettingManagementService(), []);
|
|
137
|
+
const [, forceUpdate] = useState({});
|
|
138
|
+
useEffect(() => {
|
|
139
|
+
const unsubscribe = service.subscribe(() => {
|
|
140
|
+
forceUpdate({});
|
|
141
|
+
});
|
|
142
|
+
return unsubscribe;
|
|
143
|
+
}, [service]);
|
|
144
|
+
const addSetting = useCallback(
|
|
145
|
+
(tab) => {
|
|
146
|
+
service.addSetting(tab);
|
|
147
|
+
},
|
|
148
|
+
[service]
|
|
149
|
+
);
|
|
150
|
+
const addSettings = useCallback(
|
|
151
|
+
(tabs) => {
|
|
152
|
+
service.addSettings(tabs);
|
|
153
|
+
},
|
|
154
|
+
[service]
|
|
155
|
+
);
|
|
156
|
+
const removeSetting = useCallback(
|
|
157
|
+
(name) => {
|
|
158
|
+
service.removeSetting(name);
|
|
159
|
+
},
|
|
160
|
+
[service]
|
|
161
|
+
);
|
|
162
|
+
const setSelected = useCallback(
|
|
163
|
+
(tab) => {
|
|
164
|
+
service.setSelected(tab);
|
|
165
|
+
},
|
|
166
|
+
[service]
|
|
167
|
+
);
|
|
168
|
+
const selectByName = useCallback(
|
|
169
|
+
(name) => {
|
|
170
|
+
service.selectByName(name);
|
|
171
|
+
},
|
|
172
|
+
[service]
|
|
173
|
+
);
|
|
174
|
+
const selectByUrl = useCallback(
|
|
175
|
+
(url) => {
|
|
176
|
+
service.selectByUrl(url);
|
|
177
|
+
},
|
|
178
|
+
[service]
|
|
179
|
+
);
|
|
180
|
+
const clearSettings = useCallback(() => {
|
|
181
|
+
service.clearSettings();
|
|
182
|
+
}, [service]);
|
|
183
|
+
return {
|
|
184
|
+
settings: service.settings,
|
|
185
|
+
selected: service.selected,
|
|
186
|
+
addSetting,
|
|
187
|
+
addSettings,
|
|
188
|
+
removeSetting,
|
|
189
|
+
setSelected,
|
|
190
|
+
selectByName,
|
|
191
|
+
selectByUrl,
|
|
192
|
+
clearSettings
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// src/components/SettingLayout/SettingLayout.tsx
|
|
197
|
+
import { useEffect as useEffect2 } from "react";
|
|
198
|
+
import { useLocation, useNavigate } from "react-router-dom";
|
|
199
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
200
|
+
function SettingLayout({
|
|
201
|
+
children,
|
|
202
|
+
onTabSelect,
|
|
203
|
+
className = ""
|
|
204
|
+
}) {
|
|
205
|
+
const { settings, selected, setSelected } = useSettingManagement();
|
|
206
|
+
const location = useLocation();
|
|
207
|
+
const navigate = useNavigate();
|
|
208
|
+
useEffect2(() => {
|
|
209
|
+
if (settings.length > 0) {
|
|
210
|
+
const matchingTab = settings.find((tab) => tab.url && location.pathname.startsWith(tab.url));
|
|
211
|
+
if (matchingTab) {
|
|
212
|
+
setSelected(matchingTab);
|
|
213
|
+
} else if (!selected && settings.length > 0) {
|
|
214
|
+
setSelected(settings[0]);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}, [location.pathname, settings, selected, setSelected]);
|
|
218
|
+
const handleTabClick = (tab) => {
|
|
219
|
+
setSelected(tab);
|
|
220
|
+
onTabSelect?.(tab);
|
|
221
|
+
if (tab.url) {
|
|
222
|
+
navigate(tab.url);
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
return /* @__PURE__ */ jsxs("div", { className: `setting-layout ${className}`, style: styles.container, children: [
|
|
226
|
+
/* @__PURE__ */ jsx("div", { className: "setting-layout-sidebar", style: styles.sidebar, children: /* @__PURE__ */ jsx("nav", { className: "setting-tabs", style: styles.nav, children: settings.map((tab) => /* @__PURE__ */ jsx(
|
|
227
|
+
"button",
|
|
228
|
+
{
|
|
229
|
+
type: "button",
|
|
230
|
+
onClick: () => handleTabClick(tab),
|
|
231
|
+
className: `setting-tab ${selected?.name === tab.name ? "active" : ""}`,
|
|
232
|
+
style: {
|
|
233
|
+
...styles.tabButton,
|
|
234
|
+
...selected?.name === tab.name ? styles.tabButtonActive : {}
|
|
235
|
+
},
|
|
236
|
+
children: tab.name
|
|
237
|
+
},
|
|
238
|
+
tab.name
|
|
239
|
+
)) }) }),
|
|
240
|
+
/* @__PURE__ */ jsx("div", { className: "setting-layout-content", style: styles.content, children })
|
|
241
|
+
] });
|
|
242
|
+
}
|
|
243
|
+
var styles = {
|
|
244
|
+
container: {
|
|
245
|
+
display: "flex",
|
|
246
|
+
minHeight: "400px",
|
|
247
|
+
gap: "24px"
|
|
248
|
+
},
|
|
249
|
+
sidebar: {
|
|
250
|
+
width: "240px",
|
|
251
|
+
flexShrink: 0
|
|
252
|
+
},
|
|
253
|
+
nav: {
|
|
254
|
+
display: "flex",
|
|
255
|
+
flexDirection: "column",
|
|
256
|
+
gap: "4px"
|
|
257
|
+
},
|
|
258
|
+
tabButton: {
|
|
259
|
+
display: "block",
|
|
260
|
+
width: "100%",
|
|
261
|
+
padding: "12px 16px",
|
|
262
|
+
textAlign: "left",
|
|
263
|
+
border: "none",
|
|
264
|
+
borderRadius: "6px",
|
|
265
|
+
background: "transparent",
|
|
266
|
+
cursor: "pointer",
|
|
267
|
+
fontSize: "14px",
|
|
268
|
+
color: "inherit",
|
|
269
|
+
transition: "background-color 0.2s"
|
|
270
|
+
},
|
|
271
|
+
tabButtonActive: {
|
|
272
|
+
backgroundColor: "rgba(59, 130, 246, 0.1)",
|
|
273
|
+
color: "#3b82f6",
|
|
274
|
+
fontWeight: 500
|
|
275
|
+
},
|
|
276
|
+
content: {
|
|
277
|
+
flex: 1,
|
|
278
|
+
minWidth: 0
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
export {
|
|
282
|
+
SETTING_MANAGEMENT_ROUTES,
|
|
283
|
+
SettingLayout,
|
|
284
|
+
SettingManagementService,
|
|
285
|
+
getSettingManagementService,
|
|
286
|
+
useSettingManagement
|
|
287
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@abpjs/setting-management",
|
|
3
|
+
"version": "0.9.0",
|
|
4
|
+
"description": "ABP Framework setting-management components for React - translated from @abp/ng.setting-management",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"keywords": [
|
|
20
|
+
"abp",
|
|
21
|
+
"react",
|
|
22
|
+
"framework",
|
|
23
|
+
"setting-management"
|
|
24
|
+
],
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@chakra-ui/react": "^3.2.0",
|
|
27
|
+
"@emotion/react": "^11.11.0",
|
|
28
|
+
"@abpjs/core": "0.9.0",
|
|
29
|
+
"@abpjs/theme-shared": "0.9.0",
|
|
30
|
+
"@abpjs/permission-management": "0.9.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@abp/ng.setting-management": "0.9.0",
|
|
34
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
35
|
+
"@testing-library/react": "^14.0.0",
|
|
36
|
+
"@testing-library/user-event": "^14.6.1",
|
|
37
|
+
"@types/react": "^18.2.0",
|
|
38
|
+
"@types/react-dom": "^18.2.0",
|
|
39
|
+
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
|
40
|
+
"@typescript-eslint/parser": "^6.0.0",
|
|
41
|
+
"autoprefixer": "^10.4.16",
|
|
42
|
+
"eslint": "^8.0.0",
|
|
43
|
+
"eslint-config-prettier": "^9.1.2",
|
|
44
|
+
"eslint-plugin-react": "^7.0.0",
|
|
45
|
+
"eslint-plugin-react-hooks": "^4.0.0",
|
|
46
|
+
"jsdom": "^24.0.0",
|
|
47
|
+
"postcss": "^8.4.32",
|
|
48
|
+
"prettier": "^3.7.4",
|
|
49
|
+
"react": "^18.2.0",
|
|
50
|
+
"react-dom": "^18.2.0",
|
|
51
|
+
"react-router-dom": "^6.20.0",
|
|
52
|
+
"tailwindcss": "^3.4.0",
|
|
53
|
+
"tsup": "^8.0.0",
|
|
54
|
+
"typescript": "^5.0.0",
|
|
55
|
+
"vitest": "^1.0.0",
|
|
56
|
+
"@vitest/coverage-v8": "^1.0.0"
|
|
57
|
+
},
|
|
58
|
+
"author": "tekthar.com",
|
|
59
|
+
"license": "LGPL-3.0",
|
|
60
|
+
"publishConfig": {
|
|
61
|
+
"access": "public"
|
|
62
|
+
},
|
|
63
|
+
"repository": {
|
|
64
|
+
"type": "git",
|
|
65
|
+
"url": "https://github.com/abpjs/abp-react"
|
|
66
|
+
},
|
|
67
|
+
"homepage": "https://docs.abpjs.io/docs/packages/setting-management/overview",
|
|
68
|
+
"bugs": {
|
|
69
|
+
"url": "https://github.com/abpjs/abp-react/issues"
|
|
70
|
+
},
|
|
71
|
+
"peerDependencies": {
|
|
72
|
+
"react": ">=17.0.0",
|
|
73
|
+
"react-dom": ">=17.0.0",
|
|
74
|
+
"react-router-dom": ">=6.0.0"
|
|
75
|
+
},
|
|
76
|
+
"scripts": {
|
|
77
|
+
"build": "tsup",
|
|
78
|
+
"dev": "tsup src/index.ts --format cjs,esm --watch",
|
|
79
|
+
"lint": "eslint src",
|
|
80
|
+
"lint:fix": "eslint src --fix",
|
|
81
|
+
"format": "prettier --write \"src/**/*.{ts,tsx,json,md}\"",
|
|
82
|
+
"format:check": "prettier --check \"src/**/*.{ts,tsx,json,md}\"",
|
|
83
|
+
"type-check": "tsc --noEmit",
|
|
84
|
+
"test": "vitest"
|
|
85
|
+
}
|
|
86
|
+
}
|