Skip to content

Commit 64ad4dc

Browse files
authored
Merge pull request #1762 from appwrite/devkeys-pink2
DevKeys on Pink2
2 parents 692548b + 0692f28 commit 64ad4dc

30 files changed

+1026
-528
lines changed

src/lib/actions/analytics.ts

+7
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ export enum Click {
162162
FunctionsDeploymentDeleteClick = 'click_deployment_delete',
163163
FunctionsDeploymentCancelClick = 'click_deployment_cancel',
164164
KeyCreateClick = 'click_key_create',
165+
DevKeyCreateClick = 'click_dev_key_create',
165166
MenuDropDownClick = 'click_menu_dropdown',
166167
MenuOverviewClick = 'click_menu_overview',
167168
ModalCloseClick = 'click_close_modal',
@@ -313,12 +314,18 @@ export enum Submit {
313314
VariableDelete = 'submit_variable_delete',
314315
VariableUpdate = 'submit_variable_update',
315316
VariableEditor = 'submit_variable_editor',
317+
316318
KeyCreate = 'submit_key_create',
317319
KeyDelete = 'submit_key_delete',
318320
KeyUpdateName = 'submit_key_update_name',
319321
KeyUpdateScopes = 'submit_key_update_scopes',
320322
KeyUpdateExpire = 'submit_key_update_expire',
321323

324+
DevKeyCreate = 'submit_dev_key_create',
325+
DevKeyDelete = 'submit_dev_key_delete',
326+
DevKeyUpdateName = 'submit_dev_key_update_name',
327+
DevKeyUpdateExpire = 'submit_dev_key_update_expire',
328+
322329
PlatformCreate = 'submit_platform_create',
323330
PlatformDelete = 'submit_platform_delete',
324331
PlatformUpdate = 'submit_platform_update',
-87
Original file line numberDiff line numberDiff line change
@@ -1,87 +0,0 @@
1-
<script lang="ts">
2-
import { InputDateTime, InputSelect } from '$lib/elements/forms';
3-
import { isSameDay, isValidDate, toLocaleDate } from '$lib/helpers/date';
4-
5-
function incrementToday(value: number, type: 'day' | 'month' | 'year'): string {
6-
const date = new Date();
7-
switch (type) {
8-
case 'day':
9-
date.setDate(date.getDate() + value);
10-
break;
11-
case 'month':
12-
date.setMonth(date.getMonth() + value);
13-
break;
14-
case 'year':
15-
date.setMonth(date.getMonth() + value * 12);
16-
break;
17-
}
18-
19-
return date.toISOString();
20-
}
21-
22-
const options = [
23-
{
24-
label: 'Never',
25-
value: null
26-
},
27-
{
28-
label: '7 Days',
29-
value: incrementToday(7, 'day')
30-
},
31-
{
32-
label: '30 days',
33-
value: incrementToday(30, 'day')
34-
},
35-
{
36-
label: '90 days',
37-
value: incrementToday(90, 'day')
38-
},
39-
{
40-
label: '1 Year',
41-
value: incrementToday(1, 'year')
42-
},
43-
{
44-
label: 'Custom Date',
45-
value: 'custom'
46-
}
47-
];
48-
49-
export let value: string | null = null;
50-
export let dateSelectorLabel: string | undefined = undefined;
51-
export let selectorLabel: string | undefined = 'Expiration Date';
52-
export let resourceType: string | 'key' | 'token' | undefined = 'key';
53-
54-
function initExpirationSelect() {
55-
if (value === null || !isValidDate(value)) return null;
56-
57-
let result = 'custom';
58-
for (const option of options) {
59-
if (!isValidDate(option.value)) continue;
60-
61-
if (isSameDay(new Date(option.value), new Date(value))) {
62-
result = option.value;
63-
break;
64-
}
65-
}
66-
67-
return result;
68-
}
69-
let expirationSelect = initExpirationSelect();
70-
let expirationCustom: string | null = value ?? null;
71-
$: helper =
72-
expirationSelect !== 'custom' && expirationSelect !== null
73-
? `Your ${resourceType} will expire in ${toLocaleDate(value)}`
74-
: null;
75-
76-
$: {
77-
if (!isSameDay(new Date(expirationSelect), new Date(value))) {
78-
value = expirationSelect === 'custom' ? expirationCustom : expirationSelect;
79-
}
80-
}
81-
</script>
82-
83-
<InputSelect bind:value={expirationSelect} {options} id="preset" label={selectorLabel} {helper}>
84-
</InputSelect>
85-
{#if expirationSelect === 'custom'}
86-
<InputDateTime required id="expire" label={dateSelectorLabel} bind:value={expirationCustom} />
87-
{/if}

src/lib/constants.ts

+2
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ export enum Dependencies {
4848
PLATFORMS = 'dependency:platforms',
4949
KEY = 'dependency:key',
5050
KEYS = 'dependency:keys',
51+
DEV_KEY = 'dependency:dev_key',
52+
DEV_KEYS = 'dependency:dev_keys',
5153
DOMAINS = 'dependency:domains',
5254
DOMAIN = 'dependency:domains',
5355
WEBHOOK = 'dependency:webhook',

src/lib/layout/usage.svelte

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<script context="module" lang="ts">
2+
import { ProjectUsageRange, type Models } from '@appwrite.io/console';
23
export type UsagePeriods = '24h' | '30d' | '90d';
34
45
export function periodToDates(period: UsagePeriods): {
@@ -68,14 +69,14 @@
6869
</script>
6970

7071
<script lang="ts">
71-
import { BarChart } from '$lib/charts';
72-
import { formatNumberWithCommas } from '$lib/helpers/numbers';
73-
import { Card } from '$lib/components';
74-
import { ProjectUsageRange, type Models } from '@appwrite.io/console';
7572
import { page } from '$app/state';
76-
import { Layout, Typography } from '@appwrite.io/pink-svelte';
7773
import { goto } from '$app/navigation';
74+
75+
import { BarChart } from '$lib/charts';
76+
import { Card } from '$lib/components';
7877
import { InputSelect } from '$lib/elements/forms';
78+
import { formatNumberWithCommas } from '$lib/helpers/numbers';
79+
import { Layout, Typography } from '@appwrite.io/pink-svelte';
7980
8081
type MetricMetadata = {
8182
title: string;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
<script lang="ts">
2+
import { base } from '$app/paths';
3+
import { page } from '$app/stores';
4+
import { InputText } from '$lib/elements/forms/index.js';
5+
import { Wizard } from '$lib/layout';
6+
import { Fieldset, Layout, Typography } from '@appwrite.io/pink-svelte';
7+
import ExpirationInput from './expirationInput.svelte';
8+
import Button from '$lib/elements/forms/button.svelte';
9+
import Form from '$lib/elements/forms/form.svelte';
10+
import { sdk } from '$lib/stores/sdk';
11+
import { onboarding } from '../../store';
12+
import { goto, invalidate } from '$app/navigation';
13+
import { Dependencies } from '$lib/constants';
14+
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
15+
import { addNotification } from '$lib/stores/notifications';
16+
import { writable } from 'svelte/store';
17+
import Scopes from '../keys/scopes.svelte';
18+
19+
const projectId = $page.params.project;
20+
21+
let showExitModal = false;
22+
let formComponent: Form;
23+
let isSubmitting = writable(false);
24+
25+
let scopes = [];
26+
let name = '',
27+
expire = '';
28+
29+
async function create() {
30+
try {
31+
const { $id } = await sdk.forConsole.projects.createKey(
32+
projectId,
33+
name,
34+
scopes,
35+
expire || undefined
36+
);
37+
38+
if ($onboarding) {
39+
await invalidate(Dependencies.PROJECT);
40+
}
41+
42+
trackEvent(Submit.KeyCreate);
43+
await goto(`${base}/project-${projectId}/overview/keys/${$id}`);
44+
addNotification({
45+
message: `API key has been created`,
46+
type: 'success'
47+
});
48+
} catch (error) {
49+
addNotification({
50+
type: 'error',
51+
message: error.message
52+
});
53+
trackError(error, Submit.KeyCreate);
54+
}
55+
}
56+
</script>
57+
58+
<Wizard
59+
title="Create API key"
60+
href={`${base}/project-${projectId}/overview/keys/`}
61+
bind:showExitModal
62+
column
63+
columnSize="s"
64+
confirmExit>
65+
<Form bind:this={formComponent} onSubmit={create} bind:isSubmitting>
66+
<Layout.Stack gap="xxl">
67+
<Fieldset legend="Configuration">
68+
<Layout.Stack>
69+
<InputText
70+
id="name"
71+
label="Name"
72+
placeholder="Enter key name"
73+
required
74+
bind:value={name} />
75+
76+
<ExpirationInput bind:value={expire} keyType="api" />
77+
</Layout.Stack>
78+
</Fieldset>
79+
80+
<Fieldset legend="Scopes">
81+
<Layout.Stack gap="xl">
82+
<Typography.Text>
83+
Choose which permission scopes to grant your application. It is best
84+
practice to allow only the permissions you need to meet your project goals.
85+
</Typography.Text>
86+
<Scopes bind:scopes />
87+
</Layout.Stack>
88+
</Fieldset>
89+
</Layout.Stack>
90+
</Form>
91+
92+
<svelte:fragment slot="footer">
93+
<Button fullWidthMobile secondary on:click={() => (showExitModal = true)}>Cancel</Button>
94+
<Button
95+
fullWidthMobile
96+
on:click={() => formComponent.triggerSubmit()}
97+
disabled={$isSubmitting}>
98+
Create
99+
</Button>
100+
</svelte:fragment>
101+
</Wizard>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<script lang="ts">
2+
import { page } from '$app/state';
3+
import { base } from '$app/paths';
4+
import { sdk } from '$lib/stores/sdk';
5+
import { Dependencies } from '$lib/constants';
6+
import { type Models } from '@appwrite.io/console';
7+
import { goto, invalidate } from '$app/navigation';
8+
import Confirm from '$lib/components/confirm.svelte';
9+
import { addNotification } from '$lib/stores/notifications';
10+
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
11+
12+
export let showDelete = false;
13+
export let keyType: 'api' | 'dev' = 'api';
14+
export let key: Models.DevKey | Models.Key;
15+
16+
const projectId = page.params.project;
17+
18+
const isApiKey = keyType === 'api';
19+
const label = isApiKey ? 'API' : 'Dev';
20+
const slug = isApiKey ? 'keys' : 'dev-keys';
21+
const event = isApiKey ? Submit.KeyDelete : Submit.DevKeyDelete;
22+
const dependency = isApiKey ? Dependencies.KEYS : Dependencies.DEV_KEYS;
23+
24+
let error: string;
25+
26+
async function handleDelete() {
27+
try {
28+
isApiKey
29+
? await sdk.forConsole.projects.deleteKey(projectId, key.$id)
30+
: await sdk.forConsole.projects.deleteDevKey(projectId, key.$id);
31+
32+
await invalidate(dependency);
33+
showDelete = false;
34+
addNotification({
35+
type: 'success',
36+
message: `${key.name} has been deleted`
37+
});
38+
trackEvent(event);
39+
await goto(`${base}/project-${projectId}/overview/${slug}`);
40+
} catch (e) {
41+
error = e.message;
42+
trackError(e, event);
43+
}
44+
}
45+
</script>
46+
47+
<Confirm onSubmit={handleDelete} title="Delete {label} key" bind:open={showDelete} bind:error>
48+
Are you sure you want to delete this key?
49+
</Confirm>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<script lang="ts">
2+
import { page } from '$app/state';
3+
import { base } from '$app/paths';
4+
import { sdk } from '$lib/stores/sdk';
5+
import { Dependencies } from '$lib/constants';
6+
import { goto, invalidate } from '$app/navigation';
7+
import Confirm from '$lib/components/confirm.svelte';
8+
import { addNotification } from '$lib/stores/notifications';
9+
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
10+
11+
export let showDelete = false;
12+
export let keyIds: string[] = [];
13+
export let keyType: 'api' | 'dev' = 'api';
14+
15+
let error: string;
16+
17+
const isApiKey = keyType === 'api';
18+
const label = isApiKey ? 'API' : 'dev';
19+
const projectId = page.params.project;
20+
21+
async function handleDelete() {
22+
const slug = isApiKey ? 'keys' : 'dev-keys';
23+
const event = isApiKey ? Submit.KeyDelete : Submit.DevKeyDelete;
24+
const dependency = isApiKey ? Dependencies.KEYS : Dependencies.DEV_KEYS;
25+
26+
try {
27+
await Promise.all(
28+
keyIds.map((key) =>
29+
isApiKey
30+
? sdk.forConsole.projects.deleteKey(projectId, key)
31+
: sdk.forConsole.projects.deleteDevKey(projectId, key)
32+
)
33+
);
34+
35+
await invalidate(dependency);
36+
showDelete = false;
37+
38+
addNotification({
39+
type: 'success',
40+
message: `${keyIds.length} ${label} key${keyIds.length > 1 ? 's' : ''} deleted`
41+
});
42+
43+
trackEvent(event);
44+
await goto(`${base}/project-${projectId}/overview/${slug}`);
45+
} catch (e) {
46+
error = e.message;
47+
trackError(e, event);
48+
} finally {
49+
keyIds = [];
50+
}
51+
}
52+
</script>
53+
54+
<Confirm onSubmit={handleDelete} title={`Delete ${label} key`} bind:open={showDelete} bind:error>
55+
<p>
56+
Are you sure you want to delete <b>{keyIds.length}</b>
57+
{label} key{keyIds.length > 1 ? 's' : ''}?
58+
</p>
59+
</Confirm>

0 commit comments

Comments
 (0)