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
- const filtered = records.filter((r) => r.caption?.toUpperCase().includes(query.toUpperCase()));
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 visibleItems = filtered;
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="Enter Search Value" allowClear style={{ width: 300, marginBottom: '0px' }} onChange={onSearch} />
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 accordion>
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 accordion>
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}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ui-soxo-bootstrap-core",
3
- "version": "2.6.40-dev.11",
3
+ "version": "2.6.40-dev.12",
4
4
  "description": "All the Core Components for you to start",
5
5
  "keywords": [
6
6
  "all in one"