Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: api keys #106

Merged
merged 5 commits into from
Nov 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
511 changes: 14 additions & 497 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
},
"dependencies": {
"@aw-labs/appwrite-console": "^10.0.0",
"@aw-labs/icons": "0.0.0-66",
"@aw-labs/ui": "0.0.0-66",
"@aw-labs/icons": "0.0.0-68",
"@aw-labs/ui": "0.0.0-68",
"@popperjs/core": "^2.11.6",
"echarts": "^5.4.0",
"prismjs": "^1.29.0",
Expand Down
10 changes: 9 additions & 1 deletion src/lib/components/collapsibleItem.svelte
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
<script lang="ts">
export let withIndentation = false;
</script>

<li class="collapsible-item">
<details class="collapsible-wrapper">
<summary class="collapsible-button">
<slot name="beforetitle" />
<span class="text"><slot name="title" /></span>
<span class="collapsible-button-optional"><slot name="subtitle" /></span>
<div class="icon">
<span class="icon-cheveron-down" aria-hidden="true" />
</div>
</summary>
<div class="collapsible-content">
<div
class="collapsible-content"
class:u-margin-block-start-8={withIndentation}
class:u-padding-inline-32={withIndentation}>
<slot />
</div>
</details>
Expand Down
6 changes: 5 additions & 1 deletion src/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ export enum Dependencies {
WEBHOOKS = 'webhooks'
}

export const scopes = [
export const scopes: {
scope: string;
description: string;
category: string;
}[] = [
{
scope: 'users.read',
description: "Access to read your project's users",
Expand Down
1 change: 0 additions & 1 deletion src/lib/stores/oauth-providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ const setProviders = (project: Models.Project): Provider[] => {

switch (n.name.toLowerCase()) {
case 'amazon':
console.log(n);
docs = 'https://developer.amazon.com/apps-and-games/services-and-apis';
break;
case 'apple':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,9 @@
import { Dependencies } from '$lib/constants';

async function onFinish() {
console.log(2);
await invalidate(Dependencies.FUNCTIONS);
}
async function create() {
console.log(1);
try {
const response = await sdkForProject.functions.create(
$createFunction.id ?? 'unique()',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

$: projectId = $page.params.project;
$: path = `/console/project-${projectId}/overview`;
$: console.log($stats.get(projectId));
let period: UsagePeriods = '30d';
let showPeriodBandwidth = false;
let showPeriodRequests = false;
Expand Down
23 changes: 14 additions & 9 deletions src/routes/console/project-[project]/overview/keys/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,21 @@
TableRowLink
} from '$lib/elements/table';
import { toLocaleDateTime } from '$lib/helpers/date';
import { wizard } from '$lib/stores/wizard';
import type { PageData } from './$types';
import Create from './create.svelte';
import Wizard from './wizard.svelte';

export let data: PageData;
let show = false;

function create() {
wizard.start(Wizard);
}
</script>

<div class="common-section u-flex u-gap-12">
<Heading tag="h3" size="7">API Keys</Heading>
<span class="u-margin-inline-start-auto">
<Button on:click={() => (show = true)}>
<Button on:click={create}>
<span class="icon-plus" aria-hidden="true" />
<span class="text">Create API Key</span>
</Button>
Expand All @@ -32,7 +37,7 @@
<TableCellHead>Name</TableCellHead>
<TableCellHead>last accessed</TableCellHead>
<TableCellHead>expiration date</TableCellHead>
<TableCellHead>clients</TableCellHead>
<TableCellHead>scopes</TableCellHead>
</TableHeader>
<TableBody>
{#each data.keys.keys as key}
Expand All @@ -44,15 +49,17 @@
{key.accessedAt ? toLocaleDateTime(key.accessedAt) : 'never'}
</TableCellText>
<TableCellText title="Expiration Date">
{toLocaleDateTime(key.$updatedAt)}
{key.expire ? toLocaleDateTime(key.expire) : 'never'}
</TableCellText>
<TableCellText title="Expiration Date">
{key.scopes.length} Scopes
</TableCellText>
<TableCellText title="Clients" />
</TableRowLink>
{/each}
</TableBody>
</Table>
{:else}
<Empty isButton single on:click={() => (show = true)}>
<Empty isButton single on:click={create}>
<div class="u-text-center">
<p class="text u-line-height-1-5">Create your first API Key to get started</p>
<p class="text u-line-height-1-5">Need a hand? Check out our documentation.</p>
Expand All @@ -63,5 +70,3 @@
</div>
</Empty>
{/if}

<Create bind:show />
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
let name: string = null;
let secret: string = null;
let expire: string = null;
let scopes: string[] = [];
let scopes: string[] = null;

onMount(() => {
name ??= $key.name;
Expand Down Expand Up @@ -135,16 +135,20 @@
practice to allow only the permissions you need to meet your project goals.
</p>
<svelte:fragment slot="aside">
<Scopes bind:scopes />
{#if scopes !== null}
<Scopes bind:scopes />
{/if}
</svelte:fragment>

<svelte:fragment slot="actions">
<Button
submit
disabled={!(
difference(scopes, $key.scopes).length !== 0 ||
difference($key.scopes, scopes).length !== 0
)}>Update</Button>
disabled={scopes &&
$key?.scopes &&
!(
difference(scopes, $key.scopes).length !== 0 ||
difference($key.scopes, scopes).length !== 0
)}>Update</Button>
</svelte:fragment>
</CardGrid>
</Form>
Expand Down
42 changes: 0 additions & 42 deletions src/routes/console/project-[project]/overview/keys/create.svelte

This file was deleted.

73 changes: 60 additions & 13 deletions src/routes/console/project-[project]/overview/keys/scopes.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@

export let scopes: string[];

enum Category {
Authentication = 'Authentication',
Database = 'Database',
Functions = 'Functions',
Storage = 'Storage',
Other = 'Other'
}

let mounted = false;

onMount(() => {
Expand All @@ -28,6 +36,29 @@
}
}

function categoryState(category: string, s: string[]): boolean | null {
const scopesByCategory = allScopes.filter((n) => n.category === category);
const filtered = scopesByCategory.filter((n) => s.includes(n.scope));
if (filtered.length === 0) {
return false;
} else if (filtered.length === scopesByCategory.length) {
return true;
} else {
return null;
}
}

function onCategoryChange(
event: Event & { currentTarget: EventTarget & HTMLInputElement },
category: Category
) {
allScopes.forEach((s) => {
if (s.category === category) {
activeScopes[s.scope] = event.currentTarget.checked;
}
});
}

const activeScopes = allScopes.reduce((prev, next) => {
prev[next.scope] = false;

Expand All @@ -54,19 +85,35 @@
<Button text on:click={selectAll}>Select all</Button>
</div>
<Collapsible>
{#each ['Authentication', 'Database', 'Functions', 'Storage', 'Other'] as category}
<CollapsibleItem>
<svelte:fragment slot="title">{category}</svelte:fragment>
<FormList>
{#each allScopes.filter((s) => s.category === category) as scope}
<InputChoice
id={scope.scope}
label={scope.scope}
bind:value={activeScopes[scope.scope]}>
{scope.description}
</InputChoice>
{/each}
</FormList>
{#each [Category.Authentication, Category.Database, Category.Functions, Category.Storage, Category.Other] as category}
{@const checked = categoryState(category, scopes)}
<CollapsibleItem withIndentation>
<svelte:fragment slot="beforetitle">
<input
type="checkbox"
{checked}
indeterminate={checked === null ? true : false}
on:change={(e) => onCategoryChange(e, category)} />
</svelte:fragment>
<svelte:fragment slot="title">
{category}
</svelte:fragment>
<svelte:fragment slot="subtitle">
({allScopes.filter((n) => n.category === category && scopes.includes(n.scope))
.length} Scopes)
</svelte:fragment>
<div class="form">
<FormList>
{#each allScopes.filter((s) => s.category === category) as scope}
<InputChoice
id={scope.scope}
label={scope.scope}
bind:value={activeScopes[scope.scope]}>
{scope.description}
</InputChoice>
{/each}
</FormList>
</div>
</CollapsibleItem>
{/each}
</Collapsible>
50 changes: 50 additions & 0 deletions src/routes/console/project-[project]/overview/keys/wizard.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<script lang="ts">
import { Wizard } from '$lib/layout';
import { beforeNavigate, goto } from '$app/navigation';
import { wizard } from '$lib/stores/wizard';
import type { WizardStepsType } from '$lib/layout/wizard.svelte';
import Step1 from './wizard/step1.svelte';
import Step2 from './wizard/step2.svelte';
import { key } from './wizard/store';
import { sdkForConsole } from '$lib/stores/sdk';
import { page } from '$app/stores';
import { addNotification } from '$lib/stores/notifications';
import { onDestroy } from 'svelte';

async function onFinish() {
try {
const { $id } = await sdkForConsole.projects.createKey(
$page.params.project,
$key.name,
$key.scopes,
$key.expire ?? undefined
);
goto(`/console/project-${$page.params.project}/overview/keys/${$id}`);
} catch (error) {
addNotification({
type: 'error',
message: error.message
});
}
}

onDestroy(() => {
key.reset();
});

beforeNavigate(() => {
wizard.hide();
});

const stepsComponents: WizardStepsType = new Map();
stepsComponents.set(1, {
label: 'Details',
component: Step1
});
stepsComponents.set(2, {
label: 'Scopes',
component: Step2
});
</script>

<Wizard title="Create an API Key" steps={stepsComponents} on:finish={onFinish} />
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<script lang="ts">
import { FormList, InputText, InputDateTime } from '$lib/elements/forms';
import { WizardStep } from '$lib/layout';
import { key } from './store';
</script>

<WizardStep>
<svelte:fragment slot="title">Create an API Key</svelte:fragment>
<svelte:fragment slot="subtitle">Let's create an API Key.</svelte:fragment>
<FormList>
<InputText
id="name"
label="Name"
placeholder="API Key Name"
required
bind:value={$key.name} />
<InputDateTime id="expire" label="Expiration Date" bind:value={$key.expire} />
</FormList>
</WizardStep>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<script lang="ts">
import { FormList } from '$lib/elements/forms';
import { WizardStep } from '$lib/layout';
import Scopes from '../scopes.svelte';
import { key } from './store';
</script>

<WizardStep>
<svelte:fragment slot="title">Add Scopes</svelte:fragment>
<svelte:fragment slot="subtitle">
Choose which permission scopes to grant your application. It is best practice to allow only
the permissions you need to meet your project goals.
</svelte:fragment>
<FormList>
<Scopes bind:scopes={$key.scopes} />
</FormList>
</WizardStep>
Loading