@stacksjs/defaults 0.75.233 → 0.75.237
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-auth/SKILL.md +9 -1
- package/ai/skills/stacks-dashboard/SKILL.md +2 -2
- package/ai/skills/stacks-database/SKILL.md +1 -1
- package/ai/skills/stacks-deploy/SKILL.md +3 -2
- package/ai/skills/stacks-migrations/SKILL.md +2 -2
- package/ai/skills/stacks-native/CATALOG.md +12 -12
- package/ai/skills/stacks-realtime/SKILL.md +16 -2
- package/ai/skills/stacks-router/SKILL.md +8 -0
- package/ai/skills/stacks-testing/SKILL.md +5 -0
- package/app/Actions/Monitoring/error-provider.ts +129 -12
- package/app/Models/Error.ts +21 -0
- package/ide/vscode/package.json +1 -1
- package/package.json +2 -2
- package/resources/components/Dashboard/Auth/AuthCard.stx +29 -0
- package/resources/components/Dashboard/Auth/ForgotPassword.stx +65 -79
- package/resources/components/Dashboard/Auth/Login.stx +73 -82
- package/resources/components/Dashboard/Auth/Register.stx +121 -135
- package/resources/components/Dashboard/Auth/ResetPassword.stx +88 -102
- package/resources/components/Dashboard/Buddy/BuddyAssistant.stx +11 -15
- package/resources/components/Dashboard/Commerce/CommerceCategoriesDashboard.stx +8 -20
- package/resources/components/Dashboard/Commerce/CommerceCouponsDashboard.stx +8 -20
- package/resources/components/Dashboard/Commerce/CommerceCustomersDashboard.stx +8 -20
- package/resources/components/Dashboard/Commerce/CommerceGiftCardsDashboard.stx +8 -20
- package/resources/components/Dashboard/Commerce/CommerceManufacturersDashboard.stx +13 -24
- package/resources/components/Dashboard/Commerce/CommerceOrdersDashboard.stx +8 -20
- package/resources/components/Dashboard/Commerce/CommerceOverviewDashboard.stx +17 -21
- package/resources/components/Dashboard/Commerce/CommercePaymentsDashboard.stx +7 -19
- package/resources/components/Dashboard/Commerce/CommercePosDashboard.stx +4 -16
- package/resources/components/Dashboard/Commerce/CommerceProductsDashboard.stx +8 -20
- package/resources/components/Dashboard/Commerce/CommerceReviewsDashboard.stx +7 -18
- package/resources/components/Dashboard/Commerce/CommerceTaxesDashboard.stx +13 -24
- package/resources/components/Dashboard/Commerce/CommerceUnitsDashboard.stx +13 -24
- package/resources/components/Dashboard/Commerce/CommerceVariantsDashboard.stx +7 -18
- package/resources/components/Dashboard/Commerce/Delivery/CouriersDashboard.stx +7 -13
- package/resources/components/Dashboard/Commerce/Delivery/DeliveryOverviewDashboard.stx +12 -16
- package/resources/components/Dashboard/Commerce/Delivery/DeliveryRoutesDashboard.stx +7 -13
- package/resources/components/Dashboard/Commerce/Delivery/DigitalDeliveriesDashboard.stx +7 -13
- package/resources/components/Dashboard/Commerce/Delivery/LicenseKeysDashboard.stx +7 -13
- package/resources/components/Dashboard/Commerce/Delivery/ShippingMethodsDashboard.stx +7 -13
- package/resources/components/Dashboard/Commerce/Delivery/ShippingRatesDashboard.stx +7 -13
- package/resources/components/Dashboard/Commerce/Delivery/ShippingZonesDashboard.stx +7 -13
- package/resources/components/Dashboard/Commerce/PrintDevicesDashboard.stx +8 -20
- package/resources/components/Dashboard/Commerce/PrintLogsDashboard.stx +7 -19
- package/resources/components/Dashboard/Commerce/ProductWaitlistDashboard.stx +12 -16
- package/resources/components/Dashboard/Commerce/RestaurantWaitlistDashboard.stx +12 -16
- package/resources/components/Dashboard/Deployments/DeploymentList.stx +17 -21
- package/resources/components/Dashboard/Marketing/AbandonedCartsDashboard.stx +6 -10
- package/resources/components/Dashboard/Marketing/CampaignsDashboard.stx +6 -10
- package/resources/components/Dashboard/Marketing/MarketingListsDashboard.stx +9 -13
- package/resources/components/Dashboard/Marketing/SocialPostsDashboard.stx +6 -10
- package/resources/components/Dashboard/Queue/QueueDashboard.stx +12 -16
- package/resources/components/Dashboard/Realtime/RealtimeDashboard.stx +6 -10
- package/resources/components/Dashboard/Releases/ReleaseDashboard.stx +6 -10
- package/resources/components/Dashboard/UI/MetricCards.stx +32 -0
- package/resources/components/Dashboard/UI/PageHeader.stx +25 -66
- package/resources/components/Dashboard/UI/Table.stx +79 -6
|
@@ -43,121 +43,107 @@ function handleSubmit(): void {
|
|
|
43
43
|
}
|
|
44
44
|
</script>
|
|
45
45
|
|
|
46
|
-
<
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
46
|
+
<AuthCard :title="title()" :subtitle="subtitle()">
|
|
47
|
+
|
|
48
|
+
<!-- Form Card -->
|
|
49
|
+
<div class="p-6 bg-white dark:bg-neutral-900 border border-neutral-200/60 rounded-2xl dark:border-neutral-800 shadow-black/5 shadow-xl dark:shadow-black/20">
|
|
50
|
+
<div :if="checking()">
|
|
51
|
+
<div class="py-4 text-center">
|
|
52
|
+
<div class="inline-flex items-center justify-center mb-4 h-12 w-12 bg-neutral-100 dark:bg-neutral-800 rounded-full">
|
|
53
|
+
<div class="h-6 w-6 text-neutral-500 animate-spin i-hugeicons-loading-03"></div>
|
|
54
|
+
</div>
|
|
55
|
+
<p class="text-neutral-500 text-sm dark:text-neutral-400">Checking your link</p>
|
|
52
56
|
</div>
|
|
53
|
-
<h1 class="font-semibold text-2xl text-neutral-900 dark:text-white">
|
|
54
|
-
{{ title() }}
|
|
55
|
-
</h1>
|
|
56
|
-
<p class="mt-2 text-neutral-500 text-sm dark:text-neutral-400">
|
|
57
|
-
{{ subtitle() }}
|
|
58
|
-
</p>
|
|
59
57
|
</div>
|
|
60
58
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
<div class="inline-flex items-center justify-center mb-4 h-12 w-12 bg-neutral-100 dark:bg-neutral-800 rounded-full">
|
|
66
|
-
<div class="h-6 w-6 text-neutral-500 animate-spin i-hugeicons-loading-03"></div>
|
|
67
|
-
</div>
|
|
68
|
-
<p class="text-neutral-500 text-sm dark:text-neutral-400">Checking your link</p>
|
|
59
|
+
<div :else-if="invalid()">
|
|
60
|
+
<div class="py-4 text-center">
|
|
61
|
+
<div class="inline-flex items-center justify-center mb-4 h-12 w-12 bg-red-100 dark:bg-red-900/30 rounded-full">
|
|
62
|
+
<div class="h-6 w-6 text-red-600 dark:text-red-400 i-hugeicons-alert-circle"></div>
|
|
69
63
|
</div>
|
|
64
|
+
<h2 class="mb-2 font-medium text-lg text-neutral-900 dark:text-white">
|
|
65
|
+
This link no longer works
|
|
66
|
+
</h2>
|
|
67
|
+
<p class="mb-6 text-neutral-500 text-sm dark:text-neutral-400">
|
|
68
|
+
Reset links expire, and each one can be used only once. Ask for a fresh link and it will arrive in a moment.
|
|
69
|
+
</p>
|
|
70
|
+
<Button href="/forgot-password">
|
|
71
|
+
Send a new link
|
|
72
|
+
</Button>
|
|
70
73
|
</div>
|
|
74
|
+
</div>
|
|
71
75
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
</div>
|
|
77
|
-
<h2 class="mb-2 font-medium text-lg text-neutral-900 dark:text-white">
|
|
78
|
-
This link no longer works
|
|
79
|
-
</h2>
|
|
80
|
-
<p class="mb-6 text-neutral-500 text-sm dark:text-neutral-400">
|
|
81
|
-
Reset links expire, and each one can be used only once. Ask for a fresh link and it will arrive in a moment.
|
|
82
|
-
</p>
|
|
83
|
-
<Button href="/forgot-password">
|
|
84
|
-
Send a new link
|
|
85
|
-
</Button>
|
|
76
|
+
<div :else-if="success()">
|
|
77
|
+
<div class="py-4 text-center">
|
|
78
|
+
<div class="inline-flex items-center justify-center mb-4 h-12 w-12 bg-green-100 dark:bg-green-900/30 rounded-full">
|
|
79
|
+
<div class="h-6 w-6 text-green-600 dark:text-green-400 i-hugeicons-checkmark-circle-02"></div>
|
|
86
80
|
</div>
|
|
81
|
+
<h2 class="mb-2 font-medium text-lg text-neutral-900 dark:text-white">
|
|
82
|
+
Password changed
|
|
83
|
+
</h2>
|
|
84
|
+
<p class="mb-6 text-neutral-500 text-sm dark:text-neutral-400">
|
|
85
|
+
You can sign in with your new password now.
|
|
86
|
+
</p>
|
|
87
|
+
<Button href="/login">
|
|
88
|
+
Go to sign in
|
|
89
|
+
</Button>
|
|
87
90
|
</div>
|
|
91
|
+
</div>
|
|
88
92
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
</
|
|
94
|
-
<h2 class="mb-2 font-medium text-lg text-neutral-900 dark:text-white">
|
|
95
|
-
Password changed
|
|
96
|
-
</h2>
|
|
97
|
-
<p class="mb-6 text-neutral-500 text-sm dark:text-neutral-400">
|
|
98
|
-
You can sign in with your new password now.
|
|
99
|
-
</p>
|
|
100
|
-
<Button href="/login">
|
|
101
|
-
Go to sign in
|
|
102
|
-
</Button>
|
|
93
|
+
<div :else>
|
|
94
|
+
<div :if="error()" role="alert" class="mb-4 p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 rounded-lg dark:border-red-800">
|
|
95
|
+
<div class="flex gap-2 items-center">
|
|
96
|
+
<div class="h-4 w-4 text-red-600 dark:text-red-400 i-hugeicons-alert-circle"></div>
|
|
97
|
+
<p class="text-red-600 text-sm dark:text-red-400">{{ error() }}</p>
|
|
103
98
|
</div>
|
|
104
99
|
</div>
|
|
105
100
|
|
|
106
|
-
<
|
|
107
|
-
<div
|
|
108
|
-
<
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
101
|
+
<form @submit.prevent="handleSubmit">
|
|
102
|
+
<div class="mb-4">
|
|
103
|
+
<Input
|
|
104
|
+
type="password"
|
|
105
|
+
label="New password"
|
|
106
|
+
placeholder="At least 8 characters"
|
|
107
|
+
autocomplete="new-password"
|
|
108
|
+
v-model:value="password"
|
|
109
|
+
required
|
|
110
|
+
:disabled="isLoading()"
|
|
111
|
+
/>
|
|
112
112
|
</div>
|
|
113
113
|
|
|
114
|
-
<
|
|
115
|
-
<
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
<div class="mb-6">
|
|
128
|
-
<Input
|
|
129
|
-
type="password"
|
|
130
|
-
label="Confirm new password"
|
|
131
|
-
placeholder="Repeat your new password"
|
|
132
|
-
autocomplete="new-password"
|
|
133
|
-
v-model:value="confirmation"
|
|
134
|
-
:error="mismatch() ? 'Both passwords must match' : ''"
|
|
135
|
-
required
|
|
136
|
-
:disabled="isLoading()"
|
|
137
|
-
/>
|
|
138
|
-
</div>
|
|
139
|
-
|
|
140
|
-
<Button
|
|
141
|
-
type="submit"
|
|
142
|
-
variant="primary"
|
|
143
|
-
size="lg"
|
|
144
|
-
fullWidth
|
|
145
|
-
:loading="isLoading()"
|
|
146
|
-
:disabled="!canSubmit()"
|
|
147
|
-
>
|
|
148
|
-
<span :if="isLoading()">Saving...</span>
|
|
149
|
-
<span :if="!isLoading()">Change password</span>
|
|
150
|
-
</Button>
|
|
151
|
-
</form>
|
|
152
|
-
</div>
|
|
153
|
-
</div>
|
|
114
|
+
<div class="mb-6">
|
|
115
|
+
<Input
|
|
116
|
+
type="password"
|
|
117
|
+
label="Confirm new password"
|
|
118
|
+
placeholder="Repeat your new password"
|
|
119
|
+
autocomplete="new-password"
|
|
120
|
+
v-model:value="confirmation"
|
|
121
|
+
:error="mismatch() ? 'Both passwords must match' : ''"
|
|
122
|
+
required
|
|
123
|
+
:disabled="isLoading()"
|
|
124
|
+
/>
|
|
125
|
+
</div>
|
|
154
126
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
127
|
+
<Button
|
|
128
|
+
type="submit"
|
|
129
|
+
variant="primary"
|
|
130
|
+
size="lg"
|
|
131
|
+
fullWidth
|
|
132
|
+
:loading="isLoading()"
|
|
133
|
+
:disabled="!canSubmit()"
|
|
134
|
+
>
|
|
135
|
+
<span :if="isLoading()">Saving...</span>
|
|
136
|
+
<span :if="!isLoading()">Change password</span>
|
|
137
|
+
</Button>
|
|
138
|
+
</form>
|
|
139
|
+
</div>
|
|
162
140
|
</div>
|
|
163
|
-
|
|
141
|
+
|
|
142
|
+
<!-- Back to Login -->
|
|
143
|
+
<p class="mt-6 text-center text-neutral-500 text-sm dark:text-neutral-400">
|
|
144
|
+
<a href="/login" class="inline-flex gap-1 items-center font-medium text-blue-600 dark:text-blue-400 hover:text-blue-500 dark:hover:text-blue-300">
|
|
145
|
+
<div class="h-4 w-4 i-hugeicons-arrow-left-01"></div>
|
|
146
|
+
Back to sign in
|
|
147
|
+
</a>
|
|
148
|
+
</p>
|
|
149
|
+
</AuthCard>
|
|
@@ -84,21 +84,17 @@ onMount(() => {
|
|
|
84
84
|
</script>
|
|
85
85
|
|
|
86
86
|
<div class="space-y-6">
|
|
87
|
-
<
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
<
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
Clear
|
|
99
|
-
</Button>
|
|
100
|
-
</div>
|
|
101
|
-
</header>
|
|
87
|
+
<PageHeader title="Buddy" description="Ask framework questions through your configured Stacks AI provider.">
|
|
88
|
+
<div class="flex gap-2 items-center">
|
|
89
|
+
<span :class="'inline-flex items-center px-2.5 py-1 font-medium text-xs rounded-full ' + (chatState()?.configured ? 'text-green-700 bg-green-100 dark:text-green-300 dark:bg-green-950' : 'text-amber-700 bg-amber-100 dark:text-amber-300 dark:bg-amber-950')">
|
|
90
|
+
<span :class="'mr-1.5 h-1.5 w-1.5 rounded-full ' + (chatState()?.configured ? 'bg-green-500' : 'bg-amber-500')"></span>
|
|
91
|
+
{{ providerName() }} {{ chatState()?.configured ? 'ready' : 'needs configuration' }}
|
|
92
|
+
</span>
|
|
93
|
+
<Button :if="messages().length > 0" variant="secondary" size="sm" @click="clearHistory">
|
|
94
|
+
Clear
|
|
95
|
+
</Button>
|
|
96
|
+
</div>
|
|
97
|
+
</PageHeader>
|
|
102
98
|
|
|
103
99
|
<div :if="loadError()" class="p-4 text-red-700 text-sm dark:text-red-300 bg-red-50 dark:bg-red-950/30 border border-red-200 rounded-lg dark:border-red-900">
|
|
104
100
|
{{ loadError() }}
|
|
@@ -239,29 +239,17 @@ onMount(() => {
|
|
|
239
239
|
</script>
|
|
240
240
|
|
|
241
241
|
<div class="space-y-6">
|
|
242
|
-
<
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
</
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
<Button tag="a" variant="secondary" :href="exportHref()" :download="'product-categories-' + new Date().toISOString().slice(0, 10) + '.csv'"><span class="h-4 w-4 i-hugeicons-download-04"></span>Export filtered</Button>
|
|
250
|
-
<Button @click="openAdd()"><span class="h-4 w-4 i-hugeicons-add-01"></span>Add category</Button>
|
|
251
|
-
</div>
|
|
252
|
-
</header>
|
|
242
|
+
<PageHeader title="Product Categories" description="Manage the native Category hierarchy, display order, and storefront availability.">
|
|
243
|
+
<div class="flex flex-wrap gap-2">
|
|
244
|
+
<Button variant="secondary" :loading="loading()" @click="loadCategories()"><span :if="!loading()" class="h-4 w-4 i-hugeicons-refresh"></span>Refresh</Button>
|
|
245
|
+
<Button tag="a" variant="secondary" :href="exportHref()" :download="'product-categories-' + new Date().toISOString().slice(0, 10) + '.csv'"><span class="h-4 w-4 i-hugeicons-download-04"></span>Export filtered</Button>
|
|
246
|
+
<Button @click="openAdd()"><span class="h-4 w-4 i-hugeicons-add-01"></span>Add category</Button>
|
|
247
|
+
</div>
|
|
248
|
+
</PageHeader>
|
|
253
249
|
|
|
254
250
|
<div :if="loadError()" class="p-4 text-red-700 text-sm dark:text-red-300 bg-red-50 dark:bg-red-950/30 border border-red-200 rounded-lg dark:border-red-900">{{ loadError() }}</div>
|
|
255
251
|
|
|
256
|
-
<
|
|
257
|
-
<template :for="item in metricCards()" :key="item.label">
|
|
258
|
-
<article class="p-4 bg-white dark:bg-neutral-800 border border-gray-200 rounded-lg dark:border-neutral-700">
|
|
259
|
-
<p class="text-gray-500 text-xs dark:text-neutral-400">{{ item.label }}</p>
|
|
260
|
-
<p class="mt-2 font-semibold text-2xl text-gray-900 dark:text-white">{{ item.value }}</p>
|
|
261
|
-
<p class="mt-1 text-gray-400 text-xs dark:text-neutral-500">{{ item.detail }}</p>
|
|
262
|
-
</article>
|
|
263
|
-
</template>
|
|
264
|
-
</section>
|
|
252
|
+
<MetricCards label="Product category metrics" columns="grid-cols-2 lg:grid-cols-4" :items="metricCards()" />
|
|
265
253
|
|
|
266
254
|
<CommerceCategoryHierarchy :records="records()" />
|
|
267
255
|
|
|
@@ -250,29 +250,17 @@ onMount(() => {
|
|
|
250
250
|
</script>
|
|
251
251
|
|
|
252
252
|
<div class="space-y-6">
|
|
253
|
-
<
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
</
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
<Button tag="a" variant="secondary" :href="exportHref()" :download="'coupons-' + new Date().toISOString().slice(0, 10) + '.csv'"><span class="h-4 w-4 i-hugeicons-download-04"></span>Export filtered</Button>
|
|
261
|
-
<Button @click="openAdd()"><span class="h-4 w-4 i-hugeicons-add-01"></span>Add coupon</Button>
|
|
262
|
-
</div>
|
|
263
|
-
</header>
|
|
253
|
+
<PageHeader title="Coupons" description="Manage native Coupon records, availability, limits, and redemption state.">
|
|
254
|
+
<div class="flex flex-wrap gap-2">
|
|
255
|
+
<Button variant="secondary" :loading="loading()" @click="loadCoupons()"><span :if="!loading()" class="h-4 w-4 i-hugeicons-refresh"></span>Refresh</Button>
|
|
256
|
+
<Button tag="a" variant="secondary" :href="exportHref()" :download="'coupons-' + new Date().toISOString().slice(0, 10) + '.csv'"><span class="h-4 w-4 i-hugeicons-download-04"></span>Export filtered</Button>
|
|
257
|
+
<Button @click="openAdd()"><span class="h-4 w-4 i-hugeicons-add-01"></span>Add coupon</Button>
|
|
258
|
+
</div>
|
|
259
|
+
</PageHeader>
|
|
264
260
|
|
|
265
261
|
<div :if="loadError()" class="p-4 text-red-700 text-sm dark:text-red-300 bg-red-50 dark:bg-red-950/30 border border-red-200 rounded-lg dark:border-red-900">{{ loadError() }}</div>
|
|
266
262
|
|
|
267
|
-
<
|
|
268
|
-
<template :for="item in metricCards()" :key="item.label">
|
|
269
|
-
<article class="p-4 bg-white dark:bg-neutral-800 border border-gray-200 rounded-lg dark:border-neutral-700">
|
|
270
|
-
<p class="text-gray-500 text-xs dark:text-neutral-400">{{ item.label }}</p>
|
|
271
|
-
<p class="mt-2 font-semibold text-2xl text-gray-900 dark:text-white">{{ item.value }}</p>
|
|
272
|
-
<p class="mt-1 text-gray-400 text-xs dark:text-neutral-500">{{ item.detail }}</p>
|
|
273
|
-
</article>
|
|
274
|
-
</template>
|
|
275
|
-
</section>
|
|
263
|
+
<MetricCards label="Coupon metrics" columns="grid-cols-2 lg:grid-cols-4" :items="metricCards()" />
|
|
276
264
|
|
|
277
265
|
<CommerceCouponBreakdown :records="records()" />
|
|
278
266
|
|
|
@@ -252,29 +252,17 @@ onMount(() => {
|
|
|
252
252
|
</script>
|
|
253
253
|
|
|
254
254
|
<div class="space-y-6">
|
|
255
|
-
<
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
</
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
<Button tag="a" variant="secondary" :href="exportHref()" :download="'customers-' + new Date().toISOString().slice(0, 10) + '.csv'"><span class="h-4 w-4 i-hugeicons-download-04"></span>Export filtered</Button>
|
|
263
|
-
<Button @click="openAdd()"><span class="h-4 w-4 i-hugeicons-add-01"></span>Add customer</Button>
|
|
264
|
-
</div>
|
|
265
|
-
</header>
|
|
255
|
+
<PageHeader title="Customers" description="Manage native Customer records, contact details, status, and recorded spend.">
|
|
256
|
+
<div class="flex flex-wrap gap-2">
|
|
257
|
+
<Button variant="secondary" :loading="loading()" @click="loadCustomers()"><span :if="!loading()" class="h-4 w-4 i-hugeicons-refresh"></span>Refresh</Button>
|
|
258
|
+
<Button tag="a" variant="secondary" :href="exportHref()" :download="'customers-' + new Date().toISOString().slice(0, 10) + '.csv'"><span class="h-4 w-4 i-hugeicons-download-04"></span>Export filtered</Button>
|
|
259
|
+
<Button @click="openAdd()"><span class="h-4 w-4 i-hugeicons-add-01"></span>Add customer</Button>
|
|
260
|
+
</div>
|
|
261
|
+
</PageHeader>
|
|
266
262
|
|
|
267
263
|
<div :if="loadError()" class="p-4 text-red-700 text-sm dark:text-red-300 bg-red-50 dark:bg-red-950/30 border border-red-200 rounded-lg dark:border-red-900">{{ loadError() }}</div>
|
|
268
264
|
|
|
269
|
-
<
|
|
270
|
-
<template :for="item in metricCards()" :key="item.label">
|
|
271
|
-
<article class="p-4 bg-white dark:bg-neutral-800 border border-gray-200 rounded-lg dark:border-neutral-700">
|
|
272
|
-
<p class="text-gray-500 text-xs dark:text-neutral-400">{{ item.label }}</p>
|
|
273
|
-
<p class="mt-2 font-semibold text-2xl text-gray-900 dark:text-white">{{ item.value }}</p>
|
|
274
|
-
<p class="mt-1 text-gray-400 text-xs dark:text-neutral-500">{{ item.detail }}</p>
|
|
275
|
-
</article>
|
|
276
|
-
</template>
|
|
277
|
-
</section>
|
|
265
|
+
<MetricCards label="Customer metrics" columns="grid-cols-2 lg:grid-cols-4" :items="metricCards()" />
|
|
278
266
|
|
|
279
267
|
<section class="space-y-3">
|
|
280
268
|
<div class="grid gap-3 grid-cols-1 sm:grid-cols-2 lg:grid-cols-4">
|
|
@@ -266,29 +266,17 @@ onMount(() => {
|
|
|
266
266
|
</script>
|
|
267
267
|
|
|
268
268
|
<div class="space-y-6">
|
|
269
|
-
<
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
</
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
<Button tag="a" variant="secondary" :href="exportHref()" :download="'gift-cards-' + new Date().toISOString().slice(0, 10) + '.csv'"><span class="h-4 w-4 i-hugeicons-download-04"></span>Export filtered</Button>
|
|
277
|
-
<Button @click="openAdd()"><span class="h-4 w-4 i-hugeicons-add-01"></span>Add gift card</Button>
|
|
278
|
-
</div>
|
|
279
|
-
</header>
|
|
269
|
+
<PageHeader title="Gift Cards" description="Manage native GiftCard balances, recipients, delivery, and lifecycle state.">
|
|
270
|
+
<div class="flex flex-wrap gap-2">
|
|
271
|
+
<Button variant="secondary" :loading="loading()" @click="loadGiftCards()"><span :if="!loading()" class="h-4 w-4 i-hugeicons-refresh"></span>Refresh</Button>
|
|
272
|
+
<Button tag="a" variant="secondary" :href="exportHref()" :download="'gift-cards-' + new Date().toISOString().slice(0, 10) + '.csv'"><span class="h-4 w-4 i-hugeicons-download-04"></span>Export filtered</Button>
|
|
273
|
+
<Button @click="openAdd()"><span class="h-4 w-4 i-hugeicons-add-01"></span>Add gift card</Button>
|
|
274
|
+
</div>
|
|
275
|
+
</PageHeader>
|
|
280
276
|
|
|
281
277
|
<div :if="loadError()" class="p-4 text-red-700 text-sm dark:text-red-300 bg-red-50 dark:bg-red-950/30 border border-red-200 rounded-lg dark:border-red-900">{{ loadError() }}</div>
|
|
282
278
|
|
|
283
|
-
<
|
|
284
|
-
<template :for="item in metricCards()" :key="item.label">
|
|
285
|
-
<article class="p-4 bg-white dark:bg-neutral-800 border border-gray-200 rounded-lg dark:border-neutral-700">
|
|
286
|
-
<p class="text-gray-500 text-xs dark:text-neutral-400">{{ item.label }}</p>
|
|
287
|
-
<p class="mt-2 font-semibold text-2xl text-gray-900 dark:text-white">{{ item.value }}</p>
|
|
288
|
-
<p class="mt-1 text-gray-400 text-xs dark:text-neutral-500">{{ item.detail }}</p>
|
|
289
|
-
</article>
|
|
290
|
-
</template>
|
|
291
|
-
</section>
|
|
279
|
+
<MetricCards label="Gift card metrics" columns="grid-cols-2 lg:grid-cols-4" :items="metricCards()" />
|
|
292
280
|
|
|
293
281
|
<CommerceGiftCardBreakdown :summary="summary()" />
|
|
294
282
|
|
|
@@ -175,33 +175,22 @@ onMount(() => {
|
|
|
175
175
|
</script>
|
|
176
176
|
|
|
177
177
|
<div class="space-y-6">
|
|
178
|
-
<
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
<
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
Add manufacturer
|
|
191
|
-
</Button>
|
|
192
|
-
</div>
|
|
193
|
-
</header>
|
|
178
|
+
<PageHeader title="Manufacturers" description="Manage native Manufacturer records and their product relationships.">
|
|
179
|
+
<div class="flex gap-2">
|
|
180
|
+
<Button variant="secondary" :loading="loading()" @click="loadManufacturers">
|
|
181
|
+
<span :if="!loading()" class="h-4 w-4 i-hugeicons-refresh"></span>
|
|
182
|
+
Refresh
|
|
183
|
+
</Button>
|
|
184
|
+
<Button @click="openAdd()">
|
|
185
|
+
<span class="h-4 w-4 i-hugeicons-add-01"></span>
|
|
186
|
+
Add manufacturer
|
|
187
|
+
</Button>
|
|
188
|
+
</div>
|
|
189
|
+
</PageHeader>
|
|
194
190
|
|
|
195
191
|
<div :if="loadError()" class="p-4 text-red-700 text-sm dark:text-red-300 bg-red-50 dark:bg-red-950/30 border border-red-200 rounded-lg dark:border-red-900">{{ loadError() }}</div>
|
|
196
192
|
|
|
197
|
-
<
|
|
198
|
-
<template :for="item in metricCards()" :key="item.label">
|
|
199
|
-
<article class="p-4 bg-white dark:bg-neutral-800 border border-gray-200 rounded-lg dark:border-neutral-700">
|
|
200
|
-
<p class="text-gray-500 text-xs dark:text-neutral-400">{{ item.label }}</p>
|
|
201
|
-
<p class="mt-2 font-semibold text-2xl text-gray-900 dark:text-white">{{ item.value }}</p>
|
|
202
|
-
</article>
|
|
203
|
-
</template>
|
|
204
|
-
</section>
|
|
193
|
+
<MetricCards label="Manufacturer metrics" columns="grid-cols-2 lg:grid-cols-4" :items="metricCards()" />
|
|
205
194
|
|
|
206
195
|
<section class="space-y-3">
|
|
207
196
|
<div class="grid gap-3 grid-cols-1 sm:grid-cols-2 xl:grid-cols-4">
|
|
@@ -293,29 +293,17 @@ onMount(() => {
|
|
|
293
293
|
</script>
|
|
294
294
|
|
|
295
295
|
<div class="space-y-6">
|
|
296
|
-
<
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
</
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
<Button tag="a" variant="secondary" :href="exportHref()" :download="'orders-' + new Date().toISOString().slice(0, 10) + '.csv'"><span class="h-4 w-4 i-hugeicons-download-04"></span>Export filtered</Button>
|
|
304
|
-
<Button @click="openAdd()"><span class="h-4 w-4 i-hugeicons-add-01"></span>Add order</Button>
|
|
305
|
-
</div>
|
|
306
|
-
</header>
|
|
296
|
+
<PageHeader title="Orders" description="Manage native Order records, customer assignments, totals, and fulfillment state.">
|
|
297
|
+
<div class="flex flex-wrap gap-2">
|
|
298
|
+
<Button variant="secondary" :loading="loading()" @click="loadOrders()"><span :if="!loading()" class="h-4 w-4 i-hugeicons-refresh"></span>Refresh</Button>
|
|
299
|
+
<Button tag="a" variant="secondary" :href="exportHref()" :download="'orders-' + new Date().toISOString().slice(0, 10) + '.csv'"><span class="h-4 w-4 i-hugeicons-download-04"></span>Export filtered</Button>
|
|
300
|
+
<Button @click="openAdd()"><span class="h-4 w-4 i-hugeicons-add-01"></span>Add order</Button>
|
|
301
|
+
</div>
|
|
302
|
+
</PageHeader>
|
|
307
303
|
|
|
308
304
|
<div :if="loadError()" class="p-4 text-red-700 text-sm dark:text-red-300 bg-red-50 dark:bg-red-950/30 border border-red-200 rounded-lg dark:border-red-900">{{ loadError() }}</div>
|
|
309
305
|
|
|
310
|
-
<
|
|
311
|
-
<template :for="item in metricCards()" :key="item.label">
|
|
312
|
-
<article class="p-4 bg-white dark:bg-neutral-800 border border-gray-200 rounded-lg dark:border-neutral-700">
|
|
313
|
-
<p class="text-gray-500 text-xs dark:text-neutral-400">{{ item.label }}</p>
|
|
314
|
-
<p class="mt-2 font-semibold text-2xl text-gray-900 dark:text-white">{{ item.value }}</p>
|
|
315
|
-
<p class="mt-1 text-gray-400 text-xs dark:text-neutral-500">{{ item.detail }}</p>
|
|
316
|
-
</article>
|
|
317
|
-
</template>
|
|
318
|
-
</section>
|
|
306
|
+
<MetricCards label="Order metrics" columns="grid-cols-2 lg:grid-cols-5" :items="metricCards()" />
|
|
319
307
|
|
|
320
308
|
<section :if="summary().currencyTotals.length > 0" aria-label="Order currency totals" class="flex flex-wrap gap-2 items-center">
|
|
321
309
|
<span class="text-gray-500 text-xs dark:text-neutral-400">Recorded order value</span>
|
|
@@ -62,27 +62,23 @@ onMount(() => {
|
|
|
62
62
|
</script>
|
|
63
63
|
|
|
64
64
|
<div class="space-y-8">
|
|
65
|
-
<
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
<
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
</
|
|
75
|
-
<
|
|
76
|
-
<
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
<option value="all">All time</option>
|
|
83
|
-
</select>
|
|
84
|
-
</div>
|
|
85
|
-
</header>
|
|
65
|
+
<PageHeader title="Commerce Dashboard" :description="`Persisted order performance for ${rangeLabel().toLowerCase()}.`">
|
|
66
|
+
<div class="flex gap-2">
|
|
67
|
+
<Button variant="secondary" :loading="loading()" @click="loadDashboard">
|
|
68
|
+
<span :if="!loading()" class="h-4 w-4 i-hugeicons-refresh"></span>
|
|
69
|
+
Refresh
|
|
70
|
+
</Button>
|
|
71
|
+
<label class="sr-only" for="commerce-dashboard-range">Reporting range</label>
|
|
72
|
+
<select id="commerce-dashboard-range" x-model="range" class="block pl-3 pr-10 py-2 text-gray-900 sm:leading-6 sm:text-sm dark:text-white dark:bg-neutral-800 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-700 focus:ring-2 focus:ring-blue-600" @change="reloadSelectedRange($event)">
|
|
73
|
+
<option value="today">Today</option>
|
|
74
|
+
<option value="7d">Last 7 days</option>
|
|
75
|
+
<option value="30d">Last 30 days</option>
|
|
76
|
+
<option value="90d">Last 90 days</option>
|
|
77
|
+
<option value="year">Last year</option>
|
|
78
|
+
<option value="all">All time</option>
|
|
79
|
+
</select>
|
|
80
|
+
</div>
|
|
81
|
+
</PageHeader>
|
|
86
82
|
|
|
87
83
|
<div :if="loadError()" class="px-4 py-3 text-red-700 text-sm dark:text-red-300 bg-red-50 dark:bg-red-950/30 border border-red-300 rounded-md dark:border-red-800">
|
|
88
84
|
{{ loadError() }}
|
|
@@ -170,28 +170,16 @@ onMount(() => {
|
|
|
170
170
|
</script>
|
|
171
171
|
|
|
172
172
|
<div class="space-y-6">
|
|
173
|
-
<
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
<Button variant="secondary" :loading="loading()" @click="loadPayments"><span :if="!loading()" class="h-4 w-4 i-hugeicons-refresh"></span>Refresh</Button>
|
|
180
|
-
<Button tag="a" :href="exportHref()" :download="exportFilename()"><span class="h-4 w-4 i-hugeicons-download-04"></span>Export current view</Button>
|
|
181
|
-
</div>
|
|
182
|
-
</header>
|
|
173
|
+
<PageHeader title="Payments" description="Inspect native Payment records, export the current view, and record confirmed refunds.">
|
|
174
|
+
<div class="flex flex-wrap gap-2">
|
|
175
|
+
<Button variant="secondary" :loading="loading()" @click="loadPayments"><span :if="!loading()" class="h-4 w-4 i-hugeicons-refresh"></span>Refresh</Button>
|
|
176
|
+
<Button tag="a" :href="exportHref()" :download="exportFilename()"><span class="h-4 w-4 i-hugeicons-download-04"></span>Export current view</Button>
|
|
177
|
+
</div>
|
|
178
|
+
</PageHeader>
|
|
183
179
|
|
|
184
180
|
<div :if="loadError()" class="p-4 text-red-700 text-sm dark:text-red-300 bg-red-50 dark:bg-red-950/30 border border-red-200 rounded-lg dark:border-red-900">{{ loadError() }}</div>
|
|
185
181
|
|
|
186
|
-
<
|
|
187
|
-
<template :for="item in metricCards()" :key="item.label">
|
|
188
|
-
<article class="p-4 bg-white dark:bg-neutral-800 border border-gray-200 rounded-lg dark:border-neutral-700">
|
|
189
|
-
<p class="text-gray-500 text-xs dark:text-neutral-400">{{ item.label }}</p>
|
|
190
|
-
<p class="mt-2 font-semibold text-2xl text-gray-900 dark:text-white">{{ item.value }}</p>
|
|
191
|
-
<p class="mt-1 text-gray-400 text-xs dark:text-neutral-500">{{ item.detail }}</p>
|
|
192
|
-
</article>
|
|
193
|
-
</template>
|
|
194
|
-
</section>
|
|
182
|
+
<MetricCards label="Payment metrics" columns="grid-cols-2 lg:grid-cols-4" :items="metricCards()" />
|
|
195
183
|
|
|
196
184
|
<CommercePaymentsBreakdown :records="visibleRecords()" />
|
|
197
185
|
|