@stacksjs/defaults 0.75.242 → 0.75.243
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-actions/SKILL.md +1 -1
- package/ai/skills/stacks-native/CATALOG.md +6 -6
- package/app/Actions/Dashboard/hq-read.ts +144 -0
- package/ide/vscode/package.json +1 -1
- package/package.json +2 -2
- package/resources/components/Dashboard/Commerce/CommerceManufacturersTable.stx +58 -61
- package/resources/components/Dashboard/Commerce/CommerceUnitsTable.stx +59 -61
- package/resources/components/Dashboard/Commerce/ProductWaitlistTable.stx +49 -61
- package/resources/components/Dashboard/Commerce/RestaurantWaitlistTable.stx +66 -71
- package/resources/components/Dashboard/Library/DependenciesDashboard.stx +68 -14
- package/resources/components/Dashboard/Realtime/RealtimeDashboard.stx +25 -26
- package/resources/components/Dashboard/UI/Table.stx +244 -9
- package/stx-components-plugin.ts +8 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: stacks-actions
|
|
3
|
-
description: Use when working with Stacks server actions - creating actions in app/Actions/, auto-generated API actions from the useApi model trait, the
|
|
3
|
+
description: Use when working with Stacks server actions - creating actions in app/Actions/, auto-generated API actions from the useApi model trait, the 673 default framework actions (auth, dashboard, commerce, content, deployment, jobs), action request/response handling, or action registration. Covers @stacksjs/actions and storage/framework/defaults/app/Actions/.
|
|
4
4
|
license: MIT
|
|
5
5
|
compatibility: Bun >= 1.3.0, TypeScript
|
|
6
6
|
allowed-tools: Read Edit Write Bash Grep Glob
|
|
@@ -11,7 +11,7 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
|
|
|
11
11
|
| Package | Task guidance | Source entry | Retained tests |
|
|
12
12
|
|---|---|---|---|
|
|
13
13
|
| `@stacksjs/action-runner` | [`stacks-actions`](../stacks-actions/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/action-runner/src/index.ts) | 1 |
|
|
14
|
-
| `@stacksjs/actions` | [`stacks-actions`](../stacks-actions/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/index.ts) |
|
|
14
|
+
| `@stacksjs/actions` | [`stacks-actions`](../stacks-actions/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/index.ts) | 75 |
|
|
15
15
|
| `@stacksjs/ai` | [`stacks-ai`](../stacks-ai/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/index.ts) | 17 |
|
|
16
16
|
| `@stacksjs/alias` | [`stacks-alias`](../stacks-alias/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/alias/src/index.ts) | 1 |
|
|
17
17
|
| `@stacksjs/analytics` | [`stacks-analytics`](../stacks-analytics/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/analytics/src/index.ts) | 6 |
|
|
@@ -21,7 +21,7 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
|
|
|
21
21
|
| `@stacksjs/auth` | [`stacks-auth`](../stacks-auth/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/index.ts) | 119 |
|
|
22
22
|
| `@stacksjs/browser` | [`stacks-browser`](../stacks-browser/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/browser/src/index.ts) | 8 |
|
|
23
23
|
| `@stacksjs/browser-extension` | [`stacks-browser-extension`](../stacks-browser-extension/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/browser-extension/src/index.ts) | 7 |
|
|
24
|
-
| `@stacksjs/buddy` | [`stacks-buddy`](../stacks-buddy/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/buddy/src/index.ts) |
|
|
24
|
+
| `@stacksjs/buddy` | [`stacks-buddy`](../stacks-buddy/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/buddy/src/index.ts) | 152 |
|
|
25
25
|
| `@stacksjs/build` | [`stacks-build`](../stacks-build/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/build/src/index.ts) | 2 |
|
|
26
26
|
| `@stacksjs/cache` | [`stacks-cache`](../stacks-cache/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/cache/src/index.ts) | 11 |
|
|
27
27
|
| `@stacksjs/calendar-api` | [`stacks-calendar`](../stacks-calendar/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/calendar-api/src/index.ts) | 2 |
|
|
@@ -65,7 +65,7 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
|
|
|
65
65
|
| `@stacksjs/newsletter` | [`stacks-newsletter`](../stacks-newsletter/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/newsletter/src/index.ts) | 7 |
|
|
66
66
|
| `@stacksjs/notifications` | [`stacks-notifications`](../stacks-notifications/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/notifications/src/index.ts) | 16 |
|
|
67
67
|
| `@stacksjs/objects` | [`stacks-objects`](../stacks-objects/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/objects/src/index.ts) | 4 |
|
|
68
|
-
| `@stacksjs/orm` | [`stacks-orm`](../stacks-orm/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/index.ts) |
|
|
68
|
+
| `@stacksjs/orm` | [`stacks-orm`](../stacks-orm/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/index.ts) | 63 |
|
|
69
69
|
| `@stacksjs/pagination` | [`stacks-pagination`](../stacks-pagination/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/pagination/src/index.ts) | 0 |
|
|
70
70
|
| `@stacksjs/path` | [`stacks-path`](../stacks-path/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/path/src/index.ts) | 11 |
|
|
71
71
|
| `@stacksjs/payments` | [`stacks-payments`](../stacks-payments/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/index.ts) | 28 |
|
|
@@ -119,7 +119,7 @@ Declared runtime exports: `BlogAdminError`, `DEFAULT_IOS_DEPENDENCIES`, `DEFAULT
|
|
|
119
119
|
|
|
120
120
|
Local source modules: [src/action.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/action.ts), [src/add.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/add.ts), [src/blog-admin.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/blog-admin.ts), [src/build/ios-toolchain.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/build/ios-toolchain.ts), [src/commit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/commit.ts), [src/dev/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/dev/index.ts), [src/discover-packages.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/discover-packages.ts), [src/generate/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/generate/index.ts), [src/github-release.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/github-release.ts), [src/helpers/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/helpers/index.ts), [src/library/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/library/index.ts), [src/lint/lint.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/lint/lint.ts), [src/lint/stx-gate.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/lint/stx-gate.ts), [src/make-command.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/make-command.ts), [src/make-job.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/make-job.ts), [src/make-policy.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/make-policy.ts), [src/make-resource.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/make-resource.ts), [src/make.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/make.ts), [src/scaffold-crud.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/scaffold-crud.ts), [src/setup/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/setup/index.ts), [src/stacks.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/stacks.ts), [src/upgrade/package-project.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/upgrade/package-project.ts), [src/upgrade/route-actions.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/upgrade/route-actions.ts).
|
|
121
121
|
|
|
122
|
-
Evidence directory: [
|
|
122
|
+
Evidence directory: [75 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
|
|
123
123
|
|
|
124
124
|
### @stacksjs/ai
|
|
125
125
|
|
|
@@ -215,7 +215,7 @@ Read the entrypoint and package export map for re-exported or type-only surfaces
|
|
|
215
215
|
|
|
216
216
|
Local source modules: [src/commands/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/buddy/src/commands/index.ts).
|
|
217
217
|
|
|
218
|
-
Evidence directory: [
|
|
218
|
+
Evidence directory: [152 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/buddy/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
|
|
219
219
|
|
|
220
220
|
### @stacksjs/build
|
|
221
221
|
|
|
@@ -633,7 +633,7 @@ Declared runtime exports: `Activity`, `AnalyticsEvent`, `Auction`, `AuctionItem`
|
|
|
633
633
|
|
|
634
634
|
Local source modules: [src/auto-crud.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/auto-crud.ts), [src/batch-loader.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/batch-loader.ts), [src/db.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/db.ts), [src/define-model.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/define-model.ts), [src/extend-model.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/extend-model.ts), [src/gdpr/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/gdpr/index.ts), [src/generate-database-schema.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/generate-database-schema.ts), [src/locked-row.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/locked-row.ts), [src/messaging.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/messaging.ts), [src/model-types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/model-types.ts), [src/ownership.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/ownership.ts), [src/paginator-request.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/paginator-request.ts), [src/row-token.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/row-token.ts), [src/subquery.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/subquery.ts), [src/traits/audit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/audit.ts), [src/traits/billable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/billable.ts), [src/traits/categorizable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/categorizable.ts), [src/traits/commentable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/commentable.ts), [src/traits/likeable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/likeable.ts), [src/traits/taggable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/taggable.ts), [src/transaction.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/transaction.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/types.ts), [src/utils/encrypted.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/utils/encrypted.ts), [src/utils/prunable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/utils/prunable.ts).
|
|
635
635
|
|
|
636
|
-
Evidence directory: [
|
|
636
|
+
Evidence directory: [63 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
|
|
637
637
|
|
|
638
638
|
### @stacksjs/pagination
|
|
639
639
|
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import type { DashboardHqDriverOptions } from '@stacksjs/types'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The one way a dashboard section talks to a hosted HQ product.
|
|
5
|
+
*
|
|
6
|
+
* `dashboard-provider.ts` decides *which* provider a section reads from and
|
|
7
|
+
* guarantees that a remote one cannot take the page down. This module is the
|
|
8
|
+
* other half: how a remote read is actually performed, so that each domain
|
|
9
|
+
* driver is a path and a shape rather than its own copy of base-URL joining,
|
|
10
|
+
* header handling and failure translation.
|
|
11
|
+
*
|
|
12
|
+
* Everything here exists to make one of `readThroughProvider`'s three degrade
|
|
13
|
+
* paths real:
|
|
14
|
+
*
|
|
15
|
+
* it rejects — an unreachable host, a non-2xx answer, or a body that
|
|
16
|
+
* is not JSON, all raised as {@link HqReadError}
|
|
17
|
+
* it never answers — a hung connection, aborted at `timeoutMs`. Nothing
|
|
18
|
+
* else in the seam imposes a deadline, so without this
|
|
19
|
+
* the "never answers" case was documented rather than
|
|
20
|
+
* handled: the request simply hung and took the
|
|
21
|
+
* section's request with it
|
|
22
|
+
* the wrong shape — left to the caller, which knows what its section
|
|
23
|
+
* renders; this module parses JSON and no more
|
|
24
|
+
*
|
|
25
|
+
* The read key only ever travels in `Authorization`. A URL is logged by
|
|
26
|
+
* proxies, kept in browser history and attached to error reports, and a
|
|
27
|
+
* read-scoped key is still a credential, so it never becomes a query
|
|
28
|
+
* parameter even though several hosted APIs would accept one.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/** How long a hosted read may take before it is treated as unreachable. */
|
|
32
|
+
export const HQ_DEFAULT_TIMEOUT_MS = 10_000
|
|
33
|
+
|
|
34
|
+
/** The upper bound on a configured timeout, so one cannot hold a section open. */
|
|
35
|
+
export const HQ_MAX_TIMEOUT_MS = 60_000
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* A hosted read that did not produce a payload.
|
|
39
|
+
*
|
|
40
|
+
* Carries `status` when the product answered and the answer was not a 2xx, so
|
|
41
|
+
* an operator reading the log can tell a misconfigured key (401/403) from a
|
|
42
|
+
* wrong project id (404) from the product being unwell (5xx). `status` is
|
|
43
|
+
* absent when no answer arrived at all.
|
|
44
|
+
*/
|
|
45
|
+
export class HqReadError extends Error {
|
|
46
|
+
readonly status?: number
|
|
47
|
+
readonly url: string
|
|
48
|
+
|
|
49
|
+
constructor(message: string, url: string, status?: number) {
|
|
50
|
+
super(message)
|
|
51
|
+
this.name = 'HqReadError'
|
|
52
|
+
this.url = url
|
|
53
|
+
this.status = status
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Whether the options carry enough to attempt a read at all. */
|
|
58
|
+
export function hqConfigured(options: DashboardHqDriverOptions | null | undefined): boolean {
|
|
59
|
+
return Boolean(options?.baseUrl && options?.token)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* `base` and `path` joined into one URL, with exactly one slash between them.
|
|
64
|
+
*
|
|
65
|
+
* A base URL is hand-written in a config file, so it arrives with or without
|
|
66
|
+
* a trailing slash, and a driver's path is written as a literal that reads
|
|
67
|
+
* best with a leading one. Both spellings have to land on the same address.
|
|
68
|
+
*/
|
|
69
|
+
export function hqUrl(base: string, path: string, query?: Record<string, string | number | undefined>): string {
|
|
70
|
+
const url = new URL(path.replace(/^\/+/, ''), base.endsWith('/') ? base : `${base}/`)
|
|
71
|
+
for (const [key, value] of Object.entries(query ?? {})) {
|
|
72
|
+
if (value !== undefined && value !== '')
|
|
73
|
+
url.searchParams.set(key, String(value))
|
|
74
|
+
}
|
|
75
|
+
return url.toString()
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** A configured timeout, clamped so neither a typo nor a zero disables it. */
|
|
79
|
+
export function hqTimeout(options: DashboardHqDriverOptions | null | undefined): number {
|
|
80
|
+
const asked = Number(options?.timeoutMs)
|
|
81
|
+
if (!Number.isFinite(asked) || asked <= 0)
|
|
82
|
+
return HQ_DEFAULT_TIMEOUT_MS
|
|
83
|
+
return Math.min(HQ_MAX_TIMEOUT_MS, asked)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* One read from a hosted HQ product, as JSON.
|
|
88
|
+
*
|
|
89
|
+
* Throws {@link HqReadError} for every failure, which is what the caller
|
|
90
|
+
* wants: `readThroughProvider` turns a rejection into the section's empty
|
|
91
|
+
* payload with a reason, so a driver never has to handle a failure itself.
|
|
92
|
+
*
|
|
93
|
+
* `fetchImpl` exists for tests. Nothing in the application passes it.
|
|
94
|
+
*/
|
|
95
|
+
export async function hqRead<T = unknown>(
|
|
96
|
+
options: DashboardHqDriverOptions | null | undefined,
|
|
97
|
+
path: string,
|
|
98
|
+
query?: Record<string, string | number | undefined>,
|
|
99
|
+
fetchImpl: typeof fetch = fetch,
|
|
100
|
+
): Promise<T> {
|
|
101
|
+
if (!hqConfigured(options)) {
|
|
102
|
+
// Not a network failure, and worth saying so differently: a section that
|
|
103
|
+
// reads empty because nobody filled in a base URL is a configuration
|
|
104
|
+
// mistake an operator can fix, not an outage to wait out.
|
|
105
|
+
throw new HqReadError('The hosted provider has no baseUrl and token configured.', '')
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const url = hqUrl(options!.baseUrl!, path, query)
|
|
109
|
+
let answer: Response
|
|
110
|
+
try {
|
|
111
|
+
answer = await fetchImpl(url, {
|
|
112
|
+
headers: {
|
|
113
|
+
// The read key, and only here. See the note at the top of this file.
|
|
114
|
+
authorization: `Bearer ${options!.token}`,
|
|
115
|
+
accept: 'application/json',
|
|
116
|
+
},
|
|
117
|
+
signal: AbortSignal.timeout(hqTimeout(options)),
|
|
118
|
+
})
|
|
119
|
+
}
|
|
120
|
+
catch (cause) {
|
|
121
|
+
// An abort and a refused connection are the same thing to a section: no
|
|
122
|
+
// data arrived. They are told apart in the message so the log is useful.
|
|
123
|
+
const aborted = (cause as { name?: string })?.name === 'TimeoutError'
|
|
124
|
+
|| (cause as { name?: string })?.name === 'AbortError'
|
|
125
|
+
throw new HqReadError(
|
|
126
|
+
aborted
|
|
127
|
+
? `The hosted provider did not answer within ${hqTimeout(options)}ms.`
|
|
128
|
+
: `The hosted provider could not be reached: ${(cause as Error)?.message ?? String(cause)}`,
|
|
129
|
+
url,
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (!answer.ok)
|
|
134
|
+
throw new HqReadError(`The hosted provider answered ${answer.status}.`, url, answer.status)
|
|
135
|
+
|
|
136
|
+
try {
|
|
137
|
+
return await answer.json() as T
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
// A 2xx that is not JSON is usually a sign-in page or a proxy's error
|
|
141
|
+
// document, which is a configuration problem wearing a success code.
|
|
142
|
+
throw new HqReadError('The hosted provider answered with something that is not JSON.', url, answer.status)
|
|
143
|
+
}
|
|
144
|
+
}
|
package/ide/vscode/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"publisher": "Stacks",
|
|
3
3
|
"name": "vscode-stacks",
|
|
4
4
|
"displayName": "Stacks",
|
|
5
|
-
"version": "0.75.
|
|
5
|
+
"version": "0.75.243",
|
|
6
6
|
"description": "Stacks, built into VS Code: stx templates, pickier linting and formatting, encrypted env files, the dev server preview and every buddy command. No other extensions required.",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"funding": "https://github.com/sponsors/chrisbbreuer",
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/defaults",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.75.
|
|
5
|
+
"version": "0.75.243",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "git+https://github.com/stacksjs/stacks.git",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@iconify-json/f7": "^1.2.2",
|
|
46
46
|
"@iconify-json/hugeicons": "^1.2.35",
|
|
47
|
-
"@stacksjs/mobile": "0.75.
|
|
47
|
+
"@stacksjs/mobile": "0.75.243",
|
|
48
48
|
"@stacksjs/sanitizer": "^0.2.534",
|
|
49
49
|
"@xterm/addon-fit": "^0.11.0",
|
|
50
50
|
"@xterm/xterm": "^6.0.0",
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
@import('../UI/Table')
|
|
2
|
+
|
|
1
3
|
<script client>
|
|
2
4
|
import type { ManufacturerRecord } from '../../../../app/Actions/Dashboard/Commerce/manufacturer-records'
|
|
3
5
|
|
|
@@ -5,67 +7,62 @@ const records = useReactiveProp('records', [] as ManufacturerRecord[])
|
|
|
5
7
|
const loading = useReactiveProp('loading', false)
|
|
6
8
|
const emit = defineEmits()
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
/**
|
|
11
|
+
* `featured` becomes a flag badge beside the name rather than the starred line
|
|
12
|
+
* it used to be under it. The information is the same and it reads as a table
|
|
13
|
+
* column; the star is dropped because a `cell` slot cannot carry markup yet
|
|
14
|
+
* (stacksjs/stx#2095, stacksjs/stx#2096).
|
|
15
|
+
*
|
|
16
|
+
* `createdAt` is a `date` column, and `UI/Table` now normalises SQLite's
|
|
17
|
+
* space-separated timestamps the way this component used to do for itself.
|
|
18
|
+
*/
|
|
19
|
+
const COLUMNS = [
|
|
20
|
+
{ key: 'name', label: 'Manufacturer', sortable: true, emptyText: 'Unnamed manufacturer', class: 'min-w-48 font-medium text-gray-900 dark:text-white' },
|
|
21
|
+
{
|
|
22
|
+
key: 'featuredFlag',
|
|
23
|
+
label: '',
|
|
24
|
+
type: 'badge' as const,
|
|
25
|
+
emptyText: '',
|
|
26
|
+
badgeClasses: { featured: 'text-blue-700 dark:text-blue-300 bg-blue-50 dark:bg-blue-950/40' },
|
|
27
|
+
badgeLabels: { featured: 'Featured' },
|
|
28
|
+
searchable: false,
|
|
29
|
+
},
|
|
30
|
+
{ key: 'description', label: 'Description', emptyText: 'No description recorded.', class: 'max-w-md min-w-64 line-clamp-2 text-gray-500 dark:text-neutral-400' },
|
|
31
|
+
{ key: 'country', label: 'Country', sortable: true, emptyText: 'Not recorded', class: 'whitespace-nowrap' },
|
|
32
|
+
{ key: 'productCount', label: 'Products', type: 'number' as const, sortable: true, align: 'right' as const, class: 'font-mono' },
|
|
33
|
+
{ key: 'createdAt', label: 'Created', type: 'date' as const, sortable: true, class: 'whitespace-nowrap' },
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
const ROW_ACTIONS = [
|
|
37
|
+
{ action: 'edit', label: 'Edit', icon: 'i-hugeicons-edit-01' },
|
|
38
|
+
{ action: 'delete', label: 'Delete', icon: 'i-hugeicons-waste', class: 'text-red-500' },
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
/** A badge column maps a row field, so the flag needs one. */
|
|
42
|
+
const rows = derived(() => records().map(record => ({
|
|
43
|
+
...record,
|
|
44
|
+
featuredFlag: record.featured ? 'featured' : '',
|
|
45
|
+
})))
|
|
46
|
+
|
|
47
|
+
function handleRowAction(payload: { action: string, row: ManufacturerRecord }): void {
|
|
48
|
+
emit(payload.action, payload.row)
|
|
18
49
|
}
|
|
19
50
|
</script>
|
|
20
51
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
<th scope="col" class="px-4 py-3 font-semibold text-gray-600 text-left text-xs uppercase dark:text-neutral-400">Created</th>
|
|
39
|
-
<th scope="col" class="relative px-4 py-3"><span class="sr-only">Actions</span></th>
|
|
40
|
-
</tr>
|
|
41
|
-
</thead>
|
|
42
|
-
<tbody class="divide-gray-100 divide-y dark:divide-neutral-700">
|
|
43
|
-
<template :for="record in records()" :key="record.id">
|
|
44
|
-
<tr class="hover:bg-gray-50/60 dark:hover:bg-neutral-700/40">
|
|
45
|
-
<td class="px-4 py-4 min-w-48">
|
|
46
|
-
<p class="font-medium text-gray-900 text-sm dark:text-white">{{ record.name || 'Unnamed manufacturer' }}</p>
|
|
47
|
-
<span :if="record.featured" class="inline-flex items-center mt-1 font-medium text-blue-700 text-xs dark:text-blue-300">
|
|
48
|
-
<span class="mr-1 h-3.5 w-3.5 i-hugeicons-star"></span>
|
|
49
|
-
Featured
|
|
50
|
-
</span>
|
|
51
|
-
</td>
|
|
52
|
-
<td class="px-4 py-4 max-w-md min-w-64 text-gray-500 text-sm dark:text-neutral-400">
|
|
53
|
-
<p class="line-clamp-2">{{ record.description || 'No description recorded.' }}</p>
|
|
54
|
-
</td>
|
|
55
|
-
<td class="px-4 py-4 text-gray-700 text-sm whitespace-nowrap dark:text-neutral-200">{{ record.country || 'Not recorded' }}</td>
|
|
56
|
-
<td class="px-4 py-4 font-mono text-gray-700 text-right text-sm dark:text-neutral-200">{{ record.productCount }}</td>
|
|
57
|
-
<td class="px-4 py-4 text-gray-500 text-sm whitespace-nowrap dark:text-neutral-400">{{ formatDate(record.createdAt) }}</td>
|
|
58
|
-
<td class="px-4 py-3 text-right whitespace-nowrap">
|
|
59
|
-
<Button variant="ghost" size="sm" iconOnly :ariaLabel="'Edit ' + record.name" @click="emit('edit', record)">
|
|
60
|
-
<span class="block h-4 w-4 text-blue-500 i-hugeicons-edit-01"></span>
|
|
61
|
-
</Button>
|
|
62
|
-
<Button variant="ghost" size="sm" iconOnly :ariaLabel="'Delete ' + record.name" @click="emit('delete', record)">
|
|
63
|
-
<span class="block h-4 w-4 text-red-500 i-hugeicons-waste"></span>
|
|
64
|
-
</Button>
|
|
65
|
-
</td>
|
|
66
|
-
</tr>
|
|
67
|
-
</template>
|
|
68
|
-
</tbody>
|
|
69
|
-
</table>
|
|
70
|
-
</div>
|
|
71
|
-
</div>
|
|
52
|
+
{{--
|
|
53
|
+
No `searchable` or `filterable`: the parent dashboard already owns the
|
|
54
|
+
search box and the filter selects, and a second set inside the table would
|
|
55
|
+
duplicate them. Paging is what was missing, and Table brings it.
|
|
56
|
+
--}}
|
|
57
|
+
<Table
|
|
58
|
+
:columns="COLUMNS"
|
|
59
|
+
:data="rows()"
|
|
60
|
+
:loading="loading()"
|
|
61
|
+
:row-actions="ROW_ACTIONS"
|
|
62
|
+
action-label-key="name"
|
|
63
|
+
paginated
|
|
64
|
+
:page-size="25"
|
|
65
|
+
empty-title="No manufacturers found"
|
|
66
|
+
empty-description="Add a manufacturer or adjust the current filters."
|
|
67
|
+
@row-action="handleRowAction"
|
|
68
|
+
/>
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
@import('../UI/Table')
|
|
2
|
+
|
|
1
3
|
<script client>
|
|
2
4
|
import type { ProductUnitRecord } from '../../../../app/Actions/Dashboard/Commerce/product-unit-records'
|
|
3
5
|
|
|
@@ -5,67 +7,63 @@ const records = useReactiveProp('records', [] as ProductUnitRecord[])
|
|
|
5
7
|
const loading = useReactiveProp('loading', false)
|
|
6
8
|
const emit = defineEmits()
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
/**
|
|
11
|
+
* No slots. `UI/Table`'s `cell` and `actions` slots cannot be used yet -
|
|
12
|
+
* slot content loses its `{{ … }}` (stacksjs/stx#2095) and `stx typecheck`
|
|
13
|
+
* rejects every scoped slot prop (stacksjs/stx#2096) - so the two custom
|
|
14
|
+
* cells here are expressed as column options instead: `subtitleKey` for the
|
|
15
|
+
* abbreviation under the name, and a flag `badge` column for the default
|
|
16
|
+
* marker.
|
|
17
|
+
*/
|
|
18
|
+
const COLUMNS = [
|
|
19
|
+
{ key: 'name', label: 'Unit', sortable: true, subtitleKey: 'abbreviation', class: 'font-medium text-gray-900 dark:text-white' },
|
|
20
|
+
{
|
|
21
|
+
key: 'defaultFlag',
|
|
22
|
+
label: '',
|
|
23
|
+
type: 'badge' as const,
|
|
24
|
+
// A flag rather than a status: only the default unit is marked, and the
|
|
25
|
+
// rest of the column stays blank.
|
|
26
|
+
emptyText: '',
|
|
27
|
+
badgeClasses: { default: 'text-emerald-700 dark:text-emerald-300 bg-emerald-50 dark:bg-emerald-950/40' },
|
|
28
|
+
badgeLabels: { default: 'Default' },
|
|
29
|
+
searchable: false,
|
|
30
|
+
},
|
|
31
|
+
{ key: 'type', label: 'Type', sortable: true, class: 'whitespace-nowrap' },
|
|
32
|
+
{ key: 'productName', label: 'Product', sortable: true, emptyText: 'Unassigned' },
|
|
33
|
+
{ key: 'description', label: 'Description', class: 'max-w-sm', emptyText: 'No description' },
|
|
34
|
+
{ key: 'createdAt', label: 'Created', type: 'datetime' as const, sortable: true, class: 'whitespace-nowrap' },
|
|
35
|
+
]
|
|
17
36
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
</div>
|
|
37
|
+
const ROW_ACTIONS = [
|
|
38
|
+
{ action: 'edit', label: 'Edit', icon: 'i-hugeicons-edit-01' },
|
|
39
|
+
{ action: 'delete', label: 'Delete', icon: 'i-hugeicons-delete-02', class: 'text-red-500' },
|
|
40
|
+
]
|
|
23
41
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
42
|
+
/** `defaultFlag` carries the badge value, since a badge column maps a row field. */
|
|
43
|
+
const rows = derived(() => records().map(record => ({
|
|
44
|
+
...record,
|
|
45
|
+
defaultFlag: record.isDefault ? 'default' : '',
|
|
46
|
+
})))
|
|
47
|
+
|
|
48
|
+
function handleRowAction(payload: { action: string, row: ProductUnitRecord }): void {
|
|
49
|
+
emit(payload.action, payload.row)
|
|
50
|
+
}
|
|
51
|
+
</script>
|
|
29
52
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
<p class="font-medium text-gray-900 text-sm dark:text-white">{{ record.name }}</p>
|
|
48
|
-
<span :if="record.isDefault" class="px-2 py-0.5 font-medium text-emerald-700 text-xs dark:text-emerald-300 bg-emerald-50 dark:bg-emerald-950/40 rounded-full">Default</span>
|
|
49
|
-
</div>
|
|
50
|
-
<p class="mt-1 text-gray-500 text-xs dark:text-neutral-400">{{ record.abbreviation }}</p>
|
|
51
|
-
</td>
|
|
52
|
-
<td class="px-4 py-4 text-gray-600 text-sm whitespace-nowrap dark:text-neutral-300">{{ record.type }}</td>
|
|
53
|
-
<td class="px-4 py-4 text-gray-600 text-sm dark:text-neutral-300">{{ record.productName || 'Unassigned' }}</td>
|
|
54
|
-
<td class="px-4 py-4 max-w-sm text-gray-600 text-sm dark:text-neutral-300">{{ record.description || 'No description' }}</td>
|
|
55
|
-
<td class="px-4 py-4 text-gray-500 text-sm whitespace-nowrap dark:text-neutral-400">{{ formatDate(record.createdAt) }}</td>
|
|
56
|
-
<td class="px-4 py-4">
|
|
57
|
-
<div class="flex gap-1 justify-end">
|
|
58
|
-
<Button variant="ghost" size="sm" iconOnly :ariaLabel="'Edit ' + record.name" @click="emit('edit', record)">
|
|
59
|
-
<span class="block h-4 w-4 text-blue-500 i-hugeicons-edit-01"></span>
|
|
60
|
-
</Button>
|
|
61
|
-
<Button variant="ghost" size="sm" iconOnly :ariaLabel="'Delete ' + record.name" @click="emit('delete', record)">
|
|
62
|
-
<span class="block h-4 w-4 text-red-500 i-hugeicons-delete-02"></span>
|
|
63
|
-
</Button>
|
|
64
|
-
</div>
|
|
65
|
-
</td>
|
|
66
|
-
</tr>
|
|
67
|
-
</template>
|
|
68
|
-
</tbody>
|
|
69
|
-
</table>
|
|
70
|
-
</div>
|
|
71
|
-
</div>
|
|
53
|
+
{{--
|
|
54
|
+
No `searchable` or `filterable`: the parent dashboard already owns the
|
|
55
|
+
search box and the filter selects, and a second set inside the table would
|
|
56
|
+
duplicate them. Paging is what was missing, and Table brings it.
|
|
57
|
+
--}}
|
|
58
|
+
<Table
|
|
59
|
+
:columns="COLUMNS"
|
|
60
|
+
:data="rows()"
|
|
61
|
+
:loading="loading()"
|
|
62
|
+
:row-actions="ROW_ACTIONS"
|
|
63
|
+
action-label-key="name"
|
|
64
|
+
paginated
|
|
65
|
+
:page-size="25"
|
|
66
|
+
empty-title="No product units found"
|
|
67
|
+
empty-description="Adjust the filters or add a ProductUnit record."
|
|
68
|
+
@row-action="handleRowAction"
|
|
69
|
+
/>
|