@locusgraph/blocks 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/billing/plan-price.js +24 -7
- package/dist/billing/plans.js +39 -7
- package/dist/billing/top-up.js +44 -8
- package/dist/billing/wallet.js +73 -13
- package/dist/dates/local-date.js +51 -7
- package/dist/keys/keys-empty.js +29 -6
- package/dist/keys/keys.js +65 -5
- package/dist/skeletons/keys-skeleton.js +81 -14
- package/dist/skeletons/plans-skeleton.js +52 -7
- package/dist/skeletons/top-up-skeleton.js +36 -6
- package/dist/skeletons/usage-skeleton.js +39 -5
- package/dist/skeletons/wallet-skeleton.js +38 -4
- package/dist/types.js +1 -1
- package/dist/usage/quota.js +50 -17
- package/dist/usage/usage-alert.js +58 -21
- package/dist/usage/usage.js +20 -3
- package/package.json +4 -4
|
@@ -1,9 +1,26 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
1
|
import { formatCents } from "@locusgraph/utils";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
const intervalLabel = {
|
|
4
|
+
month: "/month",
|
|
5
|
+
year: "/year"
|
|
6
|
+
};
|
|
7
|
+
export function PlanPrice({
|
|
8
|
+
plan
|
|
9
|
+
}) {
|
|
10
|
+
if (plan.amountCents === undefined) {
|
|
11
|
+
return /*#__PURE__*/_jsx("span", {
|
|
12
|
+
className: "font-heading text-xl font-semibold tracking-[-0.02em] tabular-nums",
|
|
13
|
+
children: plan.price
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return /*#__PURE__*/_jsxs("span", {
|
|
17
|
+
className: "flex items-baseline gap-1",
|
|
18
|
+
children: [/*#__PURE__*/_jsx("span", {
|
|
19
|
+
className: "font-heading text-2xl font-semibold tracking-[-0.02em] tabular-nums",
|
|
20
|
+
children: formatCents(plan.amountCents)
|
|
21
|
+
}), plan.interval && /*#__PURE__*/_jsx("span", {
|
|
22
|
+
className: "text-sm text-muted-foreground",
|
|
23
|
+
children: intervalLabel[plan.interval]
|
|
24
|
+
})]
|
|
25
|
+
});
|
|
9
26
|
}
|
package/dist/billing/plans.js
CHANGED
|
@@ -1,9 +1,41 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Badge, RuleGrid, RuleGridCell, RuleGridFooter, RuleGridTitle, } from "@locusgraph/components";
|
|
1
|
+
import { Badge, RuleGrid, RuleGridCell, RuleGridFooter, RuleGridTitle } from "@locusgraph/components";
|
|
3
2
|
import { PlanPrice } from "./plan-price.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
4
|
+
export function Plans({
|
|
5
|
+
plans,
|
|
6
|
+
actionFor
|
|
7
|
+
}) {
|
|
8
|
+
return /*#__PURE__*/_jsx(RuleGrid, {
|
|
9
|
+
columns: plans.length >= 3 ? 3 : 2,
|
|
10
|
+
children: plans.map(plan => {
|
|
11
|
+
const action = plan.current ? null : actionFor?.(plan);
|
|
12
|
+
return /*#__PURE__*/_jsxs(RuleGridCell, {
|
|
13
|
+
"data-current": plan.current || undefined,
|
|
14
|
+
className: "gap-4",
|
|
15
|
+
children: [/*#__PURE__*/_jsxs("div", {
|
|
16
|
+
className: "flex flex-col gap-2",
|
|
17
|
+
children: [/*#__PURE__*/_jsxs(RuleGridTitle, {
|
|
18
|
+
className: "flex min-h-6 items-center gap-2",
|
|
19
|
+
children: [plan.name, plan.current && /*#__PURE__*/_jsx(Badge, {
|
|
20
|
+
variant: "secondary",
|
|
21
|
+
children: "Current"
|
|
22
|
+
})]
|
|
23
|
+
}), /*#__PURE__*/_jsx(PlanPrice, {
|
|
24
|
+
plan: plan
|
|
25
|
+
})]
|
|
26
|
+
}), /*#__PURE__*/_jsx("ul", {
|
|
27
|
+
className: "flex flex-col gap-1.5 text-sm text-muted-foreground",
|
|
28
|
+
children: plan.points.map(point => /*#__PURE__*/_jsx("li", {
|
|
29
|
+
children: point
|
|
30
|
+
}, point))
|
|
31
|
+
}), /*#__PURE__*/_jsx(RuleGridFooter, {
|
|
32
|
+
className: "mt-auto",
|
|
33
|
+
children: plan.current ? /*#__PURE__*/_jsx("p", {
|
|
34
|
+
className: "flex min-h-8 items-center text-sm text-muted-foreground",
|
|
35
|
+
children: "Your plan"
|
|
36
|
+
}) : action
|
|
37
|
+
})]
|
|
38
|
+
}, plan.name);
|
|
39
|
+
})
|
|
40
|
+
});
|
|
9
41
|
}
|
package/dist/billing/top-up.js
CHANGED
|
@@ -1,12 +1,48 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Button, RuleGridCell, RuleGridDescription, RuleGridLabel, Spinner, } from "@locusgraph/components";
|
|
1
|
+
import { Button, RuleGridCell, RuleGridDescription, RuleGridLabel, Spinner } from "@locusgraph/components";
|
|
3
2
|
import { centsToMicroUsd, formatCents, formatMicroUsd } from "@locusgraph/utils";
|
|
3
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
4
4
|
function hasBonus(pack) {
|
|
5
|
-
|
|
5
|
+
return centsToMicroUsd(pack.priceCents) !== pack.amountMicroUsd;
|
|
6
6
|
}
|
|
7
|
-
export function TopUp({
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
export function TopUp({
|
|
8
|
+
packs,
|
|
9
|
+
onBuy,
|
|
10
|
+
pending = false,
|
|
11
|
+
pendingPackId,
|
|
12
|
+
highlightedPackId,
|
|
13
|
+
description = "Pay once with Stripe. Credits never expire and never renew on their own."
|
|
14
|
+
}) {
|
|
15
|
+
const busy = pending || pendingPackId !== undefined;
|
|
16
|
+
return /*#__PURE__*/_jsxs(RuleGridCell, {
|
|
17
|
+
className: "gap-4",
|
|
18
|
+
children: [/*#__PURE__*/_jsxs("div", {
|
|
19
|
+
className: "flex flex-col gap-1.5",
|
|
20
|
+
children: [/*#__PURE__*/_jsx("span", {
|
|
21
|
+
className: "flex min-h-6 items-center",
|
|
22
|
+
children: /*#__PURE__*/_jsx(RuleGridLabel, {
|
|
23
|
+
children: "Buy credits"
|
|
24
|
+
})
|
|
25
|
+
}), /*#__PURE__*/_jsx(RuleGridDescription, {
|
|
26
|
+
children: description
|
|
27
|
+
})]
|
|
28
|
+
}), /*#__PURE__*/_jsx("div", {
|
|
29
|
+
className: "flex flex-wrap gap-2",
|
|
30
|
+
children: packs.map(pack => /*#__PURE__*/_jsxs(Button, {
|
|
31
|
+
variant: pack.id === highlightedPackId ? "default" : "outline",
|
|
32
|
+
disabled: busy,
|
|
33
|
+
"aria-busy": pack.id === pendingPackId || undefined,
|
|
34
|
+
onClick: () => onBuy(pack.id),
|
|
35
|
+
children: [pack.id === pendingPackId && /*#__PURE__*/_jsx(Spinner, {
|
|
36
|
+
"aria-hidden": "true",
|
|
37
|
+
role: undefined
|
|
38
|
+
}), /*#__PURE__*/_jsx("span", {
|
|
39
|
+
className: "tabular-nums",
|
|
40
|
+
children: formatMicroUsd(pack.amountMicroUsd)
|
|
41
|
+
}), hasBonus(pack) && /*#__PURE__*/_jsxs("span", {
|
|
42
|
+
className: pack.id === highlightedPackId ? "tabular-nums opacity-75" : "font-medium text-good tabular-nums",
|
|
43
|
+
children: ["for ", formatCents(pack.priceCents)]
|
|
44
|
+
})]
|
|
45
|
+
}, pack.id))
|
|
46
|
+
})]
|
|
47
|
+
});
|
|
12
48
|
}
|
package/dist/billing/wallet.js
CHANGED
|
@@ -1,19 +1,79 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
1
|
import { Badge, RuleGridCell, RuleGridLabel } from "@locusgraph/components";
|
|
3
2
|
import { balanceLevel, formatDate, formatMicroUsd } from "@locusgraph/utils";
|
|
3
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
4
4
|
const levelHint = {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
low: {
|
|
6
|
+
badge: "Low",
|
|
7
|
+
text: "Add credits before usage stops.",
|
|
8
|
+
tone: "text-warn"
|
|
9
|
+
},
|
|
10
|
+
empty: {
|
|
11
|
+
badge: "Empty",
|
|
12
|
+
text: "Paid usage is paused until you add credits.",
|
|
13
|
+
tone: "text-destructive"
|
|
14
|
+
}
|
|
11
15
|
};
|
|
12
|
-
function GrantList({
|
|
13
|
-
|
|
16
|
+
function GrantList({
|
|
17
|
+
grants
|
|
18
|
+
}) {
|
|
19
|
+
return /*#__PURE__*/_jsx("ul", {
|
|
20
|
+
className: "flex flex-col divide-y divide-line",
|
|
21
|
+
children: grants.map(grant => /*#__PURE__*/_jsxs("li", {
|
|
22
|
+
className: "flex justify-between gap-4 py-2",
|
|
23
|
+
children: [/*#__PURE__*/_jsx("span", {
|
|
24
|
+
children: grant.label
|
|
25
|
+
}), /*#__PURE__*/_jsxs("span", {
|
|
26
|
+
className: "flex items-baseline gap-2 tabular-nums",
|
|
27
|
+
children: [/*#__PURE__*/_jsx("span", {
|
|
28
|
+
className: "font-medium text-foreground",
|
|
29
|
+
children: formatMicroUsd(grant.remainingMicroUsd)
|
|
30
|
+
}), /*#__PURE__*/_jsx("span", {
|
|
31
|
+
className: "text-muted-foreground",
|
|
32
|
+
children: grant.expiresAt ? `expires ${formatDate(grant.expiresAt)}` : "never expires"
|
|
33
|
+
})]
|
|
34
|
+
})]
|
|
35
|
+
}, `${grant.label}:${grant.expiresAt}`))
|
|
36
|
+
});
|
|
14
37
|
}
|
|
15
|
-
export function Wallet({
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
38
|
+
export function Wallet({
|
|
39
|
+
balanceMicroUsd,
|
|
40
|
+
debtMicroUsd = 0,
|
|
41
|
+
grants
|
|
42
|
+
}) {
|
|
43
|
+
const level = balanceLevel(balanceMicroUsd);
|
|
44
|
+
const hint = level === "fine" ? null : levelHint[level];
|
|
45
|
+
return /*#__PURE__*/_jsxs(RuleGridCell, {
|
|
46
|
+
"data-level": level,
|
|
47
|
+
className: "gap-4",
|
|
48
|
+
children: [/*#__PURE__*/_jsxs("span", {
|
|
49
|
+
className: "flex min-h-6 items-center justify-between",
|
|
50
|
+
children: [/*#__PURE__*/_jsx(RuleGridLabel, {
|
|
51
|
+
children: "Prepaid credits"
|
|
52
|
+
}), hint && /*#__PURE__*/_jsx(Badge, {
|
|
53
|
+
variant: level === "empty" ? "destructive" : "secondary",
|
|
54
|
+
className: level === "low" ? "text-warn" : undefined,
|
|
55
|
+
children: hint.badge
|
|
56
|
+
})]
|
|
57
|
+
}), /*#__PURE__*/_jsxs("div", {
|
|
58
|
+
className: "flex flex-col gap-1",
|
|
59
|
+
children: [/*#__PURE__*/_jsx("span", {
|
|
60
|
+
className: `font-heading text-3xl font-semibold tracking-[-0.02em] tabular-nums ${hint?.tone ?? ""}`,
|
|
61
|
+
children: formatMicroUsd(balanceMicroUsd)
|
|
62
|
+
}), hint && /*#__PURE__*/_jsx("p", {
|
|
63
|
+
className: "text-sm text-muted-foreground",
|
|
64
|
+
children: hint.text
|
|
65
|
+
})]
|
|
66
|
+
}), /*#__PURE__*/_jsxs("div", {
|
|
67
|
+
className: "flex flex-col gap-3 text-sm",
|
|
68
|
+
children: [grants.length > 0 && /*#__PURE__*/_jsx(GrantList, {
|
|
69
|
+
grants: grants
|
|
70
|
+
}), grants.length === 0 && level !== "empty" && /*#__PURE__*/_jsx("p", {
|
|
71
|
+
className: "text-muted-foreground",
|
|
72
|
+
children: "No credit grants to show."
|
|
73
|
+
}), debtMicroUsd > 0 && /*#__PURE__*/_jsxs("p", {
|
|
74
|
+
className: "text-destructive",
|
|
75
|
+
children: [formatMicroUsd(debtMicroUsd), " owed. It comes out of the next credits you add."]
|
|
76
|
+
})]
|
|
77
|
+
})]
|
|
78
|
+
});
|
|
19
79
|
}
|
package/dist/dates/local-date.js
CHANGED
|
@@ -1,10 +1,54 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
import { c as _c } from "react/compiler-runtime";
|
|
3
4
|
import { useEffect, useState } from "react";
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
6
|
+
const utcFormat = new Intl.DateTimeFormat("en-US", {
|
|
7
|
+
dateStyle: "medium",
|
|
8
|
+
timeZone: "UTC"
|
|
9
|
+
});
|
|
10
|
+
const localFormat = new Intl.DateTimeFormat("en-US", {
|
|
11
|
+
dateStyle: "medium"
|
|
12
|
+
});
|
|
13
|
+
export function LocalDate(t0) {
|
|
14
|
+
const $ = _c(8);
|
|
15
|
+
const {
|
|
16
|
+
value
|
|
17
|
+
} = t0;
|
|
18
|
+
const [hydrated, setHydrated] = useState(false);
|
|
19
|
+
let t1;
|
|
20
|
+
let t2;
|
|
21
|
+
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
|
22
|
+
t1 = () => setHydrated(true);
|
|
23
|
+
t2 = [];
|
|
24
|
+
$[0] = t1;
|
|
25
|
+
$[1] = t2;
|
|
26
|
+
} else {
|
|
27
|
+
t1 = $[0];
|
|
28
|
+
t2 = $[1];
|
|
29
|
+
}
|
|
30
|
+
useEffect(t1, t2);
|
|
31
|
+
const t3 = hydrated ? localFormat : utcFormat;
|
|
32
|
+
let t4;
|
|
33
|
+
if ($[2] !== t3 || $[3] !== value) {
|
|
34
|
+
t4 = t3.format(new Date(value));
|
|
35
|
+
$[2] = t3;
|
|
36
|
+
$[3] = value;
|
|
37
|
+
$[4] = t4;
|
|
38
|
+
} else {
|
|
39
|
+
t4 = $[4];
|
|
40
|
+
}
|
|
41
|
+
let t5;
|
|
42
|
+
if ($[5] !== t4 || $[6] !== value) {
|
|
43
|
+
t5 = /*#__PURE__*/_jsx("time", {
|
|
44
|
+
dateTime: value,
|
|
45
|
+
children: t4
|
|
46
|
+
});
|
|
47
|
+
$[5] = t4;
|
|
48
|
+
$[6] = value;
|
|
49
|
+
$[7] = t5;
|
|
50
|
+
} else {
|
|
51
|
+
t5 = $[7];
|
|
52
|
+
}
|
|
53
|
+
return t5;
|
|
10
54
|
}
|
package/dist/keys/keys-empty.js
CHANGED
|
@@ -1,8 +1,31 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
1
|
import { Password as KeyRoundIcon, Add as PlusIcon } from "@carbon/icons-react";
|
|
3
|
-
import { Button, RuleGrid, RuleGridCell, RuleGridDescription, RuleGridTitle
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
import { Button, RuleGrid, RuleGridCell, RuleGridDescription, RuleGridTitle } from "@locusgraph/components";
|
|
3
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
4
|
+
export function KeysEmpty({
|
|
5
|
+
newKeyHref,
|
|
6
|
+
description = newKeyHref ? "Create a key to let a service call LocusGraph products for this organization." : "Ask an owner to create a key for this organization.",
|
|
7
|
+
linkComponent: Link = "a"
|
|
8
|
+
}) {
|
|
9
|
+
return /*#__PURE__*/_jsx(RuleGrid, {
|
|
10
|
+
columns: 1,
|
|
11
|
+
children: /*#__PURE__*/_jsxs(RuleGridCell, {
|
|
12
|
+
className: "items-center gap-2 py-12 text-center",
|
|
13
|
+
children: [/*#__PURE__*/_jsx(KeyRoundIcon, {
|
|
14
|
+
className: "mb-1 size-5 text-muted-foreground"
|
|
15
|
+
}), /*#__PURE__*/_jsx(RuleGridTitle, {
|
|
16
|
+
children: "No API keys yet"
|
|
17
|
+
}), /*#__PURE__*/_jsx(RuleGridDescription, {
|
|
18
|
+
className: "max-w-sm",
|
|
19
|
+
children: description
|
|
20
|
+
}), newKeyHref && /*#__PURE__*/_jsx(Button, {
|
|
21
|
+
asChild: true,
|
|
22
|
+
size: "sm",
|
|
23
|
+
className: "mt-2",
|
|
24
|
+
children: /*#__PURE__*/_jsxs(Link, {
|
|
25
|
+
href: newKeyHref,
|
|
26
|
+
children: [/*#__PURE__*/_jsx(PlusIcon, {}), "New key"]
|
|
27
|
+
})
|
|
28
|
+
})]
|
|
29
|
+
})
|
|
30
|
+
});
|
|
8
31
|
}
|
package/dist/keys/keys.js
CHANGED
|
@@ -1,9 +1,69 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@locusgraph/components";
|
|
1
|
+
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@locusgraph/components";
|
|
3
2
|
import { LocalDate } from "../dates/local-date.js";
|
|
3
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
4
4
|
function dateOr(value, empty) {
|
|
5
|
-
|
|
5
|
+
return value ? /*#__PURE__*/_jsx(LocalDate, {
|
|
6
|
+
value: value
|
|
7
|
+
}) : empty;
|
|
6
8
|
}
|
|
7
|
-
export function Keys({
|
|
8
|
-
|
|
9
|
+
export function Keys({
|
|
10
|
+
keys,
|
|
11
|
+
actions,
|
|
12
|
+
highlightedId
|
|
13
|
+
}) {
|
|
14
|
+
return /*#__PURE__*/_jsxs(Table, {
|
|
15
|
+
children: [/*#__PURE__*/_jsx(TableHeader, {
|
|
16
|
+
children: /*#__PURE__*/_jsxs(TableRow, {
|
|
17
|
+
children: [/*#__PURE__*/_jsx(TableHead, {
|
|
18
|
+
children: "Name"
|
|
19
|
+
}), /*#__PURE__*/_jsx(TableHead, {
|
|
20
|
+
className: "hidden md:table-cell",
|
|
21
|
+
children: "Key"
|
|
22
|
+
}), /*#__PURE__*/_jsx(TableHead, {
|
|
23
|
+
children: "Product"
|
|
24
|
+
}), /*#__PURE__*/_jsx(TableHead, {
|
|
25
|
+
className: "hidden md:table-cell",
|
|
26
|
+
children: "Created by"
|
|
27
|
+
}), /*#__PURE__*/_jsx(TableHead, {
|
|
28
|
+
className: "hidden md:table-cell",
|
|
29
|
+
children: "Created"
|
|
30
|
+
}), /*#__PURE__*/_jsx(TableHead, {
|
|
31
|
+
children: "Expires"
|
|
32
|
+
}), actions && /*#__PURE__*/_jsx(TableHead, {
|
|
33
|
+
className: "w-0"
|
|
34
|
+
})]
|
|
35
|
+
})
|
|
36
|
+
}), /*#__PURE__*/_jsx(TableBody, {
|
|
37
|
+
children: keys.map(key => /*#__PURE__*/_jsxs(TableRow, {
|
|
38
|
+
"data-new": key.id === highlightedId ? "" : undefined,
|
|
39
|
+
className: "transition-colors duration-1000 data-new:bg-accent",
|
|
40
|
+
children: [/*#__PURE__*/_jsxs(TableCell, {
|
|
41
|
+
className: "max-w-40",
|
|
42
|
+
children: [/*#__PURE__*/_jsx("span", {
|
|
43
|
+
className: "block truncate font-medium",
|
|
44
|
+
children: key.name ?? "Untitled"
|
|
45
|
+
}), /*#__PURE__*/_jsx("span", {
|
|
46
|
+
className: "block truncate font-mono text-xs text-muted-foreground md:hidden",
|
|
47
|
+
children: key.maskedKey
|
|
48
|
+
})]
|
|
49
|
+
}), /*#__PURE__*/_jsx(TableCell, {
|
|
50
|
+
className: "hidden font-mono text-muted-foreground md:table-cell",
|
|
51
|
+
children: key.maskedKey
|
|
52
|
+
}), /*#__PURE__*/_jsx(TableCell, {
|
|
53
|
+
children: key.productLabel
|
|
54
|
+
}), /*#__PURE__*/_jsx(TableCell, {
|
|
55
|
+
className: "hidden md:table-cell",
|
|
56
|
+
children: key.createdBy
|
|
57
|
+
}), /*#__PURE__*/_jsx(TableCell, {
|
|
58
|
+
className: "hidden md:table-cell",
|
|
59
|
+
children: dateOr(key.createdAt, "—")
|
|
60
|
+
}), /*#__PURE__*/_jsx(TableCell, {
|
|
61
|
+
children: dateOr(key.expiresAt, "Never")
|
|
62
|
+
}), actions && /*#__PURE__*/_jsx(TableCell, {
|
|
63
|
+
className: "w-0 pr-2 text-right whitespace-nowrap",
|
|
64
|
+
children: actions(key)
|
|
65
|
+
})]
|
|
66
|
+
}, key.id))
|
|
67
|
+
})]
|
|
68
|
+
});
|
|
9
69
|
}
|
|
@@ -1,18 +1,85 @@
|
|
|
1
|
+
import { SkeletonBar, SkeletonLoadingLabel, skeletonRootProps, Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@locusgraph/components";
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
const columns = [{
|
|
4
|
+
name: "Key",
|
|
5
|
+
visibility: "hidden md:table-cell",
|
|
6
|
+
bar: "w-36"
|
|
7
|
+
}, {
|
|
8
|
+
name: "Product",
|
|
9
|
+
visibility: "",
|
|
10
|
+
bar: "w-20"
|
|
11
|
+
}, {
|
|
12
|
+
name: "Created by",
|
|
13
|
+
visibility: "hidden md:table-cell",
|
|
14
|
+
bar: "w-32"
|
|
15
|
+
}, {
|
|
16
|
+
name: "Created",
|
|
17
|
+
visibility: "hidden md:table-cell",
|
|
18
|
+
bar: "w-20"
|
|
19
|
+
}, {
|
|
20
|
+
name: "Expires",
|
|
21
|
+
visibility: "",
|
|
22
|
+
bar: "w-20"
|
|
23
|
+
}];
|
|
10
24
|
function NameCellSkeleton() {
|
|
11
|
-
|
|
25
|
+
return /*#__PURE__*/_jsx(TableCell, {
|
|
26
|
+
className: "max-w-40",
|
|
27
|
+
children: /*#__PURE__*/_jsxs("div", {
|
|
28
|
+
className: "flex flex-col gap-1",
|
|
29
|
+
children: [/*#__PURE__*/_jsx(SkeletonBar, {
|
|
30
|
+
className: "h-4 w-28"
|
|
31
|
+
}), /*#__PURE__*/_jsx(SkeletonBar, {
|
|
32
|
+
className: "h-3 w-20 md:hidden"
|
|
33
|
+
})]
|
|
34
|
+
})
|
|
35
|
+
});
|
|
12
36
|
}
|
|
13
|
-
export function KeysSkeleton({
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
37
|
+
export function KeysSkeleton({
|
|
38
|
+
rows = 3,
|
|
39
|
+
actions = false
|
|
40
|
+
}) {
|
|
41
|
+
const count = Math.max(1, Math.floor(rows));
|
|
42
|
+
return /*#__PURE__*/_jsxs("div", {
|
|
43
|
+
"data-slot": "keys-skeleton",
|
|
44
|
+
...skeletonRootProps,
|
|
45
|
+
className: "w-full",
|
|
46
|
+
children: [/*#__PURE__*/_jsxs(Table, {
|
|
47
|
+
"aria-hidden": "true",
|
|
48
|
+
children: [/*#__PURE__*/_jsx(TableHeader, {
|
|
49
|
+
children: /*#__PURE__*/_jsxs(TableRow, {
|
|
50
|
+
className: "hover:bg-transparent",
|
|
51
|
+
children: [/*#__PURE__*/_jsx(TableHead, {
|
|
52
|
+
children: "Name"
|
|
53
|
+
}), columns.map(column => /*#__PURE__*/_jsx(TableHead, {
|
|
54
|
+
className: column.visibility,
|
|
55
|
+
children: column.name
|
|
56
|
+
}, column.name)), actions && /*#__PURE__*/_jsx(TableHead, {
|
|
57
|
+
className: "w-0"
|
|
58
|
+
})]
|
|
59
|
+
})
|
|
60
|
+
}), /*#__PURE__*/_jsx(TableBody, {
|
|
61
|
+
children: Array.from({
|
|
62
|
+
length: count
|
|
63
|
+
}, (_, row) => /*#__PURE__*/_jsxs(TableRow
|
|
64
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: placeholder rows have no identity
|
|
65
|
+
, {
|
|
66
|
+
"data-slot": "keys-skeleton-row",
|
|
67
|
+
className: "hover:bg-transparent",
|
|
68
|
+
children: [/*#__PURE__*/_jsx(NameCellSkeleton, {}), columns.map(column => /*#__PURE__*/_jsx(TableCell, {
|
|
69
|
+
className: column.visibility,
|
|
70
|
+
children: /*#__PURE__*/_jsx(SkeletonBar, {
|
|
71
|
+
className: `h-4 ${column.bar}`
|
|
72
|
+
})
|
|
73
|
+
}, column.name)), actions && /*#__PURE__*/_jsx(TableCell, {
|
|
74
|
+
className: "w-0 pr-2 text-right",
|
|
75
|
+
children: /*#__PURE__*/_jsx(SkeletonBar, {
|
|
76
|
+
className: "ml-auto h-8 w-16 rounded-full"
|
|
77
|
+
})
|
|
78
|
+
})]
|
|
79
|
+
}, row))
|
|
80
|
+
})]
|
|
81
|
+
}), /*#__PURE__*/_jsx(SkeletonLoadingLabel, {
|
|
82
|
+
children: "Loading API keys\u2026"
|
|
83
|
+
})]
|
|
84
|
+
});
|
|
18
85
|
}
|
|
@@ -1,9 +1,54 @@
|
|
|
1
|
+
import { RuleGrid, RuleGridCell, SkeletonBar, SkeletonLoadingLabel, skeletonRootProps } from "@locusgraph/components";
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
export function PlansSkeleton({
|
|
4
|
+
plans = 2,
|
|
5
|
+
points = 2,
|
|
6
|
+
currentIndex = 0
|
|
7
|
+
}) {
|
|
8
|
+
const planCount = Math.max(1, Math.floor(plans));
|
|
9
|
+
const pointCount = Math.max(0, Math.floor(points));
|
|
10
|
+
return /*#__PURE__*/_jsxs(RuleGrid, {
|
|
11
|
+
columns: planCount >= 3 ? 3 : 2,
|
|
12
|
+
"data-slot": "plans-skeleton",
|
|
13
|
+
...skeletonRootProps,
|
|
14
|
+
children: [Array.from({
|
|
15
|
+
length: planCount
|
|
16
|
+
}, (_, plan) => /*#__PURE__*/_jsxs(RuleGridCell
|
|
17
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: placeholder plans have no identity
|
|
18
|
+
, {
|
|
19
|
+
"data-slot": "plan-skeleton",
|
|
20
|
+
"aria-hidden": "true",
|
|
21
|
+
className: "gap-4",
|
|
22
|
+
children: [/*#__PURE__*/_jsxs("div", {
|
|
23
|
+
className: "flex flex-col gap-2",
|
|
24
|
+
children: [/*#__PURE__*/_jsx("div", {
|
|
25
|
+
className: "flex min-h-6 items-center",
|
|
26
|
+
children: /*#__PURE__*/_jsx(SkeletonBar, {
|
|
27
|
+
className: "h-5 w-20"
|
|
28
|
+
})
|
|
29
|
+
}), /*#__PURE__*/_jsx(SkeletonBar, {
|
|
30
|
+
className: "h-8 w-28"
|
|
31
|
+
})]
|
|
32
|
+
}), /*#__PURE__*/_jsx("div", {
|
|
33
|
+
className: "flex flex-col gap-1.5",
|
|
34
|
+
children: Array.from({
|
|
35
|
+
length: pointCount
|
|
36
|
+
}, (_, point) =>
|
|
37
|
+
/*#__PURE__*/
|
|
38
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: placeholder points have no identity
|
|
39
|
+
_jsx(SkeletonBar, {
|
|
40
|
+
className: "h-4 w-40"
|
|
41
|
+
}, point))
|
|
42
|
+
}), plan === currentIndex ? /*#__PURE__*/_jsx("div", {
|
|
43
|
+
className: "mt-auto flex min-h-8 items-center",
|
|
44
|
+
children: /*#__PURE__*/_jsx(SkeletonBar, {
|
|
45
|
+
className: "h-4 w-16"
|
|
46
|
+
})
|
|
47
|
+
}) : /*#__PURE__*/_jsx(SkeletonBar, {
|
|
48
|
+
className: "mt-auto h-8 w-28 rounded-full"
|
|
49
|
+
})]
|
|
50
|
+
}, plan)), /*#__PURE__*/_jsx(SkeletonLoadingLabel, {
|
|
51
|
+
children: "Loading plans\u2026"
|
|
52
|
+
})]
|
|
53
|
+
});
|
|
9
54
|
}
|
|
@@ -1,8 +1,38 @@
|
|
|
1
|
+
import { RuleGridCell, RuleGridLabel, SkeletonBar, SkeletonLoadingLabel, skeletonRootProps } from "@locusgraph/components";
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
export function TopUpSkeleton({
|
|
4
|
+
packs = 3
|
|
5
|
+
}) {
|
|
6
|
+
const count = Math.max(1, Math.floor(packs));
|
|
7
|
+
return /*#__PURE__*/_jsxs(RuleGridCell, {
|
|
8
|
+
"data-slot": "top-up-skeleton",
|
|
9
|
+
...skeletonRootProps,
|
|
10
|
+
className: "gap-4",
|
|
11
|
+
children: [/*#__PURE__*/_jsxs("div", {
|
|
12
|
+
className: "flex flex-col gap-1.5",
|
|
13
|
+
children: [/*#__PURE__*/_jsx("span", {
|
|
14
|
+
className: "flex min-h-6 items-center",
|
|
15
|
+
children: /*#__PURE__*/_jsx(RuleGridLabel, {
|
|
16
|
+
children: "Buy credits"
|
|
17
|
+
})
|
|
18
|
+
}), /*#__PURE__*/_jsx(SkeletonBar, {
|
|
19
|
+
className: "h-4 w-full max-w-72"
|
|
20
|
+
}), /*#__PURE__*/_jsx(SkeletonBar, {
|
|
21
|
+
className: "h-4 w-3/4 max-w-56"
|
|
22
|
+
})]
|
|
23
|
+
}), /*#__PURE__*/_jsx("div", {
|
|
24
|
+
className: "flex flex-wrap gap-2",
|
|
25
|
+
"aria-hidden": "true",
|
|
26
|
+
children: Array.from({
|
|
27
|
+
length: count
|
|
28
|
+
}, (_, index) => /*#__PURE__*/_jsx(SkeletonBar
|
|
29
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: placeholder packs have no identity
|
|
30
|
+
, {
|
|
31
|
+
"data-slot": "credit-pack-skeleton",
|
|
32
|
+
className: "h-9 w-24 rounded-full"
|
|
33
|
+
}, index))
|
|
34
|
+
}), /*#__PURE__*/_jsx(SkeletonLoadingLabel, {
|
|
35
|
+
children: "Loading credit packs\u2026"
|
|
36
|
+
})]
|
|
37
|
+
});
|
|
8
38
|
}
|
|
@@ -1,9 +1,43 @@
|
|
|
1
|
+
import { RuleGrid, RuleGridCell, RuleGridLabel, SkeletonBar, SkeletonLoadingLabel, skeletonRootProps } from "@locusgraph/components";
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { RuleGrid, RuleGridCell, RuleGridLabel, SkeletonBar, SkeletonLoadingLabel, skeletonRootProps, } from "@locusgraph/components";
|
|
3
3
|
function QuotaSkeleton() {
|
|
4
|
-
|
|
4
|
+
return /*#__PURE__*/_jsxs("div", {
|
|
5
|
+
"data-slot": "quota-skeleton",
|
|
6
|
+
"aria-hidden": "true",
|
|
7
|
+
className: "flex flex-col gap-2",
|
|
8
|
+
children: [/*#__PURE__*/_jsxs("div", {
|
|
9
|
+
className: "flex items-baseline justify-between gap-4",
|
|
10
|
+
children: [/*#__PURE__*/_jsx(SkeletonBar, {
|
|
11
|
+
className: "h-4 w-28"
|
|
12
|
+
}), /*#__PURE__*/_jsx(SkeletonBar, {
|
|
13
|
+
className: "h-4 w-36"
|
|
14
|
+
})]
|
|
15
|
+
}), /*#__PURE__*/_jsx(SkeletonBar, {
|
|
16
|
+
className: "h-2 w-full rounded-full"
|
|
17
|
+
})]
|
|
18
|
+
});
|
|
5
19
|
}
|
|
6
|
-
export function UsageSkeleton({
|
|
7
|
-
|
|
8
|
-
|
|
20
|
+
export function UsageSkeleton({
|
|
21
|
+
quotas = 2,
|
|
22
|
+
label = "Usage"
|
|
23
|
+
}) {
|
|
24
|
+
const count = Math.max(1, Math.floor(quotas));
|
|
25
|
+
return /*#__PURE__*/_jsx(RuleGrid, {
|
|
26
|
+
columns: 1,
|
|
27
|
+
"data-slot": "usage-skeleton",
|
|
28
|
+
...skeletonRootProps,
|
|
29
|
+
children: /*#__PURE__*/_jsxs(RuleGridCell, {
|
|
30
|
+
className: "gap-5",
|
|
31
|
+
children: [/*#__PURE__*/_jsx(RuleGridLabel, {
|
|
32
|
+
children: label
|
|
33
|
+
}), Array.from({
|
|
34
|
+
length: count
|
|
35
|
+
}, (_, index) =>
|
|
36
|
+
/*#__PURE__*/
|
|
37
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: placeholder meters have no identity
|
|
38
|
+
_jsx(QuotaSkeleton, {}, index)), /*#__PURE__*/_jsx(SkeletonLoadingLabel, {
|
|
39
|
+
children: "Loading usage\u2026"
|
|
40
|
+
})]
|
|
41
|
+
})
|
|
42
|
+
});
|
|
9
43
|
}
|
|
@@ -1,6 +1,40 @@
|
|
|
1
|
+
import { RuleGridCell, RuleGridLabel, SkeletonBar, SkeletonLoadingLabel, skeletonRootProps } from "@locusgraph/components";
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
export function WalletSkeleton({
|
|
4
|
+
grants = 1
|
|
5
|
+
}) {
|
|
6
|
+
const count = Math.max(0, Math.floor(grants));
|
|
7
|
+
return /*#__PURE__*/_jsxs(RuleGridCell, {
|
|
8
|
+
"data-slot": "wallet-skeleton",
|
|
9
|
+
...skeletonRootProps,
|
|
10
|
+
className: "gap-4",
|
|
11
|
+
children: [/*#__PURE__*/_jsx("span", {
|
|
12
|
+
className: "flex min-h-6 items-center justify-between",
|
|
13
|
+
children: /*#__PURE__*/_jsx(RuleGridLabel, {
|
|
14
|
+
children: "Prepaid credits"
|
|
15
|
+
})
|
|
16
|
+
}), /*#__PURE__*/_jsx("div", {
|
|
17
|
+
className: "flex flex-col gap-1",
|
|
18
|
+
"aria-hidden": "true",
|
|
19
|
+
children: /*#__PURE__*/_jsx(SkeletonBar, {
|
|
20
|
+
className: "h-9 w-32"
|
|
21
|
+
})
|
|
22
|
+
}), /*#__PURE__*/_jsx("ul", {
|
|
23
|
+
className: "flex flex-col divide-y divide-line",
|
|
24
|
+
"aria-hidden": "true",
|
|
25
|
+
children: Array.from({
|
|
26
|
+
length: count
|
|
27
|
+
}, (_, index) => /*#__PURE__*/_jsxs("li", {
|
|
28
|
+
"data-slot": "wallet-grant-skeleton",
|
|
29
|
+
className: "flex justify-between gap-4 py-2",
|
|
30
|
+
children: [/*#__PURE__*/_jsx(SkeletonBar, {
|
|
31
|
+
className: "h-4 w-24"
|
|
32
|
+
}), /*#__PURE__*/_jsx(SkeletonBar, {
|
|
33
|
+
className: "h-4 w-40"
|
|
34
|
+
})]
|
|
35
|
+
}, index))
|
|
36
|
+
}), /*#__PURE__*/_jsx(SkeletonLoadingLabel, {
|
|
37
|
+
children: "Loading credits\u2026"
|
|
38
|
+
})]
|
|
39
|
+
});
|
|
6
40
|
}
|
package/dist/types.js
CHANGED
package/dist/usage/quota.js
CHANGED
|
@@ -1,24 +1,57 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
1
|
import { Progress } from "@locusgraph/components";
|
|
3
2
|
import { formatCount, quotaPercent, quotaStatus } from "@locusgraph/utils";
|
|
4
3
|
import { periodLabel } from "../types.js";
|
|
4
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
5
5
|
const statusIndicator = {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
ok: "",
|
|
7
|
+
near: "[&_[data-slot=progress-indicator]]:bg-warn",
|
|
8
|
+
over: "[&_[data-slot=progress-indicator]]:bg-destructive"
|
|
9
9
|
};
|
|
10
|
-
function QuotaStatusNote({
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
10
|
+
function QuotaStatusNote({
|
|
11
|
+
quota
|
|
12
|
+
}) {
|
|
13
|
+
const status = quotaStatus(quota);
|
|
14
|
+
if (status === "over") {
|
|
15
|
+
return /*#__PURE__*/_jsxs("span", {
|
|
16
|
+
className: "font-medium text-destructive",
|
|
17
|
+
children: [formatCount(quota.used - quota.included), " over"]
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
if (status === "near") {
|
|
21
|
+
return /*#__PURE__*/_jsxs("span", {
|
|
22
|
+
className: "font-medium text-warn",
|
|
23
|
+
children: [quotaPercent(quota), "%"]
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
19
27
|
}
|
|
20
|
-
export function Quota({
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
28
|
+
export function Quota({
|
|
29
|
+
quota
|
|
30
|
+
}) {
|
|
31
|
+
const percent = quotaPercent(quota);
|
|
32
|
+
const name = quota.label ?? quota.key;
|
|
33
|
+
return /*#__PURE__*/_jsxs("div", {
|
|
34
|
+
"data-slot": "quota",
|
|
35
|
+
"data-status": quotaStatus(quota),
|
|
36
|
+
className: "flex flex-col gap-2",
|
|
37
|
+
children: [/*#__PURE__*/_jsxs("div", {
|
|
38
|
+
className: "flex flex-wrap items-baseline justify-between gap-x-4 gap-y-1 text-sm",
|
|
39
|
+
children: [/*#__PURE__*/_jsx("span", {
|
|
40
|
+
className: quota.label ? "text-muted-foreground" : "font-mono text-muted-foreground",
|
|
41
|
+
children: name
|
|
42
|
+
}), /*#__PURE__*/_jsxs("span", {
|
|
43
|
+
className: "flex items-baseline gap-2 tabular-nums",
|
|
44
|
+
children: [/*#__PURE__*/_jsxs("span", {
|
|
45
|
+
className: "font-medium text-foreground",
|
|
46
|
+
children: [formatCount(quota.used), " of ", formatCount(quota.included), " ", periodLabel(quota.period)]
|
|
47
|
+
}), /*#__PURE__*/_jsx(QuotaStatusNote, {
|
|
48
|
+
quota: quota
|
|
49
|
+
})]
|
|
50
|
+
})]
|
|
51
|
+
}), /*#__PURE__*/_jsx(Progress, {
|
|
52
|
+
value: percent,
|
|
53
|
+
"aria-label": `${name} ${percent}% of quota`,
|
|
54
|
+
className: statusIndicator[quotaStatus(quota)]
|
|
55
|
+
})]
|
|
56
|
+
});
|
|
24
57
|
}
|
|
@@ -1,29 +1,66 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
1
|
import { Warning as CircleAlertIcon } from "@carbon/icons-react";
|
|
3
2
|
import { Alert, AlertDescription, AlertTitle, Button } from "@locusgraph/components";
|
|
4
|
-
import { balanceLevel, formatCount, formatMicroUsd, quotaStatus
|
|
3
|
+
import { balanceLevel, formatCount, formatMicroUsd, quotaStatus } from "@locusgraph/utils";
|
|
5
4
|
import { periodLabel } from "../types.js";
|
|
5
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
6
6
|
function attentionTitle(level, overCount) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
return "Credits are running low";
|
|
11
|
-
return level === "low"
|
|
12
|
-
? "Usage is over your plan and credits are low"
|
|
13
|
-
: "Usage is over your plan";
|
|
7
|
+
if (level === "empty") return "Out of credits";
|
|
8
|
+
if (overCount === 0) return "Credits are running low";
|
|
9
|
+
return level === "low" ? "Usage is over your plan and credits are low" : "Usage is over your plan";
|
|
14
10
|
}
|
|
15
11
|
const toneClasses = {
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
warn: "bg-warn/5 [&>svg]:text-warn",
|
|
13
|
+
destructive: "bg-destructive/5 text-card-foreground [&>svg]:text-destructive"
|
|
18
14
|
};
|
|
19
|
-
export function UsageAlert({
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
15
|
+
export function UsageAlert({
|
|
16
|
+
balanceMicroUsd,
|
|
17
|
+
quotas,
|
|
18
|
+
paidPlan,
|
|
19
|
+
buyCreditsHref,
|
|
20
|
+
upgradeHref,
|
|
21
|
+
linkComponent: Link = "a"
|
|
22
|
+
}) {
|
|
23
|
+
const level = balanceMicroUsd === null ? "fine" : balanceLevel(balanceMicroUsd);
|
|
24
|
+
const over = quotas.filter(quota => quotaStatus(quota) === "over");
|
|
25
|
+
if (level === "fine" && over.length === 0) return null;
|
|
26
|
+
const empty = level === "empty";
|
|
27
|
+
const upgradeFirst = !paidPlan && over.length > 0;
|
|
28
|
+
return /*#__PURE__*/_jsxs(Alert, {
|
|
29
|
+
className: toneClasses[empty ? "destructive" : "warn"],
|
|
30
|
+
children: [/*#__PURE__*/_jsx(CircleAlertIcon, {}), /*#__PURE__*/_jsx(AlertTitle, {
|
|
31
|
+
children: attentionTitle(level, over.length)
|
|
32
|
+
}), /*#__PURE__*/_jsxs(AlertDescription, {
|
|
33
|
+
className: "flex flex-col items-start gap-3",
|
|
34
|
+
children: [/*#__PURE__*/_jsxs("ul", {
|
|
35
|
+
className: "flex flex-col gap-1",
|
|
36
|
+
children: [over.map(quota => /*#__PURE__*/_jsxs("li", {
|
|
37
|
+
children: [/*#__PURE__*/_jsx("span", {
|
|
38
|
+
className: quota.label ? undefined : "font-mono",
|
|
39
|
+
children: quota.label ?? quota.key
|
|
40
|
+
}), " ", "is at ", formatCount(quota.used), " of ", formatCount(quota.included), " ", periodLabel(quota.period), "."]
|
|
41
|
+
}, quota.key)), balanceMicroUsd !== null && level !== "fine" && /*#__PURE__*/_jsx("li", {
|
|
42
|
+
children: empty ? "Paid usage is paused until you add credits." : `${formatMicroUsd(balanceMicroUsd)} of credits left.`
|
|
43
|
+
})]
|
|
44
|
+
}), /*#__PURE__*/_jsxs("div", {
|
|
45
|
+
className: "flex flex-wrap items-center gap-2",
|
|
46
|
+
children: [!paidPlan && /*#__PURE__*/_jsx(Button, {
|
|
47
|
+
asChild: true,
|
|
48
|
+
size: "sm",
|
|
49
|
+
variant: upgradeFirst ? "default" : "ghost",
|
|
50
|
+
children: /*#__PURE__*/_jsx(Link, {
|
|
51
|
+
href: upgradeHref,
|
|
52
|
+
children: "Upgrade to Pro"
|
|
53
|
+
})
|
|
54
|
+
}), /*#__PURE__*/_jsx(Button, {
|
|
55
|
+
asChild: true,
|
|
56
|
+
size: "sm",
|
|
57
|
+
variant: upgradeFirst ? "ghost" : "default",
|
|
58
|
+
children: /*#__PURE__*/_jsx(Link, {
|
|
59
|
+
href: buyCreditsHref,
|
|
60
|
+
children: "Buy credits"
|
|
61
|
+
})
|
|
62
|
+
})]
|
|
63
|
+
})]
|
|
64
|
+
})]
|
|
65
|
+
});
|
|
29
66
|
}
|
package/dist/usage/usage.js
CHANGED
|
@@ -1,6 +1,23 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
1
|
import { RuleGrid, RuleGridCell, RuleGridLabel } from "@locusgraph/components";
|
|
3
2
|
import { Quota } from "./quota.js";
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
4
|
+
export function Usage({
|
|
5
|
+
quotas,
|
|
6
|
+
label = "Usage",
|
|
7
|
+
emptyText = "No plan includes metered usage yet."
|
|
8
|
+
}) {
|
|
9
|
+
return /*#__PURE__*/_jsx(RuleGrid, {
|
|
10
|
+
columns: 1,
|
|
11
|
+
children: /*#__PURE__*/_jsxs(RuleGridCell, {
|
|
12
|
+
className: "gap-5",
|
|
13
|
+
children: [/*#__PURE__*/_jsx(RuleGridLabel, {
|
|
14
|
+
children: label
|
|
15
|
+
}), quotas.length > 0 ? quotas.map(quota => /*#__PURE__*/_jsx(Quota, {
|
|
16
|
+
quota: quota
|
|
17
|
+
}, quota.key)) : /*#__PURE__*/_jsx("p", {
|
|
18
|
+
className: "text-sm text-muted-foreground",
|
|
19
|
+
children: emptyText
|
|
20
|
+
})]
|
|
21
|
+
})
|
|
22
|
+
});
|
|
6
23
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@locusgraph/blocks",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "Product sections built from @locusgraph/components: usage meters and alerts, wallet, credit packs, plan options and API keys.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"provenance": true
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
|
-
"@locusgraph/components": "^0.2.
|
|
32
|
+
"@locusgraph/components": "^0.2.2",
|
|
33
33
|
"react": "^19.2.0",
|
|
34
34
|
"react-dom": "^19.2.0"
|
|
35
35
|
},
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"@locusgraph/utils": "0.1.1"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@locusgraph/components": "0.2.
|
|
41
|
+
"@locusgraph/components": "0.2.2",
|
|
42
42
|
"@locusgraph/config": "0.1.1",
|
|
43
43
|
"@types/node": "^22.0.0",
|
|
44
44
|
"@types/react": "^19.2.0",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"vitest": "^5.0.3"
|
|
50
50
|
},
|
|
51
51
|
"scripts": {
|
|
52
|
-
"build": "rm -rf dist && tsc -p tsconfig.build.json && cp src/sources.css dist/sources.css && node ../../scripts/esm-extensions.mjs dist",
|
|
52
|
+
"build": "rm -rf dist && tsc -p tsconfig.build.json && cp src/sources.css dist/sources.css && node ../../scripts/react-compiler.mjs dist && node ../../scripts/esm-extensions.mjs dist",
|
|
53
53
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
54
54
|
"test": "vitest run"
|
|
55
55
|
}
|