Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
its-felix committed Jan 3, 2024
1 parent 35d5ec7 commit 972d641
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 11 deletions.
2 changes: 1 addition & 1 deletion src/components/common/copy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export function Copy({
copyText, position, children, ...boxProps
}: CopyProps) {
return (
<Box margin={{ right: 'xxs' }} display={'inline-block'} {...boxProps}>
<Box margin={{ right: 'xxs' }} {...boxProps}>
<CopyButton copyText={copyText} position={position} variant={'inline-icon'} />
{children}
</Box>
Expand Down
1 change: 1 addition & 0 deletions src/components/common/custom-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ interface NodeHeaderColumnDefinition<T> extends BaseCustomTableColumnDefinition<
export type CustomTableColumnDefinition<T> = StringHeaderColumnDefinition<T> | NodeHeaderColumnDefinition<T>;

export interface CustomTableProps<T> extends TableProps<T> {
visibleColumns?: ReadonlyArray<string>;
columnDefinitions: ReadonlyArray<CustomTableColumnDefinition<T>>
}

Expand Down
29 changes: 23 additions & 6 deletions src/pages/developer/applications-apikeys-create.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import {
Box,
Button,
Container, DatePicker,
Form, FormField, Header, Multiselect, MultiselectProps, SpaceBetween,
Container, DatePicker, ExpandableSection,
Form, FormField, Header, Multiselect, MultiselectProps, SpaceBetween, Textarea,
} from '@cloudscape-design/components';
import React, { useMemo, useState } from 'react';
import { useHref, useNavigate, useParams } from 'react-router-dom';
import { Copy } from '../../components/common/copy';
import { Hidden } from '../../components/common/hidden';
import { KeyValuePairs, ValueWithLabel } from '../../components/common/key-value-pairs';
import { RouterInlineLink } from '../../components/common/router-link';
import { catchNotify, useAppControls } from '../../components/util/context/app-controls';
import { useHttpClient } from '../../components/util/context/http-client';
Expand Down Expand Up @@ -49,15 +50,27 @@ export function DevApplicationsAPIKeysCreate() {
setLoading(true);
(async () => {
const { body } = expectSuccess(await apiClient.createDevApplicationApiKey(applicationId!, perms, exp));
const basicAuth = btoa(`${body.id}:${body.key}`);
const basicAuthFull = `Authorization: Basic ${basicAuth}`;

updateNotification({
type: 'success',
content: (
<SpaceBetween direction={'vertical'} size={'xs'}>
<Box>You API Key was created. Copy the secret now:</Box>
<Copy copyText={body.key} position={'bottom'}>
<Hidden>{body.key}</Hidden>
</Copy>
<ExpandableSection headerText={'Show'} variant={'footer'}>
<KeyValuePairs columns={1}>
<ValueWithLabel label={'ID (Username)'}>
<Copy copyText={body.key}><Box variant={'samp'} fontSize={'body-s'}>{body.id}</Box></Copy>
</ValueWithLabel>
<ValueWithLabel label={'Secret (Password)'}>
<Copy copyText={body.key}><Box variant={'samp'} fontSize={'body-s'}>{body.key}</Box></Copy>
</ValueWithLabel>
<ValueWithLabel label={'Header'}>
<Copy copyText={basicAuthFull}><Box variant={'samp'} fontSize={'body-s'}>{basicAuthFull}</Box></Copy>
</ValueWithLabel>
</KeyValuePairs>
</ExpandableSection>
</SpaceBetween>
),
dismissible: true,
Expand Down Expand Up @@ -88,10 +101,14 @@ export function DevApplicationsAPIKeysCreate() {
{
value: 'read',
label: 'read',
description: 'Not implemented',
disabled: true,
},
{
value: 'client:create',
label: 'client:create',
description: 'Not implemented',
disabled: true,
},
{
value: 'client:modify',
Expand All @@ -105,7 +122,7 @@ export function DevApplicationsAPIKeysCreate() {
/>
</FormField>

<FormField label={'Expires At'} description={'The time when this API Key should expire (optional)'}>
<FormField label={'Expires At'} description={'The time when this API Key should expire - optional'}>
<DatePicker value={expiresAt} onChange={(e) => setExpiresAt(e.detail.value)} disabled={loading} />
</FormField>
</SpaceBetween>
Expand Down
64 changes: 60 additions & 4 deletions src/pages/developer/applications-detail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,17 @@ import {
} from '@cloudscape-design/collection-hooks/dist/cjs/interfaces';
import {
Alert,
Box, Button,
Box, Button, ButtonProps,
Calendar, Checkbox, ColumnLayout, Container,
ContentLayout,
DateInput,
FormField,
Header,
Header, HelpPanel, Link,
Pagination,
PropertyFilter,
PropertyFilterProps, SpaceBetween, Spinner, StatusIndicator, StatusIndicatorProps, Tabs,
PropertyFilterProps, SpaceBetween, Spinner, StatusIndicator, StatusIndicatorProps, Tabs, Textarea, TextContent,
} from '@cloudscape-design/components';
import { LinkProps } from '@cloudscape-design/components/link/interfaces';
import React, { useEffect, useMemo, useState } from 'react';
import {
useHref, useLocation, useNavigate, useParams,
Expand All @@ -24,7 +25,7 @@ import { DeleteModal, DeleteModalProps } from '../../components/common/delete-mo
import { KeyValuePairs, ValueWithLabel } from '../../components/common/key-value-pairs';
import { RouterInlineLink } from '../../components/common/router-link';
import { ApprovalType } from '../../components/dev-application/approval-type';
import { catchNotify, useAppControls } from '../../components/util/context/app-controls';
import { catchNotify, useAppControls, useTools } from '../../components/util/context/app-controls';
import { useHttpClient } from '../../components/util/context/http-client';
import { useI18n } from '../../components/util/context/i18n';
import { usePreferences } from '../../components/util/state/use-preferences';
Expand Down Expand Up @@ -349,6 +350,7 @@ function APIKeyTable({ id, devApplication, onUpdate }: { id: string, devApplicat
<Header
counter={`(${devApplication.apiKeys.length})`}
actions={<RouterInlineLink to={`${baseHref}/apikeys/create`} variant={'primary'}>Create API Key</RouterInlineLink>}
info={<APIKeyInfo />}
>API Keys</Header>
}
empty={
Expand Down Expand Up @@ -731,3 +733,57 @@ function APIKeyDeleteModal(props: Omit<DeleteModalProps<string>, 'entityType'>)
</DeleteModal>
);
}

function APIKeyInfo() {
const [tools, setTools] = useState<React.ReactNode>();
const setToolsOpen = useTools(tools);

useEffect(() => {
setTools(<APIKeyHelpPanel onCloseClick={() => setToolsOpen(false)} />);
return () => setTools(undefined);
}, []);

function onFollow(e: CustomEvent<LinkProps.FollowDetail>) {
e.preventDefault();
setToolsOpen(true);
}

return (
<Link variant={'info'} onFollow={onFollow}>Info</Link>
);
}

function APIKeyHelpPanel({ onCloseClick }: { onCloseClick: (e: CustomEvent<ButtonProps.ClickDetail>) => void }) {
const baseURL = `${window.location.protocol}//${window.location.host}`;
const redirectURIEndpoint = `${baseURL}/api-app/application/client/:client_id/redirecturi`;
const redirectURIEndpointExample = `PATCH ${redirectURIEndpoint}
Authorization: Basic :auth
Content-Type: application/json
{
"add": ["https://example.gw2auth.com/callback"],
"remove": ["https://example.gw2auth.com/callback2"]
}`;

return (
<HelpPanel header={<Box variant={'h2'}>API Keys</Box>} footer={<Button onClick={onCloseClick}>Close</Button>}>
<SpaceBetween size={'m'} direction={'vertical'}>
<SpaceBetween size={'xs'} direction={'vertical'}>
<Box>Using an API Key you can modify the redirect URIs of an existing client of this application.</Box>
<Box variant={'small'}>More endpoints might be added later, allowing for more programmatic automation of your application.</Box>
</SpaceBetween>
<SpaceBetween size={'xs'} direction={'vertical'}>
<Box variant={'h3'}>How can I use an API Key?</Box>
<Box>GW2Auth provides a set of endpoints to manage your application which can be used with an API Key.</Box>
<Box>To authorize a request with an API Key, provide the Key ID as username and the Key Secret as password using <Link external={true} href={'https://datatracker.ietf.org/doc/html/rfc7617'}>Basic Authorization</Link>.</Box>
</SpaceBetween>
<SpaceBetween size={'xs'} direction={'vertical'}>
<Box variant={'h3'}>Available Endpoints</Box>
<Box variant={'h5'}>Modify Redirect URIs of an existing Client</Box>
<Textarea value={redirectURIEndpointExample} disabled={true} spellcheck={false} disableBrowserAutocorrect={true} rows={15} />
<TextContent><small>This endpoint requires the <samp>client:modify</samp> permission.</small></TextContent>
</SpaceBetween>
</SpaceBetween>
</HelpPanel>
);
}

0 comments on commit 972d641

Please sign in to comment.