@alliance-droid/status-feedback-system 4.0.1 → 4.0.3
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/dist/api.d.ts
CHANGED
|
@@ -70,6 +70,8 @@ export interface BoardTransitions {
|
|
|
70
70
|
publicStatus: PublicStatus;
|
|
71
71
|
};
|
|
72
72
|
targets: BoardTransition[];
|
|
73
|
+
/** Whether this user may manage status on this project (drives the UI affordance). */
|
|
74
|
+
canManage: boolean;
|
|
73
75
|
}
|
|
74
76
|
/** Result of applying a status change from the board. */
|
|
75
77
|
export interface BoardStatusUpdate {
|
|
@@ -51,7 +51,9 @@
|
|
|
51
51
|
let posKey = $derived(`${menuOpen}:${loading}:${pendingTarget?.status ?? ''}:${txns?.targets.length ?? 0}`);
|
|
52
52
|
|
|
53
53
|
onMount(() => {
|
|
54
|
-
|
|
54
|
+
// Eagerly load in the detail view: this both readies the menu and lets the
|
|
55
|
+
// board confirm privilege (loadTransitions is a no-op without a token).
|
|
56
|
+
if (loadOnMount) void board.loadTransitions(item.id);
|
|
55
57
|
});
|
|
56
58
|
|
|
57
59
|
/** Teleport the menu to <body> and keep it positioned under the trigger.
|
|
@@ -59,7 +59,12 @@ export interface FeedbackBoardState {
|
|
|
59
59
|
pastedImage?: string | null;
|
|
60
60
|
}): Promise<void>;
|
|
61
61
|
submitResponse(itemId: string, message: string, pastedImage?: string | null): Promise<void>;
|
|
62
|
-
/**
|
|
62
|
+
/**
|
|
63
|
+
* Whether the current user may manage status — resolved against the backend
|
|
64
|
+
* (valid token AND a qualifying role + project access), not merely whether a
|
|
65
|
+
* token getter was provided. Starts `false` and flips `true` once confirmed,
|
|
66
|
+
* so UI can gate the status control by actual privilege.
|
|
67
|
+
*/
|
|
63
68
|
readonly canManageStatus: boolean;
|
|
64
69
|
/** Cached allowed transitions per item id, populated by loadTransitions. */
|
|
65
70
|
readonly transitions: Record<string, BoardTransitions>;
|
|
@@ -26,6 +26,9 @@ export function createFeedbackBoard(options) {
|
|
|
26
26
|
let voteErrors = $state({});
|
|
27
27
|
let loadMoreError = $state('');
|
|
28
28
|
let transitions = $state({});
|
|
29
|
+
// Resolved status-management privilege (one-time backend probe, not token presence).
|
|
30
|
+
let statusPrivilege = $state(false);
|
|
31
|
+
let privilegeProbed = false;
|
|
29
32
|
// Response cache
|
|
30
33
|
const responseCache = {};
|
|
31
34
|
// Track in-flight votes to prevent duplicate requests. A plain Set is correct
|
|
@@ -46,6 +49,7 @@ export function createFeedbackBoard(options) {
|
|
|
46
49
|
items = data.items;
|
|
47
50
|
total = data.total;
|
|
48
51
|
categories = data.categories;
|
|
52
|
+
void ensureStatusPrivilege();
|
|
49
53
|
}
|
|
50
54
|
catch (e) {
|
|
51
55
|
error = e instanceof Error ? e.message : 'Failed to load';
|
|
@@ -180,13 +184,32 @@ export function createFeedbackBoard(options) {
|
|
|
180
184
|
try {
|
|
181
185
|
const result = await client.getBoardTransitions(itemId, token);
|
|
182
186
|
transitions = { ...transitions, [itemId]: result };
|
|
187
|
+
// The backend tells us whether this user may manage status (200 either
|
|
188
|
+
// way — no 403 console noise for ordinary signed-in users).
|
|
189
|
+
statusPrivilege = result.canManage;
|
|
183
190
|
return result;
|
|
184
191
|
}
|
|
185
192
|
catch {
|
|
186
|
-
// 401/
|
|
193
|
+
// 401 (no/invalid token) or network error → no control.
|
|
187
194
|
return null;
|
|
188
195
|
}
|
|
189
196
|
}
|
|
197
|
+
/**
|
|
198
|
+
* One-time probe so the UI can gate the status control by *actual* privilege
|
|
199
|
+
* (valid token + qualifying role + project access), not merely token presence.
|
|
200
|
+
* Loads the first item's transitions once; a non-null result confirms the
|
|
201
|
+
* backend authorized the user. No token / no items / a 403 leaves it `false`.
|
|
202
|
+
*/
|
|
203
|
+
async function ensureStatusPrivilege() {
|
|
204
|
+
if (privilegeProbed || !getAuthToken)
|
|
205
|
+
return;
|
|
206
|
+
const sample = items[0];
|
|
207
|
+
if (!sample)
|
|
208
|
+
return;
|
|
209
|
+
privilegeProbed = true;
|
|
210
|
+
// loadTransitions sets statusPrivilege from the result's canManage flag.
|
|
211
|
+
await loadTransitions(sample.id);
|
|
212
|
+
}
|
|
190
213
|
async function setStatus(itemId, status, reason) {
|
|
191
214
|
const token = await resolveToken();
|
|
192
215
|
if (!token)
|
|
@@ -226,7 +249,7 @@ export function createFeedbackBoard(options) {
|
|
|
226
249
|
getResponses,
|
|
227
250
|
submitFeedback,
|
|
228
251
|
submitResponse,
|
|
229
|
-
get canManageStatus() { return
|
|
252
|
+
get canManageStatus() { return statusPrivilege; },
|
|
230
253
|
get transitions() { return transitions; },
|
|
231
254
|
loadTransitions,
|
|
232
255
|
setStatus,
|
package/package.json
CHANGED