typescript
This commit is contained in:
@@ -1,19 +1,45 @@
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
const useCapabilitySets = ({ api, notifyApiError, setStatusMessage, token }) => {
|
||||
const [capabilitySets, setCapabilitySets] = useState([]);
|
||||
type Identifier = string | number;
|
||||
|
||||
interface CapabilitySet {
|
||||
id?: Identifier;
|
||||
slug: string;
|
||||
label?: string;
|
||||
capabilities: string[];
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
interface ApiClient {
|
||||
get<T = CapabilitySet[]>(path: string): Promise<{ data: T }>;
|
||||
post<T = CapabilitySet>(path: string, payload?: unknown): Promise<{ data: T }>;
|
||||
patch<T = CapabilitySet>(path: string, payload?: unknown): Promise<{ data: T }>;
|
||||
delete: (path: string) => Promise<void>;
|
||||
}
|
||||
|
||||
interface UseCapabilitySetsOptions {
|
||||
api: ApiClient;
|
||||
notifyApiError?: (error: unknown, message: string) => void;
|
||||
setStatusMessage?: (message: string, level?: string) => void;
|
||||
token?: string | null;
|
||||
}
|
||||
|
||||
const useCapabilitySets = ({ api, notifyApiError, setStatusMessage, token }: UseCapabilitySetsOptions) => {
|
||||
const [capabilitySets, setCapabilitySets] = useState<CapabilitySet[]>([]);
|
||||
const [capabilitySetsLoading, setCapabilitySetsLoading] = useState(false);
|
||||
const [creatingCapabilitySet, setCreatingCapabilitySet] = useState(false);
|
||||
const [savingCapabilitySetId, setSavingCapabilitySetId] = useState(null);
|
||||
const [deletingCapabilitySetId, setDeletingCapabilitySetId] = useState(null);
|
||||
const [savingCapabilitySetId, setSavingCapabilitySetId] = useState<Identifier | null>(null);
|
||||
const [deletingCapabilitySetId, setDeletingCapabilitySetId] = useState<Identifier | null>(null);
|
||||
const [supportsCapabilitySetLabels, setSupportsCapabilitySetLabels] = useState(false);
|
||||
|
||||
const applyCapabilitySets = useCallback((updater) => {
|
||||
const applyCapabilitySets = useCallback((updater: CapabilitySet[] | ((prev: CapabilitySet[]) => CapabilitySet[])) => {
|
||||
setCapabilitySets((previous) => {
|
||||
const base = Array.isArray(previous) ? [...previous] : [];
|
||||
const next = typeof updater === 'function'
|
||||
? updater(base)
|
||||
: (Array.isArray(updater) ? [...updater] : base);
|
||||
: Array.isArray(updater)
|
||||
? [...updater]
|
||||
: base;
|
||||
const supportsLabels = next.some((item) => Object.prototype.hasOwnProperty.call(item || {}, 'label'));
|
||||
setSupportsCapabilitySetLabels(supportsLabels);
|
||||
return next;
|
||||
@@ -27,7 +53,7 @@ const useCapabilitySets = ({ api, notifyApiError, setStatusMessage, token }) =>
|
||||
}
|
||||
setCapabilitySetsLoading(true);
|
||||
try {
|
||||
const { data } = await api.get('/capability-sets');
|
||||
const { data } = await api.get<CapabilitySet[]>('/capability-sets');
|
||||
applyCapabilitySets(Array.isArray(data) ? data : []);
|
||||
} catch (error) {
|
||||
notifyApiError?.(error, 'Failed to load capability sets.');
|
||||
@@ -45,7 +71,7 @@ const useCapabilitySets = ({ api, notifyApiError, setStatusMessage, token }) =>
|
||||
}, [applyCapabilitySets, refreshCapabilitySets, token]);
|
||||
|
||||
const createCapabilitySet = useCallback(
|
||||
async ({ slug, label, capabilities } = {}) => {
|
||||
async ({ slug, label, capabilities }: { slug?: string; label?: string; capabilities?: string[] } = {}) => {
|
||||
if (creatingCapabilitySet) {
|
||||
return false;
|
||||
}
|
||||
@@ -55,7 +81,7 @@ const useCapabilitySets = ({ api, notifyApiError, setStatusMessage, token }) =>
|
||||
}
|
||||
setCreatingCapabilitySet(true);
|
||||
try {
|
||||
const payload = {
|
||||
const payload: { slug?: string; label?: string; capabilities: string[] } = {
|
||||
capabilities,
|
||||
};
|
||||
const trimmedSlug = slug?.trim();
|
||||
@@ -67,12 +93,12 @@ const useCapabilitySets = ({ api, notifyApiError, setStatusMessage, token }) =>
|
||||
payload.label = trimmedLabel;
|
||||
}
|
||||
|
||||
const { data } = await api.post('/capability-sets', payload);
|
||||
const { data } = await api.post<CapabilitySet>('/capability-sets', payload);
|
||||
if (data) {
|
||||
applyCapabilitySets((previous) => {
|
||||
const next = previous.filter((entry) => entry?.id !== data.id);
|
||||
next.push(data);
|
||||
next.sort((a, b) => a.slug.localeCompare(b.slug));
|
||||
next.sort((a, b) => (a.slug || '').localeCompare(b.slug || ''));
|
||||
return next;
|
||||
});
|
||||
} else {
|
||||
@@ -99,13 +125,16 @@ const useCapabilitySets = ({ api, notifyApiError, setStatusMessage, token }) =>
|
||||
);
|
||||
|
||||
const updateCapabilitySet = useCallback(
|
||||
async (capabilitySetId, { slug, label, capabilities } = {}) => {
|
||||
async (
|
||||
capabilitySetId: Identifier | null,
|
||||
{ slug, label, capabilities }: { slug?: string; label?: string; capabilities?: string[] } = {},
|
||||
) => {
|
||||
if (!capabilitySetId) {
|
||||
return false;
|
||||
}
|
||||
setSavingCapabilitySetId(capabilitySetId);
|
||||
try {
|
||||
const payload = {};
|
||||
const payload: { slug?: string; label?: string; capabilities?: string[] } = {};
|
||||
if (slug !== undefined) {
|
||||
const trimmed = slug?.trim();
|
||||
if (trimmed) {
|
||||
@@ -126,7 +155,7 @@ const useCapabilitySets = ({ api, notifyApiError, setStatusMessage, token }) =>
|
||||
payload.capabilities = capabilities;
|
||||
}
|
||||
|
||||
const { data } = await api.patch(`/capability-sets/${capabilitySetId}`, payload);
|
||||
const { data } = await api.patch<CapabilitySet>(`/capability-sets/${capabilitySetId}`, payload);
|
||||
if (data) {
|
||||
applyCapabilitySets((previous) => {
|
||||
let found = false;
|
||||
@@ -140,7 +169,7 @@ const useCapabilitySets = ({ api, notifyApiError, setStatusMessage, token }) =>
|
||||
if (!found) {
|
||||
next.push(data);
|
||||
}
|
||||
next.sort((a, b) => a.slug.localeCompare(b.slug));
|
||||
next.sort((a, b) => (a.slug || '').localeCompare(b.slug || ''));
|
||||
return next;
|
||||
});
|
||||
} else {
|
||||
@@ -166,7 +195,7 @@ const useCapabilitySets = ({ api, notifyApiError, setStatusMessage, token }) =>
|
||||
);
|
||||
|
||||
const deleteCapabilitySet = useCallback(
|
||||
async (capabilitySetId) => {
|
||||
async (capabilitySetId: Identifier | null) => {
|
||||
if (!capabilitySetId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -58,13 +58,13 @@ interface PasskeyRegisterPayload {
|
||||
nickname?: string;
|
||||
}
|
||||
|
||||
type RegisterPasskeyFailureReason = 'unsupported' | 'busy' | 'cancelled' | 'error';
|
||||
type RegisterPasskeyResult =
|
||||
export type RegisterPasskeyFailureReason = 'unsupported' | 'busy' | 'cancelled' | 'error';
|
||||
export type RegisterPasskeyResult =
|
||||
| { ok: true }
|
||||
| { ok: false; reason: RegisterPasskeyFailureReason; message?: string };
|
||||
|
||||
type RevokePasskeyFailureReason = 'missing-id' | 'error';
|
||||
type RevokePasskeyResult =
|
||||
export type RevokePasskeyFailureReason = 'missing-id' | 'error';
|
||||
export type RevokePasskeyResult =
|
||||
| { ok: true }
|
||||
| { ok: false; reason: RevokePasskeyFailureReason; message?: string };
|
||||
|
||||
|
||||
Reference in New Issue
Block a user