@stacksjs/defaults 0.75.263 → 0.75.266
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/ai/skills/stacks-browse/SKILL.md +3 -0
- package/ai/skills/stacks-browse/scripts/browse.ts +73 -14
- package/ai/skills/stacks-native/CATALOG.md +4 -4
- package/ide/vscode/package.json +1 -1
- package/package.json +4 -4
- package/resources/components/Dashboard/App/RequestsOverview.stx +75 -58
- package/resources/components/Dashboard/App/SourceInventory.stx +68 -59
- package/resources/components/Dashboard/Auth/AccessTokens.stx +57 -37
- package/resources/components/Dashboard/Billing/BillingTransactionHistory.stx +27 -33
- package/resources/components/Dashboard/Commerce/CommercePaymentsTable.stx +85 -49
- package/resources/components/Dashboard/Commerce/CommerceTaxesTable.stx +63 -66
- package/resources/components/Dashboard/Commerce/CommerceVariantsTable.stx +67 -23
- package/resources/components/Dashboard/Content/BlogDashboard.stx +73 -67
- package/resources/components/Dashboard/Content/FileManagerDashboard.stx +39 -12
- package/resources/components/Dashboard/Data/DataRecords.stx +85 -88
- package/resources/components/Dashboard/Deployments/DeploymentTable.stx +49 -64
- package/resources/components/Dashboard/Infrastructure/DnsDashboard.stx +46 -28
- package/resources/components/Dashboard/Operations/RecoveryPointTable.stx +72 -61
- package/resources/components/Dashboard/Operations/SchedulerTaskTable.stx +74 -70
- package/resources/components/Dashboard/Queue/QueueDashboard.stx +27 -61
- package/resources/components/Dashboard/Releases/ReleaseDashboard.stx +35 -61
- package/resources/components/Dashboard/Teams/TeamPeopleDashboard.stx +127 -143
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
@import('../UI/Table')
|
|
2
|
+
|
|
1
3
|
<script client>
|
|
2
4
|
import type { ReleaseRecord, ReleaseSummary } from '../../../../app/Actions/Dashboard/Releases/release-records'
|
|
3
5
|
import { dashboardApi } from '../../../../functions/dashboard-api'
|
|
@@ -41,27 +43,30 @@ function formatNumber(value: number): string {
|
|
|
41
43
|
return new Intl.NumberFormat().format(value)
|
|
42
44
|
}
|
|
43
45
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
46
|
+
const COLUMNS = [
|
|
47
|
+
{ key: 'version', label: 'Version', sortable: true, subtitleKey: 'notes', class: 'font-semibold text-gray-900 dark:text-white' },
|
|
48
|
+
{ key: 'type', label: 'Type', sortable: true, class: 'capitalize' },
|
|
49
|
+
{
|
|
50
|
+
key: 'statusKey',
|
|
51
|
+
label: 'Status',
|
|
52
|
+
type: 'badge' as const,
|
|
53
|
+
sortable: true,
|
|
54
|
+
badgeLabelKey: 'status',
|
|
55
|
+
badgeClasses: {
|
|
56
|
+
published: 'capitalize text-green-700 dark:text-green-300 bg-green-50 dark:bg-green-950/30',
|
|
57
|
+
scheduled: 'capitalize text-blue-700 dark:text-blue-300 bg-blue-50 dark:bg-blue-950/30',
|
|
58
|
+
draft: 'capitalize text-amber-700 dark:text-amber-300 bg-amber-50 dark:bg-amber-950/30',
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
{ key: 'downloads', label: 'Downloads', type: 'number' as const, sortable: true, align: 'right' as const, class: 'font-mono' },
|
|
62
|
+
{ key: 'author', label: 'Author', sortable: true, emptyText: 'Not recorded' },
|
|
63
|
+
{ key: 'createdAt', label: 'Created', type: 'datetime' as const, sortable: true, emptyText: 'Not recorded', class: 'whitespace-nowrap' },
|
|
64
|
+
]
|
|
55
65
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
return 'text-blue-700 dark:text-blue-300 bg-blue-50 dark:bg-blue-950/30'
|
|
61
|
-
if (value === 'draft')
|
|
62
|
-
return 'text-amber-700 dark:text-amber-300 bg-amber-50 dark:bg-amber-950/30'
|
|
63
|
-
return 'text-gray-700 dark:text-neutral-300 bg-gray-100 dark:bg-neutral-700'
|
|
64
|
-
}
|
|
66
|
+
const releaseRows = derived(() => rows().map(release => ({
|
|
67
|
+
...release,
|
|
68
|
+
statusKey: release.status.toLowerCase(),
|
|
69
|
+
})))
|
|
65
70
|
|
|
66
71
|
async function loadReleases(): Promise<void> {
|
|
67
72
|
isLoading.set(true)
|
|
@@ -141,47 +146,16 @@ onMount(() => {
|
|
|
141
146
|
</div>
|
|
142
147
|
</div>
|
|
143
148
|
|
|
144
|
-
<div class="
|
|
145
|
-
<
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
<div :else class="overflow-x-auto">
|
|
155
|
-
<table class="min-w-full divide-gray-200 divide-y dark:divide-neutral-700">
|
|
156
|
-
<thead class="bg-gray-50 dark:bg-neutral-900/50">
|
|
157
|
-
<tr>
|
|
158
|
-
<th class="px-4 py-3 font-semibold text-gray-600 text-left text-xs uppercase dark:text-neutral-400">Version</th>
|
|
159
|
-
<th class="px-4 py-3 font-semibold text-gray-600 text-left text-xs uppercase dark:text-neutral-400">Type</th>
|
|
160
|
-
<th class="px-4 py-3 font-semibold text-gray-600 text-left text-xs uppercase dark:text-neutral-400">Status</th>
|
|
161
|
-
<th class="px-4 py-3 font-semibold text-gray-600 text-right text-xs uppercase dark:text-neutral-400">Downloads</th>
|
|
162
|
-
<th class="px-4 py-3 font-semibold text-gray-600 text-left text-xs uppercase dark:text-neutral-400">Author</th>
|
|
163
|
-
<th class="px-4 py-3 font-semibold text-gray-600 text-left text-xs uppercase dark:text-neutral-400">Created</th>
|
|
164
|
-
</tr>
|
|
165
|
-
</thead>
|
|
166
|
-
<tbody class="divide-gray-100 divide-y dark:divide-neutral-700">
|
|
167
|
-
<template :for="release in rows()" :key="release.id">
|
|
168
|
-
<tr>
|
|
169
|
-
<td class="px-4 py-3">
|
|
170
|
-
<p class="font-semibold text-gray-900 text-sm dark:text-white">{{ release.version }}</p>
|
|
171
|
-
<p :if="release.notes" class="mt-1 max-w-md text-gray-500 text-xs truncate dark:text-neutral-400">{{ release.notes }}</p>
|
|
172
|
-
</td>
|
|
173
|
-
<td class="px-4 py-3 capitalize text-gray-600 text-sm dark:text-neutral-300">{{ release.type }}</td>
|
|
174
|
-
<td class="px-4 py-3">
|
|
175
|
-
<span :class="'inline-flex px-2 py-1 font-medium text-xs capitalize rounded-full ' + statusClass(release.status)">{{ release.status }}</span>
|
|
176
|
-
</td>
|
|
177
|
-
<td class="px-4 py-3 font-mono text-gray-700 text-right text-sm dark:text-neutral-200">{{ formatNumber(release.downloads) }}</td>
|
|
178
|
-
<td class="px-4 py-3 text-gray-600 text-sm dark:text-neutral-300">{{ release.author || 'Not recorded' }}</td>
|
|
179
|
-
<td class="px-4 py-3 text-gray-600 text-sm whitespace-nowrap dark:text-neutral-300">{{ formatDate(release.createdAt) }}</td>
|
|
180
|
-
</tr>
|
|
181
|
-
</template>
|
|
182
|
-
</tbody>
|
|
183
|
-
</table>
|
|
184
|
-
</div>
|
|
149
|
+
<div class="bg-white dark:bg-neutral-800 border border-gray-200 rounded-lg dark:border-neutral-700">
|
|
150
|
+
<Table
|
|
151
|
+
:columns="COLUMNS"
|
|
152
|
+
:data="releaseRows()"
|
|
153
|
+
:loading="isLoading()"
|
|
154
|
+
paginated
|
|
155
|
+
:page-size="25"
|
|
156
|
+
empty-title="No release records found"
|
|
157
|
+
empty-description="Create releases through your application workflow and they will appear here."
|
|
158
|
+
/>
|
|
185
159
|
</div>
|
|
186
160
|
</section>
|
|
187
161
|
</div>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
@import('../UI/Button', '../UI/ConfirmDialog')
|
|
1
|
+
@import('../UI/Button', '../UI/ConfirmDialog', '../UI/Table')
|
|
2
2
|
|
|
3
3
|
<script client>
|
|
4
4
|
import { dashboardApi } from '../../../../functions/dashboard-api'
|
|
@@ -53,8 +53,6 @@ const memberToRemove = state<TeamMember | null>(null)
|
|
|
53
53
|
const invitationToRevoke = state<TeamInvitation | null>(null)
|
|
54
54
|
|
|
55
55
|
const teamId = derived(() => Number(route.params.id))
|
|
56
|
-
const hasMembers = derived(() => members().length > 0)
|
|
57
|
-
const hasInvitations = derived(() => invitations().length > 0)
|
|
58
56
|
|
|
59
57
|
function roleLabel(role: string): string {
|
|
60
58
|
return role.charAt(0).toUpperCase() + role.slice(1)
|
|
@@ -65,24 +63,64 @@ function memberCountLabel(): string {
|
|
|
65
63
|
return `${count} team ${count === 1 ? 'member' : 'members'}`
|
|
66
64
|
}
|
|
67
65
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
66
|
+
/**
|
|
67
|
+
* One palette for member status and invitation delivery, keyed by value, so
|
|
68
|
+
* a status the server adds later still reads, in the neutral pill.
|
|
69
|
+
*/
|
|
70
|
+
const STATUS_CLASSES = {
|
|
71
|
+
active: 'bg-green-50 text-green-700 dark:bg-green-500/10 dark:text-green-400',
|
|
72
|
+
sent: 'bg-green-50 text-green-700 dark:bg-green-500/10 dark:text-green-400',
|
|
73
|
+
suspended: 'bg-red-50 text-red-700 dark:bg-red-500/10 dark:text-red-400',
|
|
74
|
+
failed: 'bg-red-50 text-red-700 dark:bg-red-500/10 dark:text-red-400',
|
|
75
|
+
expired: 'bg-amber-50 text-amber-700 dark:bg-amber-500/10 dark:text-amber-400',
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
78
|
+
/**
|
|
79
|
+
* The member and role columns are slotted: the first for its avatar, the
|
|
80
|
+
* second because an owner's role is fixed and everyone else's is a select.
|
|
81
|
+
*/
|
|
82
|
+
const MEMBER_COLUMNS = [
|
|
83
|
+
{ key: 'name', label: 'Member', sortable: true, slotted: true },
|
|
84
|
+
{ key: 'role', label: 'Role', sortable: true, slotted: true },
|
|
85
|
+
{ key: 'status', label: 'Status', type: 'badge' as const, sortable: true, badgeLabelKey: 'statusLabel', badgeClasses: STATUS_CLASSES },
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* An owner can be neither suspended nor removed. Anyone else is offered the
|
|
90
|
+
* opposite of their current state, and every status but `active` reads as
|
|
91
|
+
* one to activate, as the hand-rolled button did.
|
|
92
|
+
*/
|
|
93
|
+
const MEMBER_ACTIONS = [
|
|
94
|
+
{ action: 'suspend', label: 'Suspend', icon: 'i-hugeicons-pause', class: 'text-amber-500', when: { key: 'statusAction', equals: 'suspend' } },
|
|
95
|
+
{ action: 'activate', label: 'Activate', icon: 'i-hugeicons-play', class: 'text-green-500', when: { key: 'statusAction', equals: 'activate' } },
|
|
96
|
+
{ action: 'remove', label: 'Remove', icon: 'i-hugeicons-delete-02', class: 'text-red-500', when: { key: 'removable', equals: true } },
|
|
97
|
+
]
|
|
98
|
+
|
|
99
|
+
const INVITATION_COLUMNS = [
|
|
100
|
+
{ key: 'email', label: 'Recipient', sortable: true, class: 'text-neutral-900 dark:text-neutral-100' },
|
|
101
|
+
{ key: 'roleLabel', label: 'Role', sortable: true },
|
|
102
|
+
{ key: 'deliveryStatus', label: 'Delivery', type: 'badge' as const, sortable: true, badgeLabelKey: 'deliveryLabel', badgeClasses: STATUS_CLASSES },
|
|
103
|
+
{ key: 'expiresAt', label: 'Expires', type: 'date' as const, sortable: true, emptyText: 'Not available' },
|
|
104
|
+
]
|
|
105
|
+
|
|
106
|
+
const INVITATION_ACTIONS = [
|
|
107
|
+
{ action: 'resend', label: 'Resend invitation to', icon: 'i-hugeicons-mail-send-01' },
|
|
108
|
+
{ action: 'revoke', label: 'Revoke invitation to', icon: 'i-hugeicons-cancel-01', class: 'text-red-500' },
|
|
109
|
+
]
|
|
110
|
+
|
|
111
|
+
const memberRows = derived(() => members().map(member => ({
|
|
112
|
+
...member,
|
|
113
|
+
initial: member.name.charAt(0).toUpperCase(),
|
|
114
|
+
statusLabel: roleLabel(member.status),
|
|
115
|
+
statusAction: member.role === 'owner' ? 'none' : member.status === 'active' ? 'suspend' : 'activate',
|
|
116
|
+
removable: member.role !== 'owner',
|
|
117
|
+
})))
|
|
118
|
+
|
|
119
|
+
const invitationRows = derived(() => invitations().map(invitation => ({
|
|
120
|
+
...invitation,
|
|
121
|
+
roleLabel: roleLabel(invitation.role),
|
|
122
|
+
deliveryLabel: roleLabel(invitation.deliveryStatus),
|
|
123
|
+
})))
|
|
86
124
|
|
|
87
125
|
async function fetchPeople(): Promise<void> {
|
|
88
126
|
isLoading.set(true)
|
|
@@ -233,6 +271,20 @@ async function revokeInvitation(): Promise<void> {
|
|
|
233
271
|
}
|
|
234
272
|
}
|
|
235
273
|
|
|
274
|
+
function handleMemberAction(payload: { action: string, row: TeamMember }): void {
|
|
275
|
+
if (payload.action === 'remove')
|
|
276
|
+
memberToRemove.set(payload.row)
|
|
277
|
+
else
|
|
278
|
+
void toggleMemberStatus(payload.row)
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function handleInvitationAction(payload: { action: string, row: TeamInvitation }): void {
|
|
282
|
+
if (payload.action === 'resend')
|
|
283
|
+
void resendInvitation(payload.row)
|
|
284
|
+
else if (payload.action === 'revoke')
|
|
285
|
+
invitationToRevoke.set(payload.row)
|
|
286
|
+
}
|
|
287
|
+
|
|
236
288
|
onMount(() => {
|
|
237
289
|
fetchPeople()
|
|
238
290
|
})
|
|
@@ -307,79 +359,48 @@ onMount(() => {
|
|
|
307
359
|
</div>
|
|
308
360
|
</div>
|
|
309
361
|
|
|
310
|
-
<
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
<td class="px-6 py-4">
|
|
353
|
-
<span class="inline-flex px-2 py-1 font-medium text-xs rounded-full" :class="statusClass(member.status)">
|
|
354
|
-
{{ roleLabel(member.status) }}
|
|
355
|
-
</span>
|
|
356
|
-
</td>
|
|
357
|
-
<td class="px-6 py-4">
|
|
358
|
-
<div :show="member.role !== 'owner'" class="flex gap-2 items-center justify-end">
|
|
359
|
-
<Button
|
|
360
|
-
variant="secondary"
|
|
361
|
-
size="sm"
|
|
362
|
-
:loading="busyMemberId() === member.id"
|
|
363
|
-
:disabled="busyMemberId() === member.id"
|
|
364
|
-
@click="toggleMemberStatus(member)"
|
|
365
|
-
>
|
|
366
|
-
{{ member.status === 'active' ? 'Suspend' : 'Activate' }}
|
|
367
|
-
</Button>
|
|
368
|
-
<Button
|
|
369
|
-
variant="ghost"
|
|
370
|
-
size="sm"
|
|
371
|
-
:disabled="busyMemberId() === member.id"
|
|
372
|
-
@click="memberToRemove.set(member)"
|
|
373
|
-
>
|
|
374
|
-
Remove
|
|
375
|
-
</Button>
|
|
376
|
-
</div>
|
|
377
|
-
</td>
|
|
378
|
-
</tr>
|
|
379
|
-
</template>
|
|
380
|
-
</tbody>
|
|
381
|
-
</table>
|
|
382
|
-
</div>
|
|
362
|
+
<Table
|
|
363
|
+
:columns="MEMBER_COLUMNS"
|
|
364
|
+
:data="memberRows()"
|
|
365
|
+
:loading="isLoading()"
|
|
366
|
+
:row-actions="MEMBER_ACTIONS"
|
|
367
|
+
action-label-key="name"
|
|
368
|
+
busy-key="id"
|
|
369
|
+
:busy-value="busyMemberId()"
|
|
370
|
+
paginated
|
|
371
|
+
:page-size="25"
|
|
372
|
+
empty-title="No members yet"
|
|
373
|
+
empty-description="No members have joined this team yet."
|
|
374
|
+
@row-action="handleMemberAction"
|
|
375
|
+
>
|
|
376
|
+
<template #cell="{ row, column }">
|
|
377
|
+
<template :if="column.key === 'name'">
|
|
378
|
+
<div class="flex gap-3 items-center">
|
|
379
|
+
<div class="flex items-center justify-center shrink-0 h-9 w-9 font-semibold text-blue-700 text-sm dark:text-blue-300 bg-blue-50 dark:bg-blue-500/10 rounded-full">{{ row.initial }}</div>
|
|
380
|
+
<div>
|
|
381
|
+
<p class="font-medium text-neutral-900 text-sm dark:text-white">{{ row.name }}</p>
|
|
382
|
+
<p class="mt-0.5 text-neutral-500 text-xs dark:text-neutral-400">{{ row.email }}</p>
|
|
383
|
+
</div>
|
|
384
|
+
</div>
|
|
385
|
+
</template>
|
|
386
|
+
<template :if="column.key === 'role' && row.role === 'owner'">
|
|
387
|
+
<span class="text-neutral-700 text-sm dark:text-neutral-300">Owner</span>
|
|
388
|
+
</template>
|
|
389
|
+
<template :if="column.key === 'role' && row.role !== 'owner'">
|
|
390
|
+
<select
|
|
391
|
+
:value="row.role"
|
|
392
|
+
:aria-label="'Role for ' + row.name"
|
|
393
|
+
:disabled="busyMemberId() === row.id"
|
|
394
|
+
class="px-2.5 h-8 text-neutral-800 text-sm dark:text-neutral-100 bg-white dark:bg-neutral-950 border border-neutral-300 rounded-lg dark:border-neutral-700"
|
|
395
|
+
@change="updateMemberRole(row, $event)"
|
|
396
|
+
>
|
|
397
|
+
<option value="admin">Admin</option>
|
|
398
|
+
<option value="member">Member</option>
|
|
399
|
+
<option value="viewer">Viewer</option>
|
|
400
|
+
</select>
|
|
401
|
+
</template>
|
|
402
|
+
</template>
|
|
403
|
+
</Table>
|
|
383
404
|
</section>
|
|
384
405
|
|
|
385
406
|
<section class="overflow-hidden bg-white dark:bg-neutral-900 border border-neutral-200/70 rounded-xl dark:border-neutral-800">
|
|
@@ -388,57 +409,20 @@ onMount(() => {
|
|
|
388
409
|
<p class="mt-0.5 text-neutral-500 text-sm dark:text-neutral-400">Track delivery, resend links, or revoke access before acceptance.</p>
|
|
389
410
|
</div>
|
|
390
411
|
|
|
391
|
-
<
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
<tbody class="divide-neutral-200 divide-y dark:divide-neutral-800">
|
|
406
|
-
<template :for="invitation in invitations">
|
|
407
|
-
<tr>
|
|
408
|
-
<td class="px-6 py-4 text-neutral-900 text-sm dark:text-neutral-100">{{ invitation.email }}</td>
|
|
409
|
-
<td class="px-6 py-4 text-neutral-600 text-sm dark:text-neutral-300">{{ roleLabel(invitation.role) }}</td>
|
|
410
|
-
<td class="px-6 py-4">
|
|
411
|
-
<span class="inline-flex px-2 py-1 font-medium text-xs rounded-full" :class="statusClass(invitation.deliveryStatus)">
|
|
412
|
-
{{ roleLabel(invitation.deliveryStatus) }}
|
|
413
|
-
</span>
|
|
414
|
-
</td>
|
|
415
|
-
<td class="px-6 py-4 text-neutral-500 text-sm dark:text-neutral-400">{{ formatDate(invitation.expiresAt) }}</td>
|
|
416
|
-
<td class="px-6 py-4">
|
|
417
|
-
<div class="flex gap-2 items-center justify-end">
|
|
418
|
-
<Button
|
|
419
|
-
variant="secondary"
|
|
420
|
-
size="sm"
|
|
421
|
-
:loading="busyInvitationId() === invitation.id"
|
|
422
|
-
:disabled="busyInvitationId() === invitation.id"
|
|
423
|
-
@click="resendInvitation(invitation)"
|
|
424
|
-
>
|
|
425
|
-
Resend
|
|
426
|
-
</Button>
|
|
427
|
-
<Button
|
|
428
|
-
variant="ghost"
|
|
429
|
-
size="sm"
|
|
430
|
-
:disabled="busyInvitationId() === invitation.id"
|
|
431
|
-
@click="invitationToRevoke.set(invitation)"
|
|
432
|
-
>
|
|
433
|
-
Revoke
|
|
434
|
-
</Button>
|
|
435
|
-
</div>
|
|
436
|
-
</td>
|
|
437
|
-
</tr>
|
|
438
|
-
</template>
|
|
439
|
-
</tbody>
|
|
440
|
-
</table>
|
|
441
|
-
</div>
|
|
412
|
+
<Table
|
|
413
|
+
:columns="INVITATION_COLUMNS"
|
|
414
|
+
:data="invitationRows()"
|
|
415
|
+
:loading="isLoading()"
|
|
416
|
+
:row-actions="INVITATION_ACTIONS"
|
|
417
|
+
action-label-key="email"
|
|
418
|
+
busy-key="id"
|
|
419
|
+
:busy-value="busyInvitationId()"
|
|
420
|
+
paginated
|
|
421
|
+
:page-size="25"
|
|
422
|
+
empty-title="No pending invitations"
|
|
423
|
+
empty-description="Invitations you send appear here until they are accepted."
|
|
424
|
+
@row-action="handleInvitationAction"
|
|
425
|
+
/>
|
|
442
426
|
</section>
|
|
443
427
|
</div>
|
|
444
428
|
|