Skip to main content
Glama

Storyden

by Southclaws
Mozilla Public License 2.0
229
AccessKeySettings.tsx4.83 kB
import { formatDate } from "date-fns"; import { OwnedAccessKey, OwnedAccessKeyList, Permission, } from "@/api/openapi-schema"; import { MemberBadge } from "@/components/member/MemberBadge/MemberBadge"; import { PermissionBadge } from "@/components/role/PermissionBadge"; import { useConfirmation } from "@/components/site/useConfirmation"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Heading } from "@/components/ui/heading"; import { WarningIcon } from "@/components/ui/icons/Warning"; import { PermissionDetails } from "@/lib/permission/permission"; import { CardBox, HStack, LStack, WStack, styled } from "@/styled-system/jsx"; import { CardBox as cardBox, lstack } from "@/styled-system/patterns"; import { useAdminAccessKeyList } from "./useAdminAccessKeyList"; type Props = { keys: OwnedAccessKeyList; }; export function AccessKeySettings({ keys }: Props) { const { revokeKey } = useAdminAccessKeyList(); if (keys.length === 0) { return ( <CardBox className={lstack()}> <Heading size="md">Access keys</Heading> <p>No access keys have been created yet.</p> </CardBox> ); } const totalKeys = keys.length; const totalActiveKeys = keys.filter(isKeyActive).length; const hasInactive = totalKeys != totalActiveKeys; return ( <CardBox className={lstack()}> <Heading size="md">Access keys</Heading> <p>All access keys created by members of this site.</p> <p> <WarningIcon display="inline" /> <strong>Note:</strong> if you revoke the ability to use access keys from a role or member (by removing the{" "} {<PermissionBadge permission={Permission.USE_PERSONAL_ACCESS_KEYS} />}{" "} permission), this will not revoke their existing access keys. </p> <WStack alignItems="center" color="fg.muted"> {hasInactive ? ( <styled.p> {totalKeys} access keys, {totalActiveKeys} active. </styled.p> ) : ( <styled.p>{keys.length} access keys.</styled.p> )} </WStack> <ul className={lstack({ gap: "3" })}> {keys.map((key) => ( <AccessKeyItem key={key.id} accessKey={key} onRevoke={() => revokeKey(key.id)} /> ))} </ul> </CardBox> ); } type AccessKeyItemProps = { accessKey: OwnedAccessKeyList[number]; onRevoke: () => Promise<void>; }; function AccessKeyItem({ accessKey, onRevoke }: AccessKeyItemProps) { const { isConfirming, handleConfirmAction, handleCancelAction } = useConfirmation(onRevoke); const isExpired = isKeyExpired(accessKey); const inactiveStatus = isExpired ? "Expired" : accessKey.enabled ? undefined : "Revoked"; return ( <li className={cardBox()}> <LStack> <WStack> <Heading size="sm">{accessKey.name}</Heading> {inactiveStatus === undefined ? ( <HStack> {isConfirming ? ( <> <Button size="xs" variant="subtle" bgColor="bg.destructive" onClick={handleConfirmAction} > Confirm Revoke </Button> <Button size="xs" variant="outline" onClick={handleCancelAction} > Cancel </Button> </> ) : ( <Button size="xs" variant="outline" bgColor="bg.destructive" onClick={handleConfirmAction} > Revoke </Button> )} </HStack> ) : ( <Badge>{inactiveStatus}</Badge> )} </WStack> <WStack flexWrap="wrap"> <styled.p fontSize="xs"> Created: <time>{formatDate(accessKey.createdAt, "PPpp")}</time> </styled.p> {accessKey.expires_at && ( <Badge gap="1"> <span>Expiry:</span> <time>{formatDate(accessKey.expires_at, "PPpp")}</time> </Badge> )} </WStack> <MemberBadge size="sm" name="full-horizontal" profile={accessKey.created_by} /> </LStack> </li> ); } function isKeyActive(key: OwnedAccessKey) { return key.enabled && !isKeyExpired(key); } function isKeyExpired(key: OwnedAccessKey) { if (key.expires_at === undefined) { return false; } const expiryDate = new Date(key.expires_at); if (expiryDate > new Date()) { return false; } return true; }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Southclaws/storyden'

If you have feedback or need assistance with the MCP directory API, please join our Discord server