Merge pull request #274 from appwrite/refactor/api-details-page

Refactor: API key page design details
This commit is contained in:
Torsten Dittmann
2023-02-10 13:27:17 +01:00
committed by GitHub
7 changed files with 151 additions and 28 deletions
@@ -61,5 +61,7 @@
</div>
{#if error}
<Helper type="warning">{error}</Helper>
{:else}
<slot name="helper" />
{/if}
</FormItem>
+17
View File
@@ -22,3 +22,20 @@ export const toLocaleDateTime = (datetime: string | number) => {
return date.toLocaleDateString('en', options);
};
export const isSameDay = (date1: Date, date2: Date) => {
return (
date1.getFullYear() === date2.getFullYear() &&
date1.getMonth() === date2.getMonth() &&
date1.getDate() === date2.getDate()
);
};
export const isValidDate = (date: string) => {
return !isNaN(new Date(date).getTime());
};
export const diffDays = (date1: Date, date2: Date) => {
const diffTime = Math.abs(date2.getTime() - date1.getTime());
return Math.floor(diffTime / (1000 * 60 * 60 * 24));
};
@@ -63,7 +63,7 @@
trackEvent('submit_key_update_scopes');
addNotification({
type: 'success',
message: 'API Key scopes has been updated'
message: 'API Key scopes have been updated'
});
} catch (error) {
addNotification({
@@ -1,12 +1,10 @@
<script lang="ts">
import { invalidate } from '$app/navigation';
import { trackEvent } from '$lib/actions/analytics';
import CardGrid from '$lib/components/cardGrid.svelte';
import Heading from '$lib/components/heading.svelte';
import { Alert, CardGrid, Heading } from '$lib/components';
import { Dependencies } from '$lib/constants';
import { Form } from '$lib/elements/forms';
import Button from '$lib/elements/forms/button.svelte';
import FormList from '$lib/elements/forms/formList.svelte';
import { Button, Form, FormList } from '$lib/elements/forms';
import { diffDays } from '$lib/helpers/date';
import { addNotification } from '$lib/stores/notifications';
import { sdkForConsole } from '$lib/stores/sdk';
import { project } from '../../../store';
@@ -37,6 +35,11 @@
});
}
}
let alertsDismissed = false;
$: isExpiring =
!alertsDismissed && $key.expire && diffDays(new Date(), new Date($key.expire)) < 14;
$: isExpired = !alertsDismissed && $key.expire !== null && new Date($key.expire) < new Date();
</script>
<Form on:submit={updateExpire}>
@@ -44,6 +47,20 @@
<Heading tag="h6" size="7">Update Expiration Date</Heading>
<p class="text">Set a date after which your API Key will expire.</p>
<svelte:fragment slot="aside">
{#if isExpired}
<Alert type="error" dismissible on:dismiss={() => (alertsDismissed = true)}>
<span slot="title">Your API Key has expired</span>
<p>
For security reasons, we recommend you delete your expired key and create a
new one.
</p>
</Alert>
{:else if isExpiring}
<Alert type="warning" dismissible on:dismiss={() => (alertsDismissed = true)}>
<span slot="title">Your API Key is about to expire</span>
<p>Update the expiration date to keep the key active</p>
</Alert>
{/if}
<FormList>
<ExpirationInput bind:value={expiration} />
</FormList>
@@ -1,6 +1,8 @@
<script lang="ts">
import Helper from '$lib/elements/forms/helper.svelte';
import InputDateTime from '$lib/elements/forms/inputDateTime.svelte';
import InputSelect from '$lib/elements/forms/inputSelect.svelte';
import { isSameDay, isValidDate, toLocaleDate } from '$lib/helpers/date';
function incrementToday(value: number, type: 'day' | 'month' | 'year'): string {
const date = new Date();
@@ -19,18 +21,7 @@
return date.toISOString();
}
export let value: string | null = null;
let expirationSelect = value === null ? null : 'custom';
let expirationCustom: string | null = value ?? null;
$: {
value = expirationSelect === 'custom' ? expirationCustom : expirationSelect;
}
</script>
<InputSelect
bind:value={expirationSelect}
options={[
const options = [
{
label: 'Never',
value: null
@@ -55,9 +46,42 @@
label: 'Custom Date',
value: 'custom'
}
]}
id="preset"
label="Expiration Date" />
];
export let value: string | null = null;
function initExpirationSelect() {
if (value === null || !isValidDate(value)) return null;
let result = 'custom';
for (const option of options) {
if (!isValidDate(option.value)) continue;
if (isSameDay(new Date(option.value), new Date(value))) {
result = option.value;
break;
}
}
return result;
}
let expirationSelect = initExpirationSelect();
let expirationCustom: string | null = value ?? null;
$: {
if (!isSameDay(new Date(expirationSelect), new Date(value))) {
value = expirationSelect === 'custom' ? expirationCustom : expirationSelect;
}
}
</script>
<InputSelect bind:value={expirationSelect} {options} id="preset" label="Expiration Date">
<svelte:fragment slot="helper">
{#if expirationSelect !== 'custom' && expirationSelect !== null}
<Helper type="neutral">Your key will expire in {toLocaleDate(value)}</Helper>
{/if}
</svelte:fragment>
</InputSelect>
{#if expirationSelect === 'custom'}
<InputDateTime id="expire" label="" bind:value={expirationCustom} showLabel={false} />
{/if}
@@ -77,10 +77,15 @@
}
</script>
<div class="u-flex u-cross-center u-main-end">
<Button text on:click={deselectAll}>Deselect all</Button>
<Button text on:click={selectAll}>Select all</Button>
</div>
<ul class="buttons-list u-main-end">
<li class="buttons-list-item">
<Button text on:click={deselectAll}>Deselect all</Button>
</li>
<li class="buttons-list-item">
<Button text on:click={selectAll}>Select all</Button>
</li>
</ul>
<Collapsible>
{#each [Category.Auth, Category.Database, Category.Functions, Category.Storage, Category.Other] as category}
{@const checked = categoryState(category, scopes)}
@@ -96,8 +101,11 @@
{category}
</svelte:fragment>
<svelte:fragment slot="subtitle">
({allScopes.filter((n) => n.category === category && scopes.includes(n.scope))
.length} Scopes)
{@const scopesLength = allScopes.filter(
(n) => n.category === category && scopes.includes(n.scope)
).length}
({scopesLength}
{scopesLength === 1 ? 'Scope' : 'Scopes'})
</svelte:fragment>
<div class="form">
<FormList>
+56 -1
View File
@@ -1,5 +1,11 @@
import '@testing-library/jest-dom';
import { toLocaleDate, toLocaleDateTime } from '$lib/helpers/date';
import {
toLocaleDate,
toLocaleDateTime,
isSameDay,
isValidDate,
diffDays
} from '$lib/helpers/date';
describe('local date', () => {
[
@@ -22,3 +28,52 @@ describe('local date time', () => {
});
});
});
describe('is same day', () => {
const entries: Array<[string, string, boolean]> = [
['2022-11-15 08:26:28', '2022-11-15 08:26:28', true],
['2022-11-15 08:26:28', '2022-11-16 08:26:28', false],
['2022-11-15 08:26:28', '2022-11-15 08:26:29', true],
['2022-11-15 08:26:28', '2022-11-15 08:26:27', true]
];
entries.forEach(([value1, value2, expected]) => {
it(`${value1} ${value2}`, () => {
expect(isSameDay(new Date(value1), new Date(value2))).toBe(expected);
});
});
});
describe('is valid date', () => {
const entries: Array<[string, boolean]> = [
['2022-11-15 08:26:28', true],
['2022-11-15 08:26:28', true],
['abc', false],
['2022-11-15', true],
['123.123.123', false]
];
entries.forEach(([value, expected]) => {
it(value, () => {
expect(isValidDate(value)).toBe(expected);
});
});
});
describe('diff days', () => {
const entries: Array<[string, string, number]> = [
['2022-11-15 08:26:28', '2022-11-15 08:26:28', 0],
['2022-11-15 08:26:28', '2022-11-16 08:26:28', 1],
['2022-11-15 08:26:28', '2022-11-16 08:26:27', 0],
['2022-11-15 08:26:28', '2022-11-14 08:26:29', 0],
['2022-11-15 08:26:28', '2022-11-14 08:26:27', 1],
['2022-11-15 08:26:28', '2022-11-20 08:26:29', 5],
['2022-11-15 08:26:28', '2022-11-20 08:26:27', 4]
];
entries.forEach(([value1, value2, expected]) => {
it(`${value1} ${value2}`, () => {
expect(diffDays(new Date(value1), new Date(value2))).toBe(expected);
});
});
});