diff --git a/package-lock.json b/package-lock.json index e55007247..b925c1ed7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,8 +9,8 @@ "version": "0.0.1", "dependencies": { "@aw-labs/appwrite-console": "^1.0.0-0", - "@aw-labs/icons": "0.0.0-53", - "@aw-labs/ui": "0.0.0-53", + "@aw-labs/icons": "0.0.0-54", + "@aw-labs/ui": "0.0.0-54", "echarts": "^5.3.3", "tippy.js": "^6.3.7", "web-vitals": "^2.1.4" @@ -77,14 +77,14 @@ } }, "node_modules/@aw-labs/icons": { - "version": "0.0.0-53", - "resolved": "https://registry.npmjs.org/@aw-labs/icons/-/icons-0.0.0-53.tgz", - "integrity": "sha512-9UhHTGajh2HJun2uYbcMyxRtPsgIQ5CXf8mn/sCiRyZJIw5FYtuxTSkP/35hv2zJsVq/mY09HvfdX3w4XVKItg==" + "version": "0.0.0-54", + "resolved": "https://registry.npmjs.org/@aw-labs/icons/-/icons-0.0.0-54.tgz", + "integrity": "sha512-lk+uikRag3Y5Rm4Ys5lHBhknhCVpA/oTaIBBDgB6nidqtJdqLpa+Nur4BdsBXOEZTlo2yOiWU2NNAl6ZzUzFGQ==" }, "node_modules/@aw-labs/ui": { - "version": "0.0.0-53", - "resolved": "https://registry.npmjs.org/@aw-labs/ui/-/ui-0.0.0-53.tgz", - "integrity": "sha512-5ftq05SZ9lVdXGHgHIyxwtGznfKsCa1fKPpZhS+279IUTIB+H7GIq0g2U2EzRBj7ht0PXNZJNO4n9hO2ItDJwA==", + "version": "0.0.0-54", + "resolved": "https://registry.npmjs.org/@aw-labs/ui/-/ui-0.0.0-54.tgz", + "integrity": "sha512-1Dj216qPaVKdBScW+1XIp6IOVBdcv/kYjiWO4YiFtoQ/IaayoSO6njlAPTwyQzclmX5A/9suEGadOVa3NZqbgQ==", "dependencies": { "@aw-labs/icons": "*" } @@ -7698,14 +7698,14 @@ } }, "@aw-labs/icons": { - "version": "0.0.0-53", - "resolved": "https://registry.npmjs.org/@aw-labs/icons/-/icons-0.0.0-53.tgz", - "integrity": "sha512-9UhHTGajh2HJun2uYbcMyxRtPsgIQ5CXf8mn/sCiRyZJIw5FYtuxTSkP/35hv2zJsVq/mY09HvfdX3w4XVKItg==" + "version": "0.0.0-54", + "resolved": "https://registry.npmjs.org/@aw-labs/icons/-/icons-0.0.0-54.tgz", + "integrity": "sha512-lk+uikRag3Y5Rm4Ys5lHBhknhCVpA/oTaIBBDgB6nidqtJdqLpa+Nur4BdsBXOEZTlo2yOiWU2NNAl6ZzUzFGQ==" }, "@aw-labs/ui": { - "version": "0.0.0-53", - "resolved": "https://registry.npmjs.org/@aw-labs/ui/-/ui-0.0.0-53.tgz", - "integrity": "sha512-5ftq05SZ9lVdXGHgHIyxwtGznfKsCa1fKPpZhS+279IUTIB+H7GIq0g2U2EzRBj7ht0PXNZJNO4n9hO2ItDJwA==", + "version": "0.0.0-54", + "resolved": "https://registry.npmjs.org/@aw-labs/ui/-/ui-0.0.0-54.tgz", + "integrity": "sha512-1Dj216qPaVKdBScW+1XIp6IOVBdcv/kYjiWO4YiFtoQ/IaayoSO6njlAPTwyQzclmX5A/9suEGadOVa3NZqbgQ==", "requires": { "@aw-labs/icons": "*" } diff --git a/package.json b/package.json index 3c1f7f036..dca4c74ed 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,8 @@ }, "dependencies": { "@aw-labs/appwrite-console": "^1.0.0-0", - "@aw-labs/icons": "0.0.0-53", - "@aw-labs/ui": "0.0.0-53", + "@aw-labs/icons": "0.0.0-54", + "@aw-labs/ui": "0.0.0-54", "echarts": "^5.3.3", "tippy.js": "^6.3.7", "web-vitals": "^2.1.4" diff --git a/src/lib/components/copyInput.svelte b/src/lib/components/copyInput.svelte index 507d69fcc..782e89c80 100644 --- a/src/lib/components/copyInput.svelte +++ b/src/lib/components/copyInput.svelte @@ -4,6 +4,8 @@ import { addNotification } from '$lib/stores/notifications'; export let value: string; + export let label: string = null; + export let showLabel = false; let content = 'Click to copy'; @@ -21,17 +23,20 @@
- - + +
+ + +
diff --git a/src/lib/components/gridItem1.svelte b/src/lib/components/gridItem1.svelte index d0f961f05..b84c29708 100644 --- a/src/lib/components/gridItem1.svelte +++ b/src/lib/components/gridItem1.svelte @@ -26,22 +26,32 @@ -
-
-

-
+
+
+
+

+
+
-
- - {#if more} - - +{more} - - {/if} + +
+
+ + {#if more} + + +{more} + + {/if} +
+
+
+
    + +
-
    - -
diff --git a/src/lib/components/modal.svelte b/src/lib/components/modal.svelte index 05da1e24f..8a85e526b 100644 --- a/src/lib/components/modal.svelte +++ b/src/lib/components/modal.svelte @@ -10,6 +10,7 @@ export let error: string = null; export let closable = true; + let alert: HTMLElement; const dispatch = createEventDispatcher(); const transitionFly: FlyParams = { duration: 150, @@ -48,6 +49,10 @@ document.body.classList.remove('u-overflow-hidden'); } } + + $: if (error) { + alert?.scrollIntoView({ behavior: 'smooth', block: 'start', inline: 'nearest' }); + } @@ -81,14 +86,16 @@ diff --git a/src/lib/elements/forms/index.ts b/src/lib/elements/forms/index.ts index 48988a2fe..7ed7d656f 100644 --- a/src/lib/elements/forms/index.ts +++ b/src/lib/elements/forms/index.ts @@ -15,5 +15,6 @@ export { default as InputSearch } from './inputSearch.svelte'; export { default as InputRadio } from './inputRadio.svelte'; export { default as InputSelect } from './inputSelect.svelte'; export { default as InputCheckbox } from './inputCheckbox.svelte'; +export { default as InputChoice } from './inputChoice.svelte'; export { default as InputPhone } from './inputPhone.svelte'; export { default as Helper } from './helper.svelte'; diff --git a/src/lib/elements/forms/inputChoice.svelte b/src/lib/elements/forms/inputChoice.svelte new file mode 100644 index 000000000..be04a386a --- /dev/null +++ b/src/lib/elements/forms/inputChoice.svelte @@ -0,0 +1,30 @@ + + + + + diff --git a/src/lib/elements/table/cellText.svelte b/src/lib/elements/table/cellText.svelte index a8a00db42..ca995e627 100644 --- a/src/lib/elements/table/cellText.svelte +++ b/src/lib/elements/table/cellText.svelte @@ -1,8 +1,9 @@
- +
diff --git a/src/lib/helpers/cache.ts b/src/lib/helpers/cache.ts new file mode 100644 index 000000000..770af75f6 --- /dev/null +++ b/src/lib/helpers/cache.ts @@ -0,0 +1,20 @@ +import { browser } from '$app/env'; +import { writable, type Writable } from 'svelte/store'; + +export function cachedStore>( + id: string, + callback: (store: Writable) => TMethods +): TMethods & Writable { + const store = writable(browser ? JSON.parse(sessionStorage.getItem(id)) : null); + + if (browser) { + store.subscribe((n) => sessionStorage?.setItem(id, JSON.stringify(n ?? ''))); + } + + return { + subscribe: store.subscribe, + set: store.set, + update: store.update, + ...callback(store) + }; +} diff --git a/src/lib/layout/header.svelte b/src/lib/layout/header.svelte index bd0dfc233..b4d0dabff 100644 --- a/src/lib/layout/header.svelte +++ b/src/lib/layout/header.svelte @@ -86,7 +86,9 @@ showDropdown = false; newOrgModal.set(true); }}>New organization - Your Account + (showDropdown = false)}>Your Account
diff --git a/src/lib/layout/notifications.svelte b/src/lib/layout/notifications.svelte index 7b019f930..202702799 100644 --- a/src/lib/layout/notifications.svelte +++ b/src/lib/layout/notifications.svelte @@ -4,8 +4,8 @@ {#if $notifications} -
-
    +
    +
      {#each $notifications as notification (notification.id)} { + await user.logout(); + await goto(`${base}/login`); + }; + const onScroll = () => { if (!tabsList) { return; @@ -77,9 +86,21 @@ } }; }; + + const toggleMenu = () => { + y = 0; + isOpen = !isOpen; + if (browser) { + if (isOpen) { + document.body.classList.add('u-overflow-hidden'); + } else { + document.body.classList.remove('u-overflow-hidden'); + } + } + }; - +
      @@ -159,6 +181,12 @@ {$title} {/if} + {#if $page.url.pathname.includes('/console/account')} +
      + +
      + {/if} + {#if $copyData?.value} diff --git a/src/lib/layout/unauthenticated.svelte b/src/lib/layout/unauthenticated.svelte index 564fe2567..18a634b3f 100644 --- a/src/lib/layout/unauthenticated.svelte +++ b/src/lib/layout/unauthenticated.svelte @@ -3,6 +3,7 @@ import LoginLight from '$lib/images/login/login-light-mode.svg'; import LoginDark from '$lib/images/login/login-dark-mode.svg'; import { app } from '$lib/stores/app'; + import { base } from '$app/paths'; const technologies = [ 'js', @@ -31,8 +32,9 @@
      +
      {#if $app.themeInUse === 'dark'} @@ -43,16 +45,18 @@
      +

      Integrate with your favourite technologies

        + class="u-flex u-main-center u-flex-wrap u-gap-16 u-margin-block-start-32 u-line-height-1 u-opacity-0-5"> {#each technologies as tech}
      • -
      • @@ -62,7 +66,7 @@
    -
    +
    diff --git a/src/lib/stores/organization.ts b/src/lib/stores/organization.ts index b6ce64a42..fa0cee9a7 100644 --- a/src/lib/stores/organization.ts +++ b/src/lib/stores/organization.ts @@ -1,52 +1,50 @@ import { sdkForConsole } from '$lib/stores/sdk'; import type { Models } from '@aw-labs/appwrite-console'; import { writable } from 'svelte/store'; -import { browser } from '$app/env'; import { get } from 'svelte/store'; import { base } from '$app/paths'; import { goto } from '$app/navigation'; +import { cachedStore } from '$lib/helpers/cache'; -function createOrganizationList() { - const { subscribe, set } = writable( - browser ? JSON.parse(sessionStorage.getItem('organizationList')) : null - ); +export const newOrgModal = writable(false); +export const newMemberModal = writable(false); +export const organizationList = cachedStore< + Models.TeamList, + { + load: () => Promise; + } +>('organizationList', function ({ set }) { return { - subscribe, - set, load: async () => { const response = await sdkForConsole.teams.list(); set(response); } }; -} -function createOrganization() { - const { subscribe, set } = writable( - browser ? JSON.parse(sessionStorage.getItem('organization')) : null - ); +}); +export const organization = cachedStore< + Models.Team, + { + load: (teamId: string) => Promise; + } +>('organization', function ({ set }) { return { - subscribe, - set, - load: async (teamId: string) => { + load: async (teamId) => { const response = await sdkForConsole.teams.get(teamId); set(response); - }, - deleteCache: () => { - sessionStorage.removeItem('organization'); } }; -} - -function createProjectList() { - const { subscribe, set } = writable( - browser ? JSON.parse(sessionStorage.getItem('projectList')) : null - ); +}); +export const projectList = cachedStore< + Models.ProjectList, + { + load: (search: string, limit: number, offset: number) => Promise; + } +>('projectList', function ({ set }) { return { - subscribe, - set, - load: async (search: string, limit: number, offset: number) => { + load: async (search, limit, offset) => { const response = await sdkForConsole.projects.list( search, limit, @@ -58,17 +56,16 @@ function createProjectList() { set(response); } }; -} - -function createMemberList() { - const { subscribe, set } = writable( - browser ? JSON.parse(sessionStorage.getItem('memberList')) : null - ); +}); +export const memberList = cachedStore< + Models.MembershipList, + { + load: (teamId: string, search: string, limit: number, offset: number) => Promise; + } +>('memberList', function ({ set }) { return { - subscribe, - set, - load: async (teamId: string, search: string, limit: number, offset: number) => { + load: async (teamId, search, limit, offset) => { const response = await sdkForConsole.teams.getMemberships( teamId, search, @@ -78,23 +75,7 @@ function createMemberList() { set(response); } }; -} - -export const organizationList = createOrganizationList(); -export const organization = createOrganization(); -export const projectList = createProjectList(); -export const memberList = createMemberList(); -export const newOrgModal = writable(false); -export const newMemberModal = writable(false); - -if (browser) { - organizationList.subscribe((n) => - sessionStorage?.setItem('organizationList', JSON.stringify(n ?? '')) - ); - organization.subscribe((n) => sessionStorage?.setItem('organization', JSON.stringify(n ?? ''))); - projectList.subscribe((n) => sessionStorage?.setItem('projectList', JSON.stringify(n ?? ''))); - memberList.subscribe((n) => sessionStorage?.setItem('memberList', JSON.stringify(n ?? ''))); -} +}); export const redirectTo = async () => { let org = get(organization); diff --git a/src/lib/stores/project-services.ts b/src/lib/stores/project-services.ts new file mode 100644 index 000000000..6f4a8cb0d --- /dev/null +++ b/src/lib/stores/project-services.ts @@ -0,0 +1,117 @@ +import { writable } from 'svelte/store'; +import type { Models } from '@aw-labs/appwrite-console'; + +export type Service = { + label: string; + method: string; + value: boolean | null; +}; + +function createServices() { + const { subscribe, set } = writable({ + list: [ + { + label: 'Account', + method: 'account', + value: null + }, + { + label: 'Avatars', + method: 'avatars', + value: null + }, + { + label: 'Databases', + method: 'databases', + value: null + }, + { + label: 'Functions', + method: 'functions', + value: null + }, + { + label: 'Health', + method: 'health', + value: null + }, + { + label: 'Locale', + method: 'locale', + value: null + }, + { + label: 'Storage', + method: 'storage', + value: null + }, + { + label: 'Teams', + method: 'teams', + value: null + }, + { + label: 'Users', + method: 'users', + value: null + } + ] + }); + + return { + subscribe, + set, + load: (project: Models.Project) => { + const list = [ + { + label: 'Account', + method: 'account', + value: project.serviceStatusForAccount + }, + { + label: 'Avatars', + method: 'avatars', + value: project.serviceStatusForAvatars + }, + { + label: 'Databases', + method: 'databases', + value: project.serviceStatusForDatabases + }, + { + label: 'Functions', + method: 'functions', + value: project.serviceStatusForFunctions + }, + { + label: 'Health', + method: 'health', + value: project.serviceStatusForHealth + }, + { + label: 'Locale', + method: 'locale', + value: project.serviceStatusForLocale + }, + { + label: 'Storage', + method: 'storage', + value: project.serviceStatusForStorage + }, + { + label: 'Teams', + method: 'teams', + value: project.serviceStatusForTeams + }, + { + label: 'Users', + method: 'users', + value: project.serviceStatusForUsers + } + ]; + set({ list }); + } + }; +} + +export const services = createServices(); diff --git a/src/lib/stores/user.ts b/src/lib/stores/user.ts index fe9993066..12a84121b 100644 --- a/src/lib/stores/user.ts +++ b/src/lib/stores/user.ts @@ -10,6 +10,9 @@ function createUserStore() { set, fetchUser: async () => { set(await sdkForConsole.account.get()); + }, + logout: async () => { + await sdkForConsole.account.deleteSession('current'); } }; } diff --git a/src/routes/__layout.svelte b/src/routes/__layout.svelte index 71975c517..2b2f30128 100644 --- a/src/routes/__layout.svelte +++ b/src/routes/__layout.svelte @@ -23,6 +23,8 @@ window.GOOGLE_ANALYTICS = import.meta.env.VITE_GOOGLE_ANALYTICS?.toString() ?? false; } + const acceptedRoutes = ['/login', '/register', '/recover', '/invite']; + onMount(async () => { try { if (!$user) { @@ -33,7 +35,9 @@ await redirectTo(); } } catch (error) { - await goto(`${base}/login`); + if (acceptedRoutes.includes($page.url.pathname)) { + await goto(`${base}${$page.url.pathname}${$page.url.search}`); + } else await goto(`${base}/login`); } finally { loaded = true; } diff --git a/src/routes/console/$me.svelte b/src/routes/console/$me.svelte deleted file mode 100644 index 732f4edb7..000000000 --- a/src/routes/console/$me.svelte +++ /dev/null @@ -1,20 +0,0 @@ - - -

    hey

    - - diff --git a/src/routes/console/__layout.svelte b/src/routes/console/__layout.svelte index 19f720775..d31f50a6b 100644 --- a/src/routes/console/__layout.svelte +++ b/src/routes/console/__layout.svelte @@ -36,7 +36,10 @@ Appwrite - Console - +
    @@ -47,4 +50,6 @@