@lukoweb/apitogo-plugin-dev-portal-billing 0.1.71 → 0.1.73
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/index.mjs +65 -73
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Button, Head, Heading } from "@lukoweb/apitogo/components";
|
|
1
|
+
import { Button, Head, Heading, Spinner } from "@lukoweb/apitogo/components";
|
|
2
2
|
import { CreditCardIcon, KeyRoundIcon, ShieldIcon, StarsIcon, TrashIcon } from "@lukoweb/apitogo/icons";
|
|
3
3
|
import { createContext, useContext, useEffect, useState } from "react";
|
|
4
4
|
import { Link, Navigate, Outlet, useNavigate, useSearchParams } from "@lukoweb/apitogo/router";
|
|
@@ -11,7 +11,7 @@ import { useMutation, useQuery, useQueryClient } from "@lukoweb/apitogo/react-qu
|
|
|
11
11
|
import { useAuth } from "@lukoweb/apitogo/hooks";
|
|
12
12
|
import { Alert, AlertTitle } from "@lukoweb/apitogo/ui/Alert.js";
|
|
13
13
|
import { Button as Button$1 } from "@lukoweb/apitogo/ui/Button.js";
|
|
14
|
-
import { Dialog,
|
|
14
|
+
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@lukoweb/apitogo/ui/Dialog.js";
|
|
15
15
|
import { Input } from "@lukoweb/apitogo/ui/Input.js";
|
|
16
16
|
import { Secret } from "@lukoweb/apitogo/ui/Secret.js";
|
|
17
17
|
import { createPlugin } from "@lukoweb/apitogo/plugins";
|
|
@@ -314,7 +314,6 @@ function createDemoCredentials(plans) {
|
|
|
314
314
|
return {
|
|
315
315
|
idToken: "demo-id-token",
|
|
316
316
|
accessToken: null,
|
|
317
|
-
subscriptionKey: DEMO_SUBSCRIPTION_KEY,
|
|
318
317
|
gatewayBaseUrl: null,
|
|
319
318
|
planSku: resolveDemoPlanSku(plans),
|
|
320
319
|
expiresAt: null
|
|
@@ -593,6 +592,8 @@ const ApiKeysPanel = ({ readOnly = false }) => {
|
|
|
593
592
|
const revokeKey = useRevokeApiKey();
|
|
594
593
|
const [name, setName] = useState("");
|
|
595
594
|
const [newKey, setNewKey] = useState(null);
|
|
595
|
+
const [openRevokeId, setOpenRevokeId] = useState(null);
|
|
596
|
+
const [pendingRevokeId, setPendingRevokeId] = useState(null);
|
|
596
597
|
const activeKeys = data?.keys.filter((key) => key.status === "active") ?? [];
|
|
597
598
|
const capLabel = data?.maxKeys == null ? `${data?.activeCount ?? activeKeys.length} active` : `${data.activeCount} of ${data.maxKeys} used`;
|
|
598
599
|
const canCreate = !readOnly && (data?.canCreate ?? false);
|
|
@@ -604,6 +605,13 @@ const ApiKeysPanel = ({ readOnly = false }) => {
|
|
|
604
605
|
setName("");
|
|
605
606
|
} });
|
|
606
607
|
};
|
|
608
|
+
const handleRevoke = (keyId) => {
|
|
609
|
+
setPendingRevokeId(keyId);
|
|
610
|
+
revokeKey.mutate(keyId, { onSettled: () => {
|
|
611
|
+
setPendingRevokeId(null);
|
|
612
|
+
setOpenRevokeId(null);
|
|
613
|
+
} });
|
|
614
|
+
};
|
|
607
615
|
return /* @__PURE__ */ jsxs("article", {
|
|
608
616
|
className: "rounded-xl border bg-card/60 p-6 space-y-5",
|
|
609
617
|
children: [
|
|
@@ -670,52 +678,59 @@ const ApiKeysPanel = ({ readOnly = false }) => {
|
|
|
670
678
|
}) : null,
|
|
671
679
|
activeKeys.length > 0 ? /* @__PURE__ */ jsx("ul", {
|
|
672
680
|
className: "divide-y rounded-lg border",
|
|
673
|
-
children: activeKeys.map((key) =>
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
className: "
|
|
677
|
-
children: [/* @__PURE__ */
|
|
678
|
-
className: "
|
|
679
|
-
children:
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
asChild: true,
|
|
691
|
-
children: /* @__PURE__ */ jsxs(Button$1, {
|
|
692
|
-
variant: "ghost",
|
|
693
|
-
className: "flex items-center gap-2",
|
|
694
|
-
disabled: revokeKey.isPending,
|
|
695
|
-
children: [/* @__PURE__ */ jsx(TrashIcon, { size: 16 }), /* @__PURE__ */ jsx("span", {
|
|
696
|
-
className: "hidden md:block",
|
|
697
|
-
children: "Revoke"
|
|
681
|
+
children: activeKeys.map((key) => {
|
|
682
|
+
const isRevoking = pendingRevokeId === key.id;
|
|
683
|
+
return /* @__PURE__ */ jsxs("li", {
|
|
684
|
+
className: "flex flex-wrap items-center justify-between gap-3 p-4",
|
|
685
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
686
|
+
className: "min-w-0 space-y-1",
|
|
687
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
688
|
+
className: "truncate font-medium",
|
|
689
|
+
children: key.name
|
|
690
|
+
}), /* @__PURE__ */ jsxs("p", {
|
|
691
|
+
className: "text-xs text-muted-foreground",
|
|
692
|
+
children: [
|
|
693
|
+
/* @__PURE__ */ jsxs("code", { children: [key.keyPrefix, "…"] }),
|
|
694
|
+
" · created",
|
|
695
|
+
" ",
|
|
696
|
+
new Date(key.createdAtUtc).toLocaleDateString()
|
|
697
|
+
]
|
|
698
698
|
})]
|
|
699
|
-
})
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
699
|
+
}), readOnly ? null : /* @__PURE__ */ jsxs(Dialog, {
|
|
700
|
+
open: openRevokeId === key.id,
|
|
701
|
+
onOpenChange: (open) => {
|
|
702
|
+
if (isRevoking) return;
|
|
703
|
+
setOpenRevokeId(open ? key.id : null);
|
|
704
|
+
},
|
|
705
|
+
children: [/* @__PURE__ */ jsx(DialogTrigger, {
|
|
706
|
+
asChild: true,
|
|
707
|
+
children: /* @__PURE__ */ jsxs(Button$1, {
|
|
708
|
+
variant: "ghost",
|
|
709
|
+
className: "flex items-center gap-2",
|
|
710
|
+
disabled: isRevoking,
|
|
711
|
+
children: [isRevoking ? /* @__PURE__ */ jsx(Spinner, { size: 14 }) : /* @__PURE__ */ jsx(TrashIcon, { size: 16 }), /* @__PURE__ */ jsx("span", {
|
|
712
|
+
className: "hidden md:block",
|
|
713
|
+
children: isRevoking ? "Revoking…" : "Revoke"
|
|
714
|
+
})]
|
|
715
|
+
})
|
|
716
|
+
}), /* @__PURE__ */ jsxs(DialogContent, { children: [/* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsxs(DialogTitle, { children: [
|
|
717
|
+
"Revoke “",
|
|
718
|
+
key.name,
|
|
719
|
+
"”?"
|
|
720
|
+
] }), /* @__PURE__ */ jsx(DialogDescription, { children: "Any application using this key will immediately start getting 401 responses from the gateway. This cannot be undone." })] }), /* @__PURE__ */ jsxs(DialogFooter, { children: [/* @__PURE__ */ jsx(Button$1, {
|
|
721
|
+
variant: "outline",
|
|
722
|
+
disabled: isRevoking,
|
|
723
|
+
onClick: () => setOpenRevokeId(null),
|
|
724
|
+
children: "Cancel"
|
|
725
|
+
}), /* @__PURE__ */ jsx(Button$1, {
|
|
726
|
+
variant: "destructive",
|
|
727
|
+
disabled: isRevoking,
|
|
728
|
+
onClick: () => handleRevoke(key.id),
|
|
729
|
+
children: isRevoking ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Spinner, { size: 14 }), "Revoking…"] }) : "Revoke key"
|
|
730
|
+
})] })] })]
|
|
731
|
+
})]
|
|
732
|
+
}, key.id);
|
|
733
|
+
})
|
|
719
734
|
}) : null,
|
|
720
735
|
readOnly ? null : /* @__PURE__ */ jsxs("div", {
|
|
721
736
|
className: "flex flex-wrap items-center gap-2",
|
|
@@ -733,7 +748,8 @@ const ApiKeysPanel = ({ readOnly = false }) => {
|
|
|
733
748
|
}), /* @__PURE__ */ jsx(Button$1, {
|
|
734
749
|
onClick: handleCreate,
|
|
735
750
|
disabled: !canCreate || createKey.isPending || !name.trim(),
|
|
736
|
-
|
|
751
|
+
className: "flex items-center gap-2",
|
|
752
|
+
children: createKey.isPending ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Spinner, { size: 14 }), "Creating…"] }) : "Create API key"
|
|
737
753
|
})]
|
|
738
754
|
}),
|
|
739
755
|
data && !data.canCreate && !readOnly ? /* @__PURE__ */ jsx("p", {
|
|
@@ -966,7 +982,6 @@ const CredentialsPage = () => {
|
|
|
966
982
|
const isDemoSession = useIsDemoSession();
|
|
967
983
|
const { data: credentials, isLoading, error } = useCredentials();
|
|
968
984
|
const { data: catalog } = usePlans();
|
|
969
|
-
const [revealed, setRevealed] = useState(false);
|
|
970
985
|
const plan = catalog?.plans.find((item) => item.sku === credentials?.planSku);
|
|
971
986
|
return /* @__PURE__ */ jsxs("div", {
|
|
972
987
|
className: "mx-auto max-w-screen-lg px-4 pb-16 pt-(--padding-content-top) lg:px-8",
|
|
@@ -1048,29 +1063,6 @@ const CredentialsPage = () => {
|
|
|
1048
1063
|
})
|
|
1049
1064
|
}),
|
|
1050
1065
|
/* @__PURE__ */ jsx(ApiKeysPanel, { readOnly: isDemoSession }),
|
|
1051
|
-
/* @__PURE__ */ jsxs("article", {
|
|
1052
|
-
className: "rounded-xl border bg-card/60 p-6 space-y-4",
|
|
1053
|
-
children: [/* @__PURE__ */ jsxs("div", {
|
|
1054
|
-
className: "space-y-1",
|
|
1055
|
-
children: [/* @__PURE__ */ jsx("h2", {
|
|
1056
|
-
className: "text-lg font-medium",
|
|
1057
|
-
children: "Default key value"
|
|
1058
|
-
}), /* @__PURE__ */ jsxs("p", {
|
|
1059
|
-
className: "text-sm text-muted-foreground",
|
|
1060
|
-
children: [
|
|
1061
|
-
"The full value of the ",
|
|
1062
|
-
/* @__PURE__ */ jsx("code", { children: "default" }),
|
|
1063
|
-
" key issued with your plan. Keys you create above are shown only once, so store them yourself."
|
|
1064
|
-
]
|
|
1065
|
-
})]
|
|
1066
|
-
}), /* @__PURE__ */ jsx(Secret, {
|
|
1067
|
-
className: "max-w-full w-full",
|
|
1068
|
-
secret: credentials.subscriptionKey,
|
|
1069
|
-
status: "active",
|
|
1070
|
-
revealed,
|
|
1071
|
-
onReveal: setRevealed
|
|
1072
|
-
})]
|
|
1073
|
-
}),
|
|
1074
1066
|
/* @__PURE__ */ jsxs("article", {
|
|
1075
1067
|
className: "rounded-xl border bg-card/60 p-6 space-y-4",
|
|
1076
1068
|
children: [/* @__PURE__ */ jsxs("div", {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lukoweb/apitogo-plugin-dev-portal-billing",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.73",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/zuplo/zudoku",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"react": "19.2.4",
|
|
47
47
|
"react-dom": "19.2.4",
|
|
48
48
|
"tsdown": "0.20.3",
|
|
49
|
-
"@lukoweb/apitogo": "0.1.
|
|
49
|
+
"@lukoweb/apitogo": "0.1.73"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|
|
52
52
|
"react": ">=19.2.0",
|