@alliance-droid/status-feedback-system 1.3.12 → 1.3.14

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.
@@ -31,7 +31,7 @@
31
31
  showOnboarding?: boolean;
32
32
  /** URL to the feedback board page. If omitted, "View Open Issues" is hidden from the context menu. */
33
33
  boardUrl?: string;
34
- /** Pre-fill the email field (e.g. from the logged-in user's session) */
34
+ /** Authenticated user email. Required for submitting feedback. */
35
35
  userEmail?: string;
36
36
  }
37
37
 
@@ -115,7 +115,8 @@
115
115
  let formType = $state<'bug' | 'feature'>('bug');
116
116
  let formTitle = $state('');
117
117
  let formMessage = $state('');
118
- let formEmail = $state('');
118
+
119
+ let isAuthenticated = $derived(!!userEmail);
119
120
  let submitting = $state(false);
120
121
  let submitResult = $state<'success' | 'error' | null>(null);
121
122
 
@@ -233,7 +234,6 @@
233
234
  formType = type;
234
235
  formTitle = '';
235
236
  formMessage = '';
236
- formEmail = userEmail ?? '';
237
237
  submitResult = null;
238
238
  menuOpen = false;
239
239
  formOpen = true;
@@ -249,7 +249,7 @@
249
249
  }
250
250
 
251
251
  async function handleSubmit() {
252
- if (!formMessage.trim()) return;
252
+ if (!formMessage.trim() || !isAuthenticated) return;
253
253
  submitting = true;
254
254
  submitResult = null;
255
255
 
@@ -286,7 +286,7 @@
286
286
  title: formTitle.trim() || undefined,
287
287
  message: formMessage.trim(),
288
288
  category: formType === 'bug' ? 'bug' : 'feature',
289
- email: formEmail.trim() || undefined,
289
+ email: userEmail,
290
290
  pageUrl: window.location.href,
291
291
  metadata,
292
292
  });
@@ -337,8 +337,8 @@
337
337
  >
338
338
  <Card variant="elevated" padding="none" class="flex flex-col max-h-[calc(100vh-2rem)] overflow-hidden">
339
339
  <!-- Header (draggable) -->
340
- <!-- svelte-ignore a11y_no_static_element_interactions — drag handle needs mousedown -->
341
340
  <div
341
+ role="presentation"
342
342
  class="flex items-center justify-between px-5 py-4 border-b border-border shrink-0 select-none"
343
343
  style="cursor: {isDragging ? 'grabbing' : 'grab'};"
344
344
  onmousedown={handleDragStart}
@@ -372,7 +372,17 @@
372
372
  {formType === 'bug' ? "We'll look into this." : "Thanks for the suggestion!"}
373
373
  </p>
374
374
  </div>
375
+ {:else if !isAuthenticated}
376
+ <div class="text-center py-6 text-foreground-tertiary">
377
+ <i class="fa-solid fa-lock text-2xl" aria-hidden="true"></i>
378
+ <p class="mt-2 text-sm">Sign in to submit feedback</p>
379
+ </div>
375
380
  {:else}
381
+ <div class="flex items-center gap-1.5 text-xs text-foreground-tertiary">
382
+ <i class="fa-solid fa-user" aria-hidden="true"></i>
383
+ <span>Submitting as <span class="font-medium text-foreground-secondary">{userEmail}</span></span>
384
+ </div>
385
+
376
386
  <Input
377
387
  bind:value={formTitle}
378
388
  placeholder={formType === 'bug' ? 'Brief summary of the bug' : 'Feature title'}
@@ -388,13 +398,6 @@
388
398
  rows={4}
389
399
  />
390
400
 
391
- <Input
392
- type="email"
393
- bind:value={formEmail}
394
- placeholder="your@email.com (optional)"
395
- label="Email"
396
- />
397
-
398
401
  <!-- Auto-captured context (bugs only) -->
399
402
  {#if formType === 'bug'}
400
403
  <div class="space-y-2">
@@ -470,7 +473,7 @@
470
473
  </div>
471
474
 
472
475
  <!-- Footer -->
473
- {#if submitResult !== 'success'}
476
+ {#if submitResult !== 'success' && isAuthenticated}
474
477
  <div class="flex justify-end gap-2 px-5 py-4 border-t border-border shrink-0">
475
478
  <Button variant="neutral" style="outline" onclick={() => (formOpen = false)}>
476
479
  Cancel
@@ -9,7 +9,7 @@ interface Props {
9
9
  showOnboarding?: boolean;
10
10
  /** URL to the feedback board page. If omitted, "View Open Issues" is hidden from the context menu. */
11
11
  boardUrl?: string;
12
- /** Pre-fill the email field (e.g. from the logged-in user's session) */
12
+ /** Authenticated user email. Required for submitting feedback. */
13
13
  userEmail?: string;
14
14
  }
15
15
  declare const DevFeedback: import("svelte").Component<Props, {}, "">;
@@ -96,7 +96,7 @@
96
96
  bind:value={category}
97
97
  class="w-full rounded-md border border-border bg-surface px-3 py-2 text-sm text-foreground"
98
98
  >
99
- {#each categories as cat}
99
+ {#each categories as cat (cat)}
100
100
  <option value={cat}>{cat}</option>
101
101
  {/each}
102
102
  </select>
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import { onMount, untrack } from 'svelte';
2
+ import { onMount } from 'svelte';
3
3
  import type { System, SystemStatus } from '../types.js';
4
4
  import { createStatusClient, type StatusClient } from '../api.js';
5
5
  import { deriveOverallStatus } from '../utils.js';
@@ -20,8 +20,8 @@
20
20
 
21
21
  let { systems: systemsProp, apiUrl, apiKey, statusUrl, refreshInterval = 60 }: Props = $props();
22
22
 
23
- let systems: System[] = $state(untrack(() => systemsProp ?? []));
24
- let loading = $state(untrack(() => !systemsProp && !!apiUrl && !!apiKey));
23
+ let systems = $derived(systemsProp ?? []);
24
+ let loading = $derived(!systemsProp && !!apiUrl && !!apiKey);
25
25
  let fetchFailed = $state(false);
26
26
 
27
27
  let usesApi = $derived(!systemsProp && !!apiUrl && !!apiKey);
@@ -66,10 +66,6 @@
66
66
  };
67
67
  });
68
68
 
69
- $effect(() => {
70
- if (systemsProp) systems = systemsProp;
71
- });
72
-
73
69
  let overallStatus = $derived(deriveOverallStatus(systems));
74
70
 
75
71
  const messages: Record<SystemStatus, string> = {
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import { onMount, untrack } from 'svelte';
2
+ import { onMount } from 'svelte';
3
3
  import type { System, Incident, StatusHistoryEntry, SystemStatus } from '../types.js';
4
4
  import { createStatusClient, type StatusClient } from '../api.js';
5
5
  import { deriveOverallStatus } from '../utils.js';
@@ -37,10 +37,10 @@
37
37
  }: Props = $props();
38
38
 
39
39
  // ── State ──
40
- let systems: System[] = $state(untrack(() => systemsProp ?? []));
41
- let incidents: Incident[] = $state(untrack(() => incidentsProp ?? []));
42
- let statusHistory: Record<string, StatusHistoryEntry[]> = $state(untrack(() => statusHistoryProp ?? {}));
43
- let loading = $state(untrack(() => !systemsProp));
40
+ let systems = $derived(systemsProp ?? []);
41
+ let incidents = $derived(incidentsProp ?? []);
42
+ let statusHistory = $derived(statusHistoryProp ?? {});
43
+ let loading = $derived(!systemsProp);
44
44
  let error = $state('');
45
45
 
46
46
  // ── Self-fetching mode ──
@@ -95,17 +95,6 @@
95
95
  };
96
96
  });
97
97
 
98
- // ── Sync props when in pass-through mode ──
99
- $effect(() => {
100
- if (systemsProp) systems = systemsProp;
101
- });
102
- $effect(() => {
103
- if (incidentsProp) incidents = incidentsProp;
104
- });
105
- $effect(() => {
106
- if (statusHistoryProp) statusHistory = statusHistoryProp;
107
- });
108
-
109
98
  // ── Derived state ──
110
99
 
111
100
  let overallStatus = $derived(deriveOverallStatus(systems));
@@ -176,7 +165,7 @@
176
165
  <section>
177
166
  <h2 class="mb-4 text-lg font-semibold text-foreground">Systems</h2>
178
167
  <div class="space-y-3">
179
- {#each systems as system}
168
+ {#each systems as system (system.id)}
180
169
  <SystemCard
181
170
  {system}
182
171
  history={statusHistory[system.id] || []}
@@ -192,7 +181,7 @@
192
181
  <section>
193
182
  <h2 class="mb-4 text-lg font-semibold text-foreground">Active Incidents</h2>
194
183
  <div class="space-y-4">
195
- {#each activeIncidents as incident}
184
+ {#each activeIncidents as incident (incident.id)}
196
185
  <div class="rounded-lg border border-border bg-surface p-4">
197
186
  <div class="flex items-start justify-between">
198
187
  <div>
@@ -222,7 +211,7 @@
222
211
  <section>
223
212
  <h2 class="mb-4 text-lg font-semibold text-foreground">Past Incidents</h2>
224
213
  <div class="space-y-4">
225
- {#each recentResolved as incident}
214
+ {#each recentResolved as incident (incident.id)}
226
215
  <div class="rounded-lg border border-border bg-surface p-4">
227
216
  <div class="flex items-start justify-between">
228
217
  <div>
@@ -31,7 +31,7 @@
31
31
  <span class="ml-auto bg-surface-hover px-2 py-0.5 rounded-full text-xs">{board.total}</span>
32
32
  </button>
33
33
 
34
- {#each board.categories as cat}
34
+ {#each board.categories as cat (cat.name)}
35
35
  <button
36
36
  class="flex items-center gap-2 px-3 py-2 rounded-lg text-sm text-left w-full transition-colors
37
37
  {board.activeCategory === cat.name ? 'bg-surface-secondary text-foreground font-semibold' : 'text-foreground-secondary hover:bg-surface-hover hover:text-foreground'}"
@@ -36,7 +36,7 @@
36
36
  </script>
37
37
 
38
38
  <div class="space-y-4" role="list" aria-label="Incident timeline">
39
- {#each updates as update}
39
+ {#each updates as update (update.id)}
40
40
  {@const config = statusConfig[update.status]}
41
41
  <div class="flex gap-3" role="listitem">
42
42
  <div class="flex flex-col items-center">
@@ -74,7 +74,7 @@
74
74
  <span>Today</span>
75
75
  </div>
76
76
  <div class="flex gap-px">
77
- {#each dayBars as bar}
77
+ {#each dayBars as bar (bar.date)}
78
78
  <div
79
79
  class="h-8 flex-1 rounded-sm transition-opacity hover:opacity-80"
80
80
  style="background-color: {bar.color}"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alliance-droid/status-feedback-system",
3
- "version": "1.3.12",
3
+ "version": "1.3.14",
4
4
  "type": "module",
5
5
  "description": "Drop-in system status pages and user feedback forms for SvelteKit apps",
6
6
  "svelte": "./dist/index.js",