Merge branch 'main' of github.com:appwrite/console into feat-databases-v2

This commit is contained in:
Arman
2023-03-29 16:12:22 +02:00
9 changed files with 268 additions and 8 deletions
+2
View File
@@ -141,6 +141,8 @@ export enum Submit {
TeamUpdateName = 'submit_team_update_name',
AuthLimitUpdate = 'submit_auth_limit_update',
AuthStatusUpdate = 'submit_auth_status_update',
AuthPasswordHistoryUpdate = 'submit_auth_password_history_limit_update',
AuthPasswordDictionaryUpdate = 'submit_auth_password_dictionary_update',
SessionsLengthUpdate = 'submit_sessions_length_update',
SessionsLimitUpdate = 'submit_sessions_limit_update',
SessionDelete = 'submit_session_delete',
+1 -1
View File
@@ -15,7 +15,7 @@
export let maxlength: number = null;
// https://www.geeksforgeeks.org/how-to-validate-a-domain-name-using-regular-expression/
const pattern = String.raw`^(?!-)[A-Za-z0-9-]+([\-\.]{1}[a-z0-9]+)*\.[A-Za-z]{2,6}$`;
const pattern = String.raw`^(?!-)[A-Za-z0-9-]+([\-\.]{1}[a-z0-9]+)*\.[A-Za-z]{2,18}$`;
let element: HTMLInputElement;
let error: string;
+1 -1
View File
@@ -163,7 +163,7 @@
</div>
{#if subNavigation}
<div class="side-nav-level-2 is-open" transition:slide={{ axis: 'x', duration: 250 }}>
<div class="side-nav-level-2 is-open" transition:slide|local={{ axis: 'x', duration: 250 }}>
<div class="side-nav-main">
<svelte:component this={subNavigation} />
</div>
+5 -5
View File
@@ -1,17 +1,17 @@
<script lang="ts">
import { navigating, page } from '$app/stores';
import { browser } from '$app/environment';
import { wizard } from '$lib/stores/wizard';
import { log } from '$lib/stores/logs';
import { beforeNavigate } from '$app/navigation';
import { page } from '$app/stores';
import { log } from '$lib/stores/logs';
import { wizard } from '$lib/stores/wizard';
export let isOpen = false;
export let showSideNavigation = false;
let y: number;
navigating.subscribe(() => {
if (isOpen) isOpen = false;
page.subscribe(({ url }) => {
isOpen = url.searchParams.get('openNavbar') === 'true';
});
const toggleMenu = () => {
@@ -1,5 +1,7 @@
<script lang="ts">
import { Container } from '$lib/layout';
import UpdatePasswordDictionary from './updatePasswordDictionary.svelte';
import UpdatePasswordHistory from './updatePasswordHistory.svelte';
import UpdateSessionLength from './updateSessionLength.svelte';
import UpdateSessionsLimit from './updateSessionsLimit.svelte';
import UpdateUsersLimit from './updateUsersLimit.svelte';
@@ -9,4 +11,6 @@
<UpdateUsersLimit />
<UpdateSessionLength />
<UpdateSessionsLimit />
<UpdatePasswordHistory />
<UpdatePasswordDictionary />
</Container>
@@ -0,0 +1,62 @@
<script lang="ts">
import { invalidate } from '$app/navigation';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { CardGrid, Heading } from '$lib/components';
import { Dependencies } from '$lib/constants';
import { Button, Form, FormList, InputSwitch } from '$lib/elements/forms';
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
import { project } from '../../store';
const projectId = $project.$id;
let passwordDictionary = $project.authPasswordDictionary ?? false;
async function updatePasswordDictionary() {
try {
await sdk.forConsole.projects.updateAuthPasswordDictionary(
projectId,
passwordDictionary
);
await invalidate(Dependencies.PROJECT);
addNotification({
type: 'success',
message: 'Updated password dictionary check.'
});
trackEvent(Submit.AuthPasswordDictionaryUpdate);
} catch (error) {
addNotification({
type: 'error',
message: error.message
});
trackError(error, Submit.AuthPasswordDictionaryUpdate);
}
}
</script>
<Form onSubmit={updatePasswordDictionary}>
<CardGrid>
<Heading tag="h2" size="6">Password Dictionary</Heading>
<svelte:fragment slot="aside">
<FormList>
<InputSwitch
bind:value={passwordDictionary}
id="passwordDictionary"
label="Password Dictionary" />
</FormList>
<p class="text">
Enabling this option prevent users from setting insecure passwords by comparing the
user's password with the <a
target="_blank"
rel="noopener noreferrer"
class="link"
href="https://github.com/danielmiessler/SecLists/blob/master/Passwords/Common-Credentials/10k-most-common.txt"
>10k most commonly used passwords.</a>
</p>
</svelte:fragment>
<svelte:fragment slot="actions">
<Button disabled={passwordDictionary === $project.authPasswordDictionary} submit
>Update</Button>
</svelte:fragment>
</CardGrid>
</Form>
@@ -0,0 +1,76 @@
<script lang="ts">
import { invalidate } from '$app/navigation';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { CardGrid, Heading } from '$lib/components';
import { Dependencies } from '$lib/constants';
import { Button, Form, InputNumber, InputSwitch } from '$lib/elements/forms';
import FormList from '$lib/elements/forms/formList.svelte';
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
import { project } from '../../store';
const projectId = $project.$id;
let passwordHistory = $project.authPasswordHistory < 1 ? 5 : $project.authPasswordHistory;
let passwordHistoryEnabled = ($project.authPasswordHistory ?? 0) != 0;
let initialPasswordHistoryEnabled = passwordHistoryEnabled;
async function updatePasswordHistoryLimit() {
try {
await sdk.forConsole.projects.updateAuthPasswordHistory(
projectId,
passwordHistoryEnabled ? passwordHistory : 0
);
await invalidate(Dependencies.PROJECT);
initialPasswordHistoryEnabled = passwordHistoryEnabled;
addNotification({
type: 'success',
message: 'Updated password history limit.'
});
trackEvent(Submit.AuthPasswordHistoryUpdate);
} catch (error) {
addNotification({
type: 'error',
message: error.message
});
trackError(error, Submit.AuthPasswordHistoryUpdate);
}
}
</script>
<Form onSubmit={updatePasswordHistoryLimit}>
<CardGrid>
<Heading tag="h2" size="6">Password History</Heading>
<svelte:fragment slot="aside">
<FormList>
<InputSwitch
bind:value={passwordHistoryEnabled}
id="passwordHisotryEnabled"
label="Password History" />
</FormList>
<p class="text">
Enabling this option prevents users from reusing recent passwords by comparing the
new password with their password history.
</p>
<p class="text">
Set the maximum number of passwords saved per user. Maximum 20 passwords.
</p>
<FormList>
<InputNumber
max={20}
min={1}
id="max-session"
label="Limit"
disabled={!passwordHistoryEnabled}
bind:value={passwordHistory} />
</FormList>
</svelte:fragment>
<svelte:fragment slot="actions">
<Button
disabled={(passwordHistory === $project.authPasswordHistory ||
$project.authPasswordHistory === 0) &&
initialPasswordHistoryEnabled === passwordHistoryEnabled}
submit>Update</Button>
</svelte:fragment>
</CardGrid>
</Form>
@@ -17,7 +17,7 @@
<section class="drop-section u-flex-vertical u-gap-8">
<a
class="u-flex u-cross-center u-sep-block-end u-padding-block-12 is-not-desktop"
href={`${base}/console/project-${project}/databases/database-${databaseId}`}>
href={`${base}/console/project-${project}/databases/database-${databaseId}?openNavbar=true`}>
<span class="icon-cheveron-left" aria-hidden="true" />
<h5 class="eyebrow-heading-3 u-margin-inline-auto">Collections</h5>
</a>
+116
View File
@@ -0,0 +1,116 @@
import '@testing-library/jest-dom';
import { render } from '@testing-library/svelte';
import userEvent from '@testing-library/user-event';
import { InputDomain } from '../../../src/lib/elements/forms';
const validStrings = ['example.com', 'i-need.travelersinsurance', 'sub.domain.com'];
const invalidStrings = ['not-a-domain', 'tld-too-short.a', 'tld-too-long.overeighteencharacters'];
test('shows domain input', () => {
const { getByText, getByLabelText } = render(InputDomain, { id: 'input', label: 'input' });
const input = getByLabelText('input');
expect(getByText('input')).toBeInTheDocument();
expect(input).toBeInTheDocument();
expect(input).toHaveAttribute('type', 'text');
});
test('shows domain input - required', () => {
const { getByLabelText } = render(InputDomain, { id: 'input', label: 'input', required: true });
expect(getByLabelText('input')).toBeRequired();
});
test('shows domain input - disabled', () => {
const { getByLabelText } = render(InputDomain, { id: 'input', label: 'input', disabled: true });
expect(getByLabelText('input')).toBeDisabled();
});
test('shows domain input - autofocus', () => {
const { getByLabelText } = render(InputDomain, {
id: 'input',
label: 'input',
autofocus: true
});
expect(getByLabelText('input')).toHaveFocus();
});
test('shows domain input - placeholder', () => {
const { getByPlaceholderText } = render(InputDomain, {
id: 'input',
label: 'input',
placeholder: 'find me'
});
expect(getByPlaceholderText('find me')).toBeInTheDocument();
});
test('shows domain input - hide label', () => {
render(InputDomain, {
id: 'input',
label: 'label',
showLabel: false
});
const label = document.querySelector('label');
expect(label).toHaveClass('u-hide');
});
test('shows domain input - autocomplete', () => {
const { getByLabelText } = render(InputDomain, {
id: 'input',
label: 'input',
autocomplete: true
});
expect(getByLabelText('input')).toHaveAttribute('autocomplete', 'on');
});
test('shows domain input - maxlength', () => {
const { getByLabelText } = render(InputDomain, {
id: 'input',
label: 'input',
maxlength: 2
});
expect(getByLabelText('input')).toHaveAttribute('maxlength', '2');
});
test('state', async () => {
const { component, getByLabelText } = render(InputDomain, {
id: 'input',
label: 'input',
value: ''
});
const input = getByLabelText('input');
expect(component.value).toEqual('');
await userEvent.type(input, 'lorem');
expect(component.value).toEqual('lorem');
});
validStrings.forEach((validString) => {
test(`validates ${validString} as valid`, () => {
const { getByLabelText } = render(InputDomain, {
id: 'input',
label: 'input',
value: validString
});
const input = getByLabelText('input') as HTMLInputElement;
expect(input.checkValidity()).toBe(true);
});
});
invalidStrings.forEach((invalidString) => {
test(`validates ${invalidString} as invalid`, () => {
const { getByLabelText } = render(InputDomain, {
id: 'input',
label: 'input',
value: invalidString
});
const input = getByLabelText('input') as HTMLInputElement;
expect(input.checkValidity()).toBe(false);
});
});