a2acalling 0.6.63 → 0.6.65
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/.a2a-manifest.json +2 -2
- package/.maestro/inbox/release-workflow-spam.md +25 -0
- package/CONVENTIONS.md +3 -0
- package/docs/plans/2026-02-21-a2a-48-permissions-redesign.md +359 -0
- package/docs/plans/2026-02-21-a2a-49-remaining-tabs-polish.md +375 -0
- package/package.json +1 -1
- package/src/dashboard/public/app.js +702 -424
- package/src/dashboard/public/index.html +223 -125
- package/src/dashboard/public/style.css +933 -109
package/.a2a-manifest.json
CHANGED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Ticket: Reduce Release Workflow Email Spam
|
|
2
|
+
|
|
3
|
+
## Summary
|
|
4
|
+
Consolidate or batch release workflows to reduce GitHub notification email volume
|
|
5
|
+
|
|
6
|
+
## Problem
|
|
7
|
+
Every commit/merge triggers a separate "Release (npm + GitHub) workflow run" notification email. During active development (like the current A2A-47/48/49 sprint), this floods the inbox.
|
|
8
|
+
|
|
9
|
+
## Proposed Solution
|
|
10
|
+
1. **Batch releases**: Only trigger release workflow once per PM run completion, not per-merge
|
|
11
|
+
2. **Conditional triggers**: Skip release workflow for WIP branches, only run on main after all tickets in a batch are merged
|
|
12
|
+
3. **Consolidate notifications**: Use GitHub's workflow_run event to chain workflows and send a single summary notification
|
|
13
|
+
|
|
14
|
+
## Acceptance Criteria
|
|
15
|
+
- [ ] Release workflow runs maximum once per maestro PM batch
|
|
16
|
+
- [ ] No release emails for intermediate merges during a sprint
|
|
17
|
+
- [ ] Single "Release complete" notification at end of batch
|
|
18
|
+
|
|
19
|
+
## Labels
|
|
20
|
+
- chore
|
|
21
|
+
- dx
|
|
22
|
+
- priority: medium
|
|
23
|
+
|
|
24
|
+
## Team
|
|
25
|
+
a2a calling
|
package/CONVENTIONS.md
CHANGED
|
@@ -63,6 +63,9 @@ All modules use CommonJS (`require`/`module.exports`). Each lib file exports a f
|
|
|
63
63
|
- Uses Shoelace web components (`<sl-*>` elements)
|
|
64
64
|
- Communicates via fetch to `/dashboard/api/*` endpoints
|
|
65
65
|
- SSE for real-time updates via `src/lib/dashboard-events.js`
|
|
66
|
+
- Dark theme is the default; uses CSS custom properties for theming
|
|
67
|
+
- Sidebar navigation with tab switching (Contacts, Calls, Invites, Logs, Settings, Permissions, Health)
|
|
68
|
+
- Permissions tab uses tier cards with tool toggles and auto-save
|
|
66
69
|
|
|
67
70
|
## Permission Tiers
|
|
68
71
|
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
# A2A-48: Permissions Tab Redesign — Implementation Plan
|
|
2
|
+
|
|
3
|
+
## Ticket
|
|
4
|
+
A2A-48: Permissions tab redesign with tier cards, tool toggles, and auto-save
|
|
5
|
+
|
|
6
|
+
## Approach Summary
|
|
7
|
+
Replace the current form-based permissions UI (dropdown tier selector, checkboxes, Save button) with a card-based, auto-saving interface matching the A2A-46 concept mock. Three files change: index.html, style.css, app.js.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## HTML Changes (index.html)
|
|
12
|
+
|
|
13
|
+
### Remove (lines 101-206 of #panel-permissions)
|
|
14
|
+
- `#tier-select` sl-select dropdown and row
|
|
15
|
+
- `#new-tier-btn` (moves to tier cards header)
|
|
16
|
+
- `#preview-caller-btn` (preview moves to right sidebar)
|
|
17
|
+
- `#show-drag-columns` checkbox and `#tier-columns` div
|
|
18
|
+
- `#tier-form` (name, description, tools checklist, topics list, goals list, Save Tier button)
|
|
19
|
+
- `#copy-from-tier` / `#copy-tier-btn` row — **REMOVED entirely** (copy-from functionality is retained only in the New Tier form's "Copy from" dropdown inside Settings details)
|
|
20
|
+
- Keep `#preview-dialog` (unchanged)
|
|
21
|
+
|
|
22
|
+
### Add (new #panel-permissions structure)
|
|
23
|
+
```
|
|
24
|
+
#panel-permissions
|
|
25
|
+
.perm-layout (flex row: main + sidebar)
|
|
26
|
+
.perm-main (flex:1, overflow-y:auto)
|
|
27
|
+
section: Active Tier
|
|
28
|
+
header with "Active Tier" + "+ New Tier" button
|
|
29
|
+
#tier-cards .tier-cards-grid (JS-rendered tier cards)
|
|
30
|
+
|
|
31
|
+
section: Active Configuration
|
|
32
|
+
header with "Active Configuration" + hint text
|
|
33
|
+
.config-columns (2-col grid)
|
|
34
|
+
.config-col: Active Topics (teal accent)
|
|
35
|
+
#active-topics-zone .drop-zone
|
|
36
|
+
.config-col: Active Goals (yellow accent)
|
|
37
|
+
#active-goals-zone .drop-zone
|
|
38
|
+
|
|
39
|
+
section: Allowed Tools
|
|
40
|
+
#tool-toggles .tool-toggles-grid (JS-rendered toggle cards)
|
|
41
|
+
|
|
42
|
+
section: Tier Warnings
|
|
43
|
+
#tier-warnings (existing, repositioned)
|
|
44
|
+
|
|
45
|
+
sl-details summary="Settings & Administration"
|
|
46
|
+
Defaults form (#defaults-form — unchanged internals)
|
|
47
|
+
New Tier form (#new-tier-form — unchanged internals, keeps #new-tier-copy-from)
|
|
48
|
+
Remote Callbook (#callbook-status — unchanged)
|
|
49
|
+
Auto Update (#auto-update-status — unchanged)
|
|
50
|
+
Paired Devices table — unchanged
|
|
51
|
+
|
|
52
|
+
.perm-sidebar (280px fixed right column)
|
|
53
|
+
#perm-preview .preview-card (inline caller preview)
|
|
54
|
+
#sidebar-topics .sidebar-list (all topics, draggable)
|
|
55
|
+
"+ Add Topic" button
|
|
56
|
+
#sidebar-goals .sidebar-list (all goals, draggable)
|
|
57
|
+
"+ Add Goal" button
|
|
58
|
+
|
|
59
|
+
sl-dialog#create-item-dialog (Create New Item modal — simplified, no icon selector)
|
|
60
|
+
sl-input#create-item-title
|
|
61
|
+
sl-textarea#create-item-desc
|
|
62
|
+
Create / Cancel buttons
|
|
63
|
+
|
|
64
|
+
sl-dialog#preview-dialog (existing — kept for full preview)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Key DOM ID changes
|
|
68
|
+
| Old ID | New ID/Structure | Notes |
|
|
69
|
+
|--------|-----------------|-------|
|
|
70
|
+
| `tier-select` | `#tier-cards` container | Cards replace dropdown. **All code reading `tier-select.value` must use `state.activeTierId` instead.** |
|
|
71
|
+
| `tier-tools-list` | `#tool-toggles` | Toggle cards replace checkboxes |
|
|
72
|
+
| `tier-topics-list` | `#active-topics-zone` | Drop zone with teal cards |
|
|
73
|
+
| `tier-goals-list` | `#active-goals-zone` | Drop zone with yellow cards |
|
|
74
|
+
| `tier-form` | Removed | Auto-save replaces form |
|
|
75
|
+
| `tier-name` / `tier-description` | Removed | Tier names shown on cards |
|
|
76
|
+
| `show-drag-columns` / `tier-columns` | Removed | Sidebar replaces columns |
|
|
77
|
+
| `copy-from-tier` / `copy-tier-btn` | **Removed entirely** | Copy-tier functionality removed; New Tier form keeps "Copy from" dropdown |
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## CSS Changes (style.css)
|
|
82
|
+
|
|
83
|
+
### New classes to add (~130 lines)
|
|
84
|
+
|
|
85
|
+
**Layout:**
|
|
86
|
+
- `.perm-layout` — flex row, gap
|
|
87
|
+
- `.perm-main` — flex:1, overflow-y:auto, max-width
|
|
88
|
+
- `.perm-sidebar` — width:280px, shrink:0, hidden below 1280px
|
|
89
|
+
- `.perm-section` — margin-bottom spacing
|
|
90
|
+
- `.perm-section-header` — flex between h2 and action buttons
|
|
91
|
+
- `.perm-hint` — muted italic helper text
|
|
92
|
+
- `.perm-add-btn` — text button with + icon style
|
|
93
|
+
|
|
94
|
+
**Tier cards:**
|
|
95
|
+
- `.tier-cards-grid` — grid, repeat(auto-fill, minmax(140px,1fr)), gap
|
|
96
|
+
- `.tier-card` — card-bg, border, rounded-xl, padding, cursor, centered content, h-24
|
|
97
|
+
- `.tier-card:hover` — lighter bg, border-gray-600
|
|
98
|
+
- `.tier-card.active` — gradient border glow (pseudo-element with blur), border-blue-500
|
|
99
|
+
- `.tier-card .status-dot` — green pulsing dot (top-right)
|
|
100
|
+
- `.tier-card-icon` — material icon, colored per tier
|
|
101
|
+
- `.tier-card-name` — font-semibold, white
|
|
102
|
+
|
|
103
|
+
**Toggle switches:**
|
|
104
|
+
- `.toggle-switch` — inline-block, 44x24px
|
|
105
|
+
- `.toggle-switch input` — hidden (opacity:0)
|
|
106
|
+
- `.toggle-switch .slider` — rounded pill, #374151 bg, transition
|
|
107
|
+
- `.toggle-switch .slider:before` — white circle, 18x18px
|
|
108
|
+
- `input:checked + .slider` — blue bg + blue glow shadow
|
|
109
|
+
- `input:checked + .slider:before` — translateX(20px)
|
|
110
|
+
- `.tool-toggle-card` — glass-panel, rounded-xl, flex between info and toggle
|
|
111
|
+
- `.tool-toggle-card.enabled` — border-blue-500/30, subtle blue shadow
|
|
112
|
+
- `.tool-icon` — 40x40 rounded-lg icon container, colored per tool
|
|
113
|
+
|
|
114
|
+
**Configuration zones:**
|
|
115
|
+
- `.config-columns` — grid, 2 columns, gap
|
|
116
|
+
- `.config-col` — flex column
|
|
117
|
+
- `.config-col-header` — uppercase, small, tracking-wide, flex with badge
|
|
118
|
+
- `.config-col-header--teal` — teal-400 color
|
|
119
|
+
- `.config-col-header--yellow` — yellow-400 color
|
|
120
|
+
- `.status-dot` — 6px circle
|
|
121
|
+
- `.status-dot--teal` — teal bg + glow
|
|
122
|
+
- `.status-dot--yellow` — yellow bg + glow
|
|
123
|
+
- `.count-badge` — tiny badge with count
|
|
124
|
+
- `.count-badge--teal` / `--yellow` — colored variants
|
|
125
|
+
- `.perm-drop-zone` — dashed SVG border, min-height, rounded-xl
|
|
126
|
+
- `.perm-drop-zone.drag-over` — blue highlight
|
|
127
|
+
- `.active-item-card` — card with accent border + glow shadow + close button
|
|
128
|
+
- `.active-item-card--teal` — teal border/glow
|
|
129
|
+
- `.active-item-card--yellow` — yellow border/glow
|
|
130
|
+
- `.drop-placeholder` — dashed inner border, "+ Drop Topic/Goal" text
|
|
131
|
+
|
|
132
|
+
**Sidebar:**
|
|
133
|
+
- `.preview-card` — gradient bg, rounded-2xl, border, padding, relative overflow
|
|
134
|
+
- `.sidebar-list` — space-y, margin-top
|
|
135
|
+
- `.sidebar-list-header` — uppercase tracking-wide muted
|
|
136
|
+
- `.sidebar-item` — card-bg, border, rounded-lg, flex, cursor-move, group-hover
|
|
137
|
+
- `.sidebar-item.active-in-zone` — dimmed, dashed border, italic "(Active)" label
|
|
138
|
+
- `.sidebar-add-btn` — dashed border, full-width, muted + hover primary
|
|
139
|
+
|
|
140
|
+
**Responsive:**
|
|
141
|
+
- `@media (max-width: 1280px)` — hide `.perm-sidebar`, show fallback preview button in .perm-main
|
|
142
|
+
|
|
143
|
+
### Modify existing
|
|
144
|
+
- Remove `.tools-checklist` rules (replaced by toggle cards)
|
|
145
|
+
- Remove `.tier-columns` / `.tier-column` rules (replaced by sidebar)
|
|
146
|
+
- Keep `.topic-row`, `.drag-handle`, `.topic-content` etc. (adapted for sidebar items)
|
|
147
|
+
- Keep `.tier-warning` rules (unchanged)
|
|
148
|
+
- Keep `.glass-panel` (reused for tool toggle cards)
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## JS Changes (app.js)
|
|
153
|
+
|
|
154
|
+
### New state
|
|
155
|
+
```js
|
|
156
|
+
// Add to state object:
|
|
157
|
+
activeTierId: 'public', // currently selected tier (replaces tier-select dropdown value)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Functions to REMOVE
|
|
161
|
+
- `fillTierSelects()` — replaced by renderTierCards() + populateInviteTierSelect()
|
|
162
|
+
- `renderTierColumns()` — replaced by sidebar lists
|
|
163
|
+
- `bindDragEvents()` — replaced by new sidebar↔zone drag handlers
|
|
164
|
+
- `bindItemListDelegation()` — replaced by direct delegation in bindPermissionsActions()
|
|
165
|
+
|
|
166
|
+
### bootstrap() call site changes (CRITICAL)
|
|
167
|
+
The bootstrap() function must be updated:
|
|
168
|
+
- `bindSettingsActions()` → `bindPermissionsActions()` (renamed)
|
|
169
|
+
- Remove `bindItemListDelegation()` call (functionality merged into bindPermissionsActions)
|
|
170
|
+
- `tabLoaders.permissions` should call `loadSettings()` to ensure fresh data on tab switch (currently a no-op)
|
|
171
|
+
|
|
172
|
+
### Functions to REWRITE
|
|
173
|
+
|
|
174
|
+
**`renderToolCheckboxes(allowedTools)` → `renderToolToggles(allowedTools)`**
|
|
175
|
+
- Renders TOOL_DESCRIPTIONS as toggle-switch cards (glass-panel + icon + name + desc + toggle)
|
|
176
|
+
- Each toggle has data-tool attribute
|
|
177
|
+
- Change event calls autoSaveTier()
|
|
178
|
+
- Active toggles get .enabled class (blue border glow)
|
|
179
|
+
|
|
180
|
+
**`renderTopicList(tier)` → `renderActiveTopics(tier)`**
|
|
181
|
+
- Renders topics in #active-topics-zone as .active-item-card--teal cards
|
|
182
|
+
- Each card has close button (removes + auto-saves)
|
|
183
|
+
- Includes "+ Drop Topic" placeholder at bottom
|
|
184
|
+
- Updates #topic-count badge
|
|
185
|
+
|
|
186
|
+
**`renderGoalList(tier)` → `renderActiveGoals(tier)`**
|
|
187
|
+
- Same pattern as topics but with yellow accent, renders in #active-goals-zone
|
|
188
|
+
- Updates #goal-count badge
|
|
189
|
+
|
|
190
|
+
**`renderTierEditor(tierId)` → `renderPermissions()`**
|
|
191
|
+
- Orchestrator: calls renderTierCards, renderActiveTopics, renderActiveGoals, renderToolToggles, renderTierWarnings, renderSidebarPreview, renderSidebarLists
|
|
192
|
+
- Uses state.activeTierId instead of reading tier-select.value
|
|
193
|
+
|
|
194
|
+
**`openCallerPreview()`** ← MUST BE REWRITTEN (not unchanged!)
|
|
195
|
+
- Current code at line 1591 reads `document.getElementById('tier-select').value` — that element is removed.
|
|
196
|
+
- Fix: Replace with `state.activeTierId`
|
|
197
|
+
- Rest of function logic (getPreviewData, dialog rendering) stays the same.
|
|
198
|
+
|
|
199
|
+
**`bindSettingsActions()` → `bindPermissionsActions()`**
|
|
200
|
+
- Remove: tier-form submit handler (Save Tier button gone)
|
|
201
|
+
- Remove: tier-select sl-change handler (cards replace it)
|
|
202
|
+
- Remove: copy-tier-btn click handler (copy-tier functionality removed)
|
|
203
|
+
- Remove: show-drag-columns handler (removed feature)
|
|
204
|
+
- Remove: preview-caller-btn handler (preview now inline in sidebar)
|
|
205
|
+
- Add: tier card click delegation → set state.activeTierId + renderPermissions()
|
|
206
|
+
- Add: tool toggle change delegation → autoSaveTier()
|
|
207
|
+
- Add: topic/goal close button delegation → remove + autoSaveTier()
|
|
208
|
+
- Add: sidebar add-topic/add-goal button → open create-item-dialog
|
|
209
|
+
- Add: create-item-dialog submit → add item + autoSaveTier()
|
|
210
|
+
- Keep: defaults-form submit handler
|
|
211
|
+
- Keep: new-tier-form submit handler — **BUT FIX LINE 1734**: replace `document.getElementById('tier-select').value = tierId` with `state.activeTierId = tierId; renderPermissions();`
|
|
212
|
+
- Keep: preview-close-btn handler
|
|
213
|
+
- Keep: callbook, auto-update, device handlers (unchanged)
|
|
214
|
+
|
|
215
|
+
**`loadSettings()`**
|
|
216
|
+
- Replace `fillTierSelects()` call with:
|
|
217
|
+
- Call `populateInviteTierSelect()` to populate `#invite-tier` and `#new-tier-copy-from`
|
|
218
|
+
- Call `renderPermissions()`
|
|
219
|
+
- Remove: `renderTierColumns()` call
|
|
220
|
+
- Keep: defaults field population
|
|
221
|
+
|
|
222
|
+
### Functions to ADD
|
|
223
|
+
|
|
224
|
+
**`renderTierCards()`**
|
|
225
|
+
- Reads state.settings.tiers, renders grid of .tier-card elements
|
|
226
|
+
- Active card (state.activeTierId) gets .active class + green status-dot
|
|
227
|
+
- Each card: icon (mapped from tier id or custom), name, click handler
|
|
228
|
+
|
|
229
|
+
**`renderSidebarPreview(tierId)`**
|
|
230
|
+
- Uses getPreviewData(tierId) to render inline preview card
|
|
231
|
+
- Shows: tier name badge, "can discuss X topics to help Y goals using Z tools" summary
|
|
232
|
+
- Active/valid status indicators
|
|
233
|
+
|
|
234
|
+
**`renderSidebarLists(tier)`**
|
|
235
|
+
- Renders all topics in #sidebar-topics as .sidebar-item cards with drag handles
|
|
236
|
+
- Topics active in current tier shown dimmed with "(Active)" label
|
|
237
|
+
- Renders all goals in #sidebar-goals same pattern
|
|
238
|
+
- Each list has "+ Add Topic" / "+ Add Goal" button at bottom
|
|
239
|
+
|
|
240
|
+
**`autoSaveTier()`**
|
|
241
|
+
- Debounced (250ms) function
|
|
242
|
+
- Collects: allowed_tools from toggle states, topics from active zone, goals from active zone
|
|
243
|
+
- PUTs to `/settings/tiers/${state.activeTierId}`
|
|
244
|
+
- Shows subtle "Saved" notice on success
|
|
245
|
+
- NOTE: Uses `c.dataset.topic` for BOTH topics and goals — this is intentional because
|
|
246
|
+
`parseTopicObjects()` in dashboard.js:160 only reads `entry.topic`. Add WHY comment.
|
|
247
|
+
|
|
248
|
+
**`bindSidebarDrag()`**
|
|
249
|
+
- Makes .sidebar-item elements draggable
|
|
250
|
+
- Drop targets: #active-topics-zone and #active-goals-zone
|
|
251
|
+
- On drop: add item to active zone, mark as "(Active)" in sidebar, auto-save
|
|
252
|
+
- Reverse: close button on active items removes from zone, un-dims in sidebar
|
|
253
|
+
|
|
254
|
+
**`populateInviteTierSelect()`**
|
|
255
|
+
- Extracted from old fillTierSelects() — populates:
|
|
256
|
+
1. `#invite-tier` (invites tab)
|
|
257
|
+
2. `#new-tier-copy-from` (inside Settings details)
|
|
258
|
+
- Does NOT populate `#tier-select` (removed) or `#copy-from-tier` (removed)
|
|
259
|
+
|
|
260
|
+
### Functions UNCHANGED
|
|
261
|
+
- `getPreviewData(tierId)` — reused by renderSidebarPreview
|
|
262
|
+
- `renderTierWarnings(tier)` — container ID stays #tier-warnings
|
|
263
|
+
- `renderCallbookStatus()` — unchanged, just inside Settings details now
|
|
264
|
+
- `renderAutoUpdateStatus()` — unchanged
|
|
265
|
+
- `loadDashboardStatus()` — unchanged
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## Auto-Save Pattern
|
|
270
|
+
|
|
271
|
+
```js
|
|
272
|
+
// A2A-48: debounced auto-save replaces explicit Save Tier button.
|
|
273
|
+
// 250ms delay prevents excessive API calls during rapid changes.
|
|
274
|
+
let _autoSaveTimer = null;
|
|
275
|
+
function autoSaveTier() {
|
|
276
|
+
clearTimeout(_autoSaveTimer);
|
|
277
|
+
_autoSaveTimer = setTimeout(async () => {
|
|
278
|
+
const tierId = state.activeTierId;
|
|
279
|
+
if (!tierId) return;
|
|
280
|
+
|
|
281
|
+
// Collect tools from toggle states
|
|
282
|
+
const toggles = document.querySelectorAll('#tool-toggles .toggle-switch input');
|
|
283
|
+
const allowed_tools = Array.from(toggles).filter(t => t.checked).map(t => t.dataset.tool);
|
|
284
|
+
|
|
285
|
+
// Collect topics from active zone
|
|
286
|
+
const topicCards = document.querySelectorAll('#active-topics-zone .active-item-card');
|
|
287
|
+
const topics = Array.from(topicCards).map(c => c.dataset.topic).filter(Boolean);
|
|
288
|
+
const manifestTopics = Array.from(topicCards).map(c => ({
|
|
289
|
+
topic: c.dataset.topic,
|
|
290
|
+
description: c.dataset.description || ''
|
|
291
|
+
})).filter(t => t.topic);
|
|
292
|
+
|
|
293
|
+
// A2A-48: uses dataset.topic for goals too (NOT dataset.objective) because
|
|
294
|
+
// parseTopicObjects() in dashboard.js:160 only reads entry.topic. The semantic
|
|
295
|
+
// distinction (objective vs topic) is UI-only; storage layer uses {topic, description}.
|
|
296
|
+
const goalCards = document.querySelectorAll('#active-goals-zone .active-item-card');
|
|
297
|
+
const goals = Array.from(goalCards).map(c => c.dataset.topic).filter(Boolean);
|
|
298
|
+
const manifestObjectives = Array.from(goalCards).map(c => ({
|
|
299
|
+
topic: c.dataset.topic,
|
|
300
|
+
description: c.dataset.description || ''
|
|
301
|
+
})).filter(g => g.topic);
|
|
302
|
+
|
|
303
|
+
const body = { allowed_tools, topics, goals, manifest: { topics: manifestTopics, objectives: manifestObjectives } };
|
|
304
|
+
try {
|
|
305
|
+
await request(`/settings/tiers/${encodeURIComponent(tierId)}`, {
|
|
306
|
+
method: 'PUT', body: JSON.stringify(body)
|
|
307
|
+
});
|
|
308
|
+
showNotice('Saved');
|
|
309
|
+
} catch (err) {
|
|
310
|
+
showNotice(`Save failed: ${err.message}`);
|
|
311
|
+
}
|
|
312
|
+
// Refresh state from server to stay in sync
|
|
313
|
+
const payload = await request('/settings');
|
|
314
|
+
state.settings = payload;
|
|
315
|
+
}, 250);
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
## Critical Integration Points
|
|
322
|
+
|
|
323
|
+
1. **state.activeTierId initialization**: Set to 'public' in state object. When permissions panel loads (`loadSettings()`), default to 'public' or first available tier.
|
|
324
|
+
|
|
325
|
+
2. **Invite tier select**: `fillTierSelects()` currently populates `#invite-tier` for the Invites tab. After removing fillTierSelects, `populateInviteTierSelect()` handles this. Called from loadSettings().
|
|
326
|
+
|
|
327
|
+
3. **Tier warnings**: `#tier-warnings` container stays in new HTML. `renderTierWarnings()` called from `renderPermissions()` unchanged.
|
|
328
|
+
|
|
329
|
+
4. **Settings details contents**: The defaults form, new-tier form, callbook, auto-update, and device sections all reference existing DOM IDs. They move INSIDE `<sl-details>` but their IDs and inner structure stay the same. All existing bind handlers still find them.
|
|
330
|
+
|
|
331
|
+
5. **Tab navigation (CORRECTED)**: `tabLoaders.permissions` is currently a no-op (`() => {}`). Update it to call `loadSettings()` to ensure fresh data when switching to Permissions tab. This is not a regression fix (existing code has same stale-data issue) but improves behavior while we're in here.
|
|
332
|
+
|
|
333
|
+
6. **Hash navigation**: `openCallTranscript()` uses hash to switch tabs. No impact — permissions tab doesn't use hash navigation.
|
|
334
|
+
|
|
335
|
+
7. **openCallerPreview() tier-select reference (FIXED)**: This function reads `document.getElementById('tier-select').value` at line 1591. Since `#tier-select` is removed, this MUST change to `state.activeTierId`. The function is listed as "Functions to REWRITE" above.
|
|
336
|
+
|
|
337
|
+
8. **new-tier-form success path (FIXED)**: At line 1734, `document.getElementById('tier-select').value = tierId` must become `state.activeTierId = tierId; renderPermissions();`.
|
|
338
|
+
|
|
339
|
+
9. **bootstrap() changes (FIXED)**: Must update: `bindSettingsActions()` → `bindPermissionsActions()`, remove `bindItemListDelegation()` call.
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
## Scope Decision
|
|
344
|
+
|
|
345
|
+
Drop the glass modal with icon selector and segmented Topic/Goal control. Instead, use a simplified `<sl-dialog>` with just title + description inputs (consistent with existing Shoelace patterns). This saves ~60-80 lines while keeping the "Create New Item" functionality.
|
|
346
|
+
|
|
347
|
+
Builder should track actual git diff size. If exceeding 550 lines, defer the sidebar drag feature (make sidebar read-only) as the primary cut.
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
## Testing Strategy
|
|
352
|
+
|
|
353
|
+
No new test files needed — this is a pure frontend SPA change. Existing backend tests (`npm test`) must pass unchanged since:
|
|
354
|
+
- No API changes
|
|
355
|
+
- No route changes
|
|
356
|
+
- No data model changes
|
|
357
|
+
- Dashboard API endpoints unchanged
|
|
358
|
+
|
|
359
|
+
Manual verification via browser: open dashboard, navigate to Permissions tab, verify all acceptance criteria visually.
|