ui-soxo-bootstrap-core 2.6.40-dev.11 → 2.6.40-dev.12
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/PUBLISHING.md
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
# Publishing `ui-soxo-bootstrap-core` to npm
|
|
2
|
+
|
|
3
|
+
Complete guide for developers.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Table of contents
|
|
8
|
+
|
|
9
|
+
1. [Quick reference](#quick-reference)
|
|
10
|
+
2. [Branch & version strategy](#branch--version-strategy)
|
|
11
|
+
3. [`npm version` keys explained](#npm-version-keys-explained)
|
|
12
|
+
4. [Publishing a dev pre-release (from `develop`)](#publishing-a-dev-pre-release-from-develop)
|
|
13
|
+
5. [Publishing a stable release (from `master`)](#publishing-a-stable-release-from-master)
|
|
14
|
+
6. [Verifying & installing](#verifying--installing)
|
|
15
|
+
7. [Rules & dos / don'ts](#rules--dos--donts)
|
|
16
|
+
8. [How auth works](#how-auth-works)
|
|
17
|
+
9. [Troubleshooting](#troubleshooting)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Quick reference
|
|
22
|
+
|
|
23
|
+
| Branch | Version format | npm dist-tag | Example | Who installs |
|
|
24
|
+
| --------- | ----------------- | ------------ | ---------------- | ------------------------------------- |
|
|
25
|
+
| `develop` | `X.Y.Z-dev.N` | `dev` | `2.6.40-dev.11` | Devs testing pre-releases |
|
|
26
|
+
| `master` | `X.Y.Z` | `latest` | `2.6.40` | Default install for everyone |
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Branch & version strategy
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
feature branches ──► develop ──► master
|
|
34
|
+
(dev tag) (latest tag)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
- All day-to-day work merges into `develop`.
|
|
38
|
+
- Each meaningful commit on `develop` can be published as a `-dev.N` pre-release for QA / integration testing.
|
|
39
|
+
- When the code is ready for production, **merge `develop` → `master`**, then bump and tag a stable version on `master`.
|
|
40
|
+
- `master` is the source of `latest` on npm. End users get this by default.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## `npm version` keys explained
|
|
45
|
+
|
|
46
|
+
`npm version <key>` bumps `package.json`, creates a commit, **and** creates a git tag in one shot. Use it instead of editing `package.json` by hand.
|
|
47
|
+
|
|
48
|
+
### Stable bumps (use on `master`)
|
|
49
|
+
|
|
50
|
+
| Key | From | To | When to use |
|
|
51
|
+
| --------- | ------- | -------- | ------------------------------------------------- |
|
|
52
|
+
| `patch` | 2.6.40 | 2.6.41 | Bug fixes only, no API change |
|
|
53
|
+
| `minor` | 2.6.40 | 2.7.0 | New features, backwards-compatible |
|
|
54
|
+
| `major` | 2.6.40 | 3.0.0 | Breaking changes (consumers must update code) |
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
npm version patch # → 2.6.41
|
|
58
|
+
npm version minor # → 2.7.0
|
|
59
|
+
npm version major # → 3.0.0
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Pre-release bumps (use on `develop`)
|
|
63
|
+
|
|
64
|
+
| Key | From | To | When to use |
|
|
65
|
+
| ---------------------------------- | --------------- | ------------------- | ------------------------------------------- |
|
|
66
|
+
| `prerelease --preid=dev` | 2.6.40-dev.10 | 2.6.40-dev.11 | Another iteration of the current pre-release |
|
|
67
|
+
| `prepatch --preid=dev` | 2.6.40 | 2.6.41-dev.0 | Start pre-releases for the next patch |
|
|
68
|
+
| `preminor --preid=dev` | 2.6.40 | 2.7.0-dev.0 | Start pre-releases for the next minor |
|
|
69
|
+
| `premajor --preid=dev` | 2.6.40 | 3.0.0-dev.0 | Start pre-releases for the next major |
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npm version prerelease --preid=dev # → 2.6.40-dev.11 (most common on develop)
|
|
73
|
+
npm version preminor --preid=dev # → 2.7.0-dev.0 (kick off next minor cycle)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Explicit version
|
|
77
|
+
|
|
78
|
+
If you know the exact string you want:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
npm version 2.6.40-dev.12
|
|
82
|
+
npm version 2.7.0
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Useful flags
|
|
86
|
+
|
|
87
|
+
| Flag | Effect |
|
|
88
|
+
| --------------------- | -------------------------------------------------------------- |
|
|
89
|
+
| `--no-git-tag-version` | Bump `package.json` only — no commit, no tag (rarely needed) |
|
|
90
|
+
| `-m "Release %s"` | Custom commit message; `%s` is replaced with the new version |
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Publishing a dev pre-release (from `develop`)
|
|
95
|
+
|
|
96
|
+
Use this for every internal QA / integration build.
|
|
97
|
+
|
|
98
|
+
### Step 1 — Make sure `develop` is up to date
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
git checkout develop
|
|
102
|
+
git pull
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Step 2 — Bump the version
|
|
106
|
+
|
|
107
|
+
Pick **one**:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
# Common case: next dev iteration of current version
|
|
111
|
+
npm version prerelease --preid=dev
|
|
112
|
+
# Example: 2.6.40-dev.10 → 2.6.40-dev.11
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
# Starting a new patch/minor/major cycle
|
|
117
|
+
npm version preminor --preid=dev
|
|
118
|
+
# Example: 2.6.40 → 2.7.0-dev.0
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
# Or explicit
|
|
123
|
+
npm version 2.6.40-dev.12
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
`npm version` automatically:
|
|
127
|
+
- Updates `package.json`
|
|
128
|
+
- Creates a commit `2.6.40-dev.11`
|
|
129
|
+
- Creates a git tag `v2.6.40-dev.11`
|
|
130
|
+
|
|
131
|
+
### Step 3 — Push commit & tag
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
git push origin develop --follow-tags
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Step 4 — Create a GitHub Release
|
|
138
|
+
|
|
139
|
+
1. Go to https://github.com/soxo-tech/bootstrap-core/releases
|
|
140
|
+
2. Click **Draft a new release**
|
|
141
|
+
3. **Choose a tag** → pick the tag you just pushed (e.g. `v2.6.40-dev.11`)
|
|
142
|
+
4. Title: same as the tag (`v2.6.40-dev.11`)
|
|
143
|
+
5. Description: short summary of what's in this build (optional but recommended)
|
|
144
|
+
6. ✅ Tick **Set as a pre-release** (so it's flagged as not stable)
|
|
145
|
+
7. Click **Publish release**
|
|
146
|
+
|
|
147
|
+
GitHub Actions will run the `npm-publish.yml` workflow and publish to npm with `dist-tag: dev`.
|
|
148
|
+
|
|
149
|
+
### Step 5 — Verify
|
|
150
|
+
|
|
151
|
+
Wait ~1–2 minutes, then:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
npm view ui-soxo-bootstrap-core dist-tags
|
|
155
|
+
# Expect: { latest: '<some stable>', dev: '2.6.40-dev.11' }
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Publishing a stable release (from `master`)
|
|
161
|
+
|
|
162
|
+
Use this when a `develop` snapshot has been QA'd and is ready for production.
|
|
163
|
+
|
|
164
|
+
### Step 1 — Merge `develop` into `master`
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
git checkout master
|
|
168
|
+
git pull
|
|
169
|
+
git merge develop
|
|
170
|
+
git push
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Resolve any conflicts as you normally would. Don't squash unless you have a reason to.
|
|
174
|
+
|
|
175
|
+
### Step 2 — Bump the version on `master`
|
|
176
|
+
|
|
177
|
+
Pick the bump that matches the change scope (relative to the last **stable** version on npm):
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
npm version patch # 2.6.40 → 2.6.41 (bug fixes)
|
|
181
|
+
npm version minor # 2.6.40 → 2.7.0 (new features)
|
|
182
|
+
npm version major # 2.6.40 → 3.0.0 (breaking changes)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
This creates a commit and a tag like `v2.6.41` (no `-dev` suffix).
|
|
186
|
+
|
|
187
|
+
### Step 3 — Push commit & tag
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
git push origin master --follow-tags
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Step 4 — Create a GitHub Release
|
|
194
|
+
|
|
195
|
+
1. Go to https://github.com/soxo-tech/bootstrap-core/releases
|
|
196
|
+
2. **Draft a new release**
|
|
197
|
+
3. **Choose a tag** → pick the stable tag (e.g. `v2.6.41`)
|
|
198
|
+
4. Title: `v2.6.41`
|
|
199
|
+
5. Description: changelog — what's new, what's fixed, any breaking changes
|
|
200
|
+
6. ❌ Do **not** tick "Set as a pre-release"
|
|
201
|
+
7. Click **Publish release**
|
|
202
|
+
|
|
203
|
+
GitHub Actions publishes to npm with `dist-tag: latest`.
|
|
204
|
+
|
|
205
|
+
### Step 5 — Verify
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
npm view ui-soxo-bootstrap-core dist-tags
|
|
209
|
+
# Expect: { latest: '2.6.41', dev: '...' }
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Step 6 (optional but recommended) — Sync `develop`
|
|
213
|
+
|
|
214
|
+
After a stable release, fast-forward `develop` to include the new version commit so the next dev cycle starts from the right place:
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
git checkout develop
|
|
218
|
+
git merge master
|
|
219
|
+
git push
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## Verifying & installing
|
|
225
|
+
|
|
226
|
+
### Check what's published
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
npm view ui-soxo-bootstrap-core dist-tags
|
|
230
|
+
npm view ui-soxo-bootstrap-core versions --json
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Install in another project
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
# Latest stable (from master)
|
|
237
|
+
npm install ui-soxo-bootstrap-core
|
|
238
|
+
|
|
239
|
+
# Latest dev pre-release (from develop)
|
|
240
|
+
npm install ui-soxo-bootstrap-core@dev
|
|
241
|
+
|
|
242
|
+
# Specific version
|
|
243
|
+
npm install ui-soxo-bootstrap-core@2.6.40-dev.11
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## Rules & dos / don'ts
|
|
249
|
+
|
|
250
|
+
| ✅ Do | ❌ Don't |
|
|
251
|
+
| ----------------------------------------------------- | ------------------------------------------------ |
|
|
252
|
+
| Use `npm version` to bump (it tags atomically) | Edit `package.json` version by hand |
|
|
253
|
+
| Tag matches `package.json` exactly | Publish manually from your laptop |
|
|
254
|
+
| `develop` → only `-dev.N` versions | Tag a stable `2.6.40` from `develop` |
|
|
255
|
+
| `master` → only stable versions | Tag a `-dev` version from `master` |
|
|
256
|
+
| Push with `--follow-tags` | Forget to push the tag (Release won't find it) |
|
|
257
|
+
| Create a GitHub Release to trigger publish | Reuse / move existing tags |
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## How auth works
|
|
262
|
+
|
|
263
|
+
Publishing uses **OIDC trusted publishing** — no `NPM_TOKEN` secret to rotate.
|
|
264
|
+
|
|
265
|
+
When the workflow runs:
|
|
266
|
+
1. GitHub Actions issues a short-lived OIDC token identifying the workflow + repo + ref.
|
|
267
|
+
2. The npm CLI exchanges that token for a one-time publish credential.
|
|
268
|
+
3. npm validates against the Trusted Publisher config on npmjs.com (`soxo-tech/bootstrap-core` + `npm-publish.yml`).
|
|
269
|
+
4. Publish succeeds.
|
|
270
|
+
|
|
271
|
+
If you ever need to inspect or change auth:
|
|
272
|
+
- https://www.npmjs.com/package/ui-soxo-bootstrap-core/access — Trusted Publisher config
|
|
273
|
+
- [.github/workflows/npm-publish.yml](.github/workflows/npm-publish.yml) — the workflow
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## Troubleshooting
|
|
278
|
+
|
|
279
|
+
### "Release tag does not match `package.json` version"
|
|
280
|
+
|
|
281
|
+
The workflow checks that the git tag is exactly `v<package.json version>`. If they don't match, the workflow fails fast.
|
|
282
|
+
|
|
283
|
+
**Fix:** Delete the Release & tag, run `npm version <correct>` to bump cleanly, push, and re-create the Release.
|
|
284
|
+
|
|
285
|
+
### Workflow runs but `npm publish` fails with 404
|
|
286
|
+
|
|
287
|
+
Likely auth issue. Check:
|
|
288
|
+
1. **Trusted Publisher exists** on https://www.npmjs.com/package/ui-soxo-bootstrap-core/access
|
|
289
|
+
2. **Repository** field is `bootstrap-core` (not `soxo-bootstrap-core`)
|
|
290
|
+
3. **Workflow filename** is `npm-publish.yml` (just the filename, not the path)
|
|
291
|
+
4. **Organization or user** is `soxo-tech`
|
|
292
|
+
|
|
293
|
+
### Workflow fails with 422 "Unsupported source repository visibility: private"
|
|
294
|
+
|
|
295
|
+
Someone added `--provenance` to the publish step. Provenance requires a public repo. Remove `--provenance` from the `npm publish` line in [.github/workflows/npm-publish.yml](.github/workflows/npm-publish.yml).
|
|
296
|
+
|
|
297
|
+
### Version already exists on npm
|
|
298
|
+
|
|
299
|
+
You can't republish the same version. Bump again and create a new Release.
|
|
300
|
+
|
|
301
|
+
### Tag pushed but no Release auto-publishes
|
|
302
|
+
|
|
303
|
+
The workflow trigger is `on: release: [created]` — pushing a tag alone doesn't publish. You must **create a Release on GitHub** for the workflow to fire.
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## Diagram of the full flow
|
|
308
|
+
|
|
309
|
+
```
|
|
310
|
+
┌─────────────────┐
|
|
311
|
+
│ feature/* │
|
|
312
|
+
└────────┬─────────┘
|
|
313
|
+
│ merge
|
|
314
|
+
▼
|
|
315
|
+
┌─────────────────┐
|
|
316
|
+
│ develop │
|
|
317
|
+
│ │ ── npm version prerelease --preid=dev
|
|
318
|
+
│ │ ── git push --follow-tags
|
|
319
|
+
│ │ ── GitHub Release (pre-release)
|
|
320
|
+
│ │ ↓
|
|
321
|
+
│ │ workflow publishes → npm @dev
|
|
322
|
+
└────────┬─────────┘
|
|
323
|
+
│ merge (when stable)
|
|
324
|
+
▼
|
|
325
|
+
┌─────────────────┐
|
|
326
|
+
│ master │
|
|
327
|
+
│ │ ── npm version patch | minor | major
|
|
328
|
+
│ │ ── git push --follow-tags
|
|
329
|
+
│ │ ── GitHub Release (stable)
|
|
330
|
+
│ │ ↓
|
|
331
|
+
│ │ workflow publishes → npm @latest
|
|
332
|
+
└─────────────────┘
|
|
333
|
+
```
|
|
@@ -158,7 +158,7 @@ export default function MenuAdd({ model, edit, history, match, formContent, call
|
|
|
158
158
|
|
|
159
159
|
{/* Model */}
|
|
160
160
|
<Form.Item label="Model" name="model_id">
|
|
161
|
-
<Select style={{ width: '100%' }}>
|
|
161
|
+
<Select allowClear style={{ width: '100%' }}>
|
|
162
162
|
{models.map((model, key) => (
|
|
163
163
|
<Option key={key} value={model.id}>{model.name}</Option>
|
|
164
164
|
))}
|
|
@@ -168,7 +168,7 @@ export default function MenuAdd({ model, edit, history, match, formContent, call
|
|
|
168
168
|
|
|
169
169
|
{/* Page */}
|
|
170
170
|
<Form.Item label="Page" name="page_id">
|
|
171
|
-
<Select style={{ width: '100%' }}>
|
|
171
|
+
<Select allowClear style={{ width: '100%' }}>
|
|
172
172
|
{pages.map((page, key) => (
|
|
173
173
|
<Option key={key} value={page.id}>{page.name}</Option>
|
|
174
174
|
))}
|
|
@@ -30,6 +30,8 @@ const MenuLists = ({ model, match, relativeAdd = false, additional_queries = [],
|
|
|
30
30
|
const [query, setQuery] = useState('');
|
|
31
31
|
const [dragMode, setDragMode] = useState(false);
|
|
32
32
|
const [orderChanged, setOrderChanged] = useState(false);
|
|
33
|
+
// keys of manually-expanded top-level panels (used when NOT searching)
|
|
34
|
+
const [manualOpenKeys, setManualOpenKeys] = useState([]);
|
|
33
35
|
|
|
34
36
|
const [nextId, setNextId] = useState(10000);
|
|
35
37
|
|
|
@@ -203,9 +205,39 @@ const MenuLists = ({ model, match, relativeAdd = false, additional_queries = [],
|
|
|
203
205
|
model.delete(rec).then(loadMenus);
|
|
204
206
|
};
|
|
205
207
|
|
|
206
|
-
|
|
208
|
+
// Recursively filter the menu tree by caption. A menu is kept if its own
|
|
209
|
+
// caption matches OR any descendant matches. When the menu itself matches we
|
|
210
|
+
// keep its full subtree; when only a descendant matches we keep just the
|
|
211
|
+
// pruned path so the matching item stays reachable.
|
|
212
|
+
const filterMenus = (menus, q) => {
|
|
213
|
+
if (!q) return menus || [];
|
|
214
|
+
const lower = q.toLowerCase();
|
|
215
|
+
|
|
216
|
+
return (menus || []).reduce((acc, menu) => {
|
|
217
|
+
const selfMatch = (menu.caption || '').toLowerCase().includes(lower);
|
|
218
|
+
if (selfMatch) {
|
|
219
|
+
acc.push({ ...menu });
|
|
220
|
+
return acc;
|
|
221
|
+
}
|
|
222
|
+
const subFiltered = filterMenus(menu.sub_menus || [], q);
|
|
223
|
+
if (subFiltered.length) {
|
|
224
|
+
acc.push({ ...menu, sub_menus: subFiltered });
|
|
225
|
+
}
|
|
226
|
+
return acc;
|
|
227
|
+
}, []);
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
// Ids of items (at one level) that have sub_menus — used to auto-expand
|
|
231
|
+
// every branch leading to a search match.
|
|
232
|
+
const expandableKeys = (items) => (items || []).filter((m) => m.sub_menus && m.sub_menus.length > 0).map((m) => String(m.id));
|
|
207
233
|
|
|
208
|
-
const
|
|
234
|
+
const searchActive = !!query;
|
|
235
|
+
const visibleItems = filterMenus(records, query);
|
|
236
|
+
|
|
237
|
+
// While searching, derive the open panels synchronously from the visible tree
|
|
238
|
+
// (every branch on the path to a match), so the matched sub-menu is revealed.
|
|
239
|
+
// When not searching, use the user's manually-expanded panels.
|
|
240
|
+
const activeKeys = searchActive ? expandableKeys(visibleItems) : manualOpenKeys;
|
|
209
241
|
|
|
210
242
|
const onSearch = (event) => {
|
|
211
243
|
setQuery(event.target.value);
|
|
@@ -305,7 +337,7 @@ const MenuLists = ({ model, match, relativeAdd = false, additional_queries = [],
|
|
|
305
337
|
<Card className="generic-list">
|
|
306
338
|
<div style={{ marginBottom: 16 }}>
|
|
307
339
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 }}>
|
|
308
|
-
<Search placeholder="
|
|
340
|
+
<Search placeholder="Search menus & sub-menus…" allowClear style={{ width: 300, marginBottom: '0px' }} onChange={onSearch} />
|
|
309
341
|
|
|
310
342
|
<Space size="small">
|
|
311
343
|
<Button onClick={getRecords} size={'small'} type="default">
|
|
@@ -361,7 +393,11 @@ const MenuLists = ({ model, match, relativeAdd = false, additional_queries = [],
|
|
|
361
393
|
{/* {!view ? ( */}
|
|
362
394
|
<Card>
|
|
363
395
|
<DndProvider backend={HTML5Backend}>
|
|
364
|
-
<Collapse
|
|
396
|
+
<Collapse
|
|
397
|
+
accordion={!searchActive}
|
|
398
|
+
activeKey={activeKeys}
|
|
399
|
+
onChange={(keys) => setManualOpenKeys(Array.isArray(keys) ? keys : keys ? [keys] : [])}
|
|
400
|
+
>
|
|
365
401
|
{visibleItems && visibleItems.length > 0 ? (
|
|
366
402
|
visibleItems.map((item, index) => (
|
|
367
403
|
<Panel
|
|
@@ -389,6 +425,8 @@ const MenuLists = ({ model, match, relativeAdd = false, additional_queries = [],
|
|
|
389
425
|
items={item.sub_menus || []}
|
|
390
426
|
model={model}
|
|
391
427
|
dragMode={dragMode}
|
|
428
|
+
searchActive={searchActive}
|
|
429
|
+
query={query}
|
|
392
430
|
setSelectedRecord={setSelectedRecord}
|
|
393
431
|
setDrawerTitle={setDrawerTitle}
|
|
394
432
|
setDrawerVisible={setDrawerVisible}
|
|
@@ -500,6 +538,8 @@ function NestedMenu({
|
|
|
500
538
|
items,
|
|
501
539
|
model,
|
|
502
540
|
dragMode,
|
|
541
|
+
searchActive,
|
|
542
|
+
query,
|
|
503
543
|
setSelectedRecord,
|
|
504
544
|
setDrawerTitle,
|
|
505
545
|
setDrawerVisible,
|
|
@@ -508,10 +548,9 @@ function NestedMenu({
|
|
|
508
548
|
onCrossLevelMove,
|
|
509
549
|
onChange,
|
|
510
550
|
}) {
|
|
511
|
-
// do not render Collapse
|
|
512
|
-
if (!items || items.length === 0) return null;
|
|
513
|
-
|
|
514
551
|
const [localItems, setLocalItems] = useState(items);
|
|
552
|
+
// keys of manually-expanded sub-panels (used when NOT searching)
|
|
553
|
+
const [manualOpenKeys, setManualOpenKeys] = useState([]);
|
|
515
554
|
|
|
516
555
|
useEffect(() => {
|
|
517
556
|
setLocalItems(items);
|
|
@@ -535,8 +574,18 @@ function NestedMenu({
|
|
|
535
574
|
return null;
|
|
536
575
|
}
|
|
537
576
|
|
|
577
|
+
// While searching, derive the open sub-panels from the items so the path to a
|
|
578
|
+
// match stays expanded; otherwise use the user's manually-expanded panels.
|
|
579
|
+
const activeKeys = searchActive
|
|
580
|
+
? localItems.filter((c) => c.sub_menus && c.sub_menus.length > 0).map((c) => String(c.id))
|
|
581
|
+
: manualOpenKeys;
|
|
582
|
+
|
|
538
583
|
return (
|
|
539
|
-
<Collapse
|
|
584
|
+
<Collapse
|
|
585
|
+
accordion={!searchActive}
|
|
586
|
+
activeKey={activeKeys}
|
|
587
|
+
onChange={(keys) => setManualOpenKeys(Array.isArray(keys) ? keys : keys ? [keys] : [])}
|
|
588
|
+
>
|
|
540
589
|
{localItems.map((child, index) => (
|
|
541
590
|
<Panel
|
|
542
591
|
key={child.id}
|
|
@@ -563,6 +612,8 @@ function NestedMenu({
|
|
|
563
612
|
step={step + 1}
|
|
564
613
|
items={child.sub_menus || []}
|
|
565
614
|
dragMode={dragMode}
|
|
615
|
+
searchActive={searchActive}
|
|
616
|
+
query={query}
|
|
566
617
|
setSelectedRecord={setSelectedRecord}
|
|
567
618
|
setDrawerTitle={setDrawerTitle}
|
|
568
619
|
setDrawerVisible={setDrawerVisible}
|