diff --git a/package.json b/package.json index 5dbe15c26a..461a4249c0 100644 --- a/package.json +++ b/package.json @@ -21,11 +21,11 @@ "e2e:ui": "playwright test --ui" }, "dependencies": { - "@appwrite.io/console": "https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@e2f082e", + "@appwrite.io/console": "https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@6dbeff0", "@appwrite.io/pink-icons": "0.25.0", - "@appwrite.io/pink-icons-svelte": "https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@6b17cb23", + "@appwrite.io/pink-icons-svelte": "https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@c339db5", "@appwrite.io/pink-legacy": "^1.0.3", - "@appwrite.io/pink-svelte": "https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@29b227f", + "@appwrite.io/pink-svelte": "https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@c339db5", "@popperjs/core": "^2.11.8", "@sentry/sveltekit": "^8.38.0", "@stripe/stripe-js": "^3.5.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e84836ebef..fb6093c59f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,20 +9,20 @@ importers: .: dependencies: '@appwrite.io/console': - specifier: https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@e2f082e - version: https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@e2f082e + specifier: https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@6dbeff0 + version: https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@6dbeff0 '@appwrite.io/pink-icons': specifier: 0.25.0 version: 0.25.0 '@appwrite.io/pink-icons-svelte': - specifier: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@6b17cb23 - version: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@6b17cb23(svelte@5.25.3) + specifier: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@c339db5 + version: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@c339db5(svelte@5.25.3) '@appwrite.io/pink-legacy': specifier: ^1.0.3 version: 1.0.3 '@appwrite.io/pink-svelte': - specifier: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@29b227f - version: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@29b227f(react-dom@18.3.1(react@18.3.1))(svelte@5.25.3) + specifier: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@c339db5 + version: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@c339db5(react-dom@18.3.1(react@18.3.1))(svelte@5.25.3) '@popperjs/core': specifier: ^2.11.8 version: 2.11.8 @@ -217,18 +217,18 @@ packages: '@analytics/type-utils@0.6.2': resolution: {integrity: sha512-TD+xbmsBLyYy/IxFimW/YL/9L2IEnM7/EoV9Aeh56U64Ify8o27HJcKjo38XY9Tcn0uOq1AX3thkKgvtWvwFQg==} - '@appwrite.io/console@https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@e2f082e': - resolution: {tarball: https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@e2f082e} + '@appwrite.io/console@https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@6dbeff0': + resolution: {tarball: https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@6dbeff0} version: 1.2.1 - '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@29b227fb7ad99f66e5031701c457d89ac190cd27': - resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@29b227fb7ad99f66e5031701c457d89ac190cd27} + '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@c339db5': + resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@c339db5} version: 1.0.0-next.7 peerDependencies: svelte: ^4.0.0 - '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@6b17cb23': - resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@6b17cb23} + '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@c339db5874e143bc11356abea82e2e964e391ce8': + resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@c339db5874e143bc11356abea82e2e964e391ce8} version: 1.0.0-next.7 peerDependencies: svelte: ^4.0.0 @@ -242,8 +242,8 @@ packages: '@appwrite.io/pink-legacy@1.0.3': resolution: {integrity: sha512-GGde5fmPhs+s6/3aFeMPc/kKADG/gTFkYQSy6oBN8pK0y0XNCLrZZgBv+EBbdhwdtqVEWXa0X85Mv9w7jcIlwQ==} - '@appwrite.io/pink-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@29b227f': - resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@29b227f} + '@appwrite.io/pink-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@c339db5': + resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@c339db5} version: 1.0.0-next.85 peerDependencies: react-dom: ^18.0.0 @@ -3534,13 +3534,13 @@ snapshots: '@analytics/type-utils@0.6.2': {} - '@appwrite.io/console@https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@e2f082e': {} + '@appwrite.io/console@https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@6dbeff0': {} - '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@29b227fb7ad99f66e5031701c457d89ac190cd27(svelte@5.25.3)': + '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@c339db5(svelte@5.25.3)': dependencies: svelte: 5.25.3 - '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@6b17cb23(svelte@5.25.3)': + '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@c339db5874e143bc11356abea82e2e964e391ce8(svelte@5.25.3)': dependencies: svelte: 5.25.3 @@ -3553,9 +3553,9 @@ snapshots: '@appwrite.io/pink-icons': 1.0.0 the-new-css-reset: 1.11.3 - '@appwrite.io/pink-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@29b227f(react-dom@18.3.1(react@18.3.1))(svelte@5.25.3)': + '@appwrite.io/pink-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@c339db5(react-dom@18.3.1(react@18.3.1))(svelte@5.25.3)': dependencies: - '@appwrite.io/pink-icons-svelte': https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@29b227fb7ad99f66e5031701c457d89ac190cd27(svelte@5.25.3) + '@appwrite.io/pink-icons-svelte': https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@c339db5874e143bc11356abea82e2e964e391ce8(svelte@5.25.3) '@floating-ui/dom': 1.6.13 '@melt-ui/pp': 0.3.2(@melt-ui/svelte@0.86.6(svelte@5.25.3))(svelte@5.25.3) '@melt-ui/svelte': 0.86.6(svelte@5.25.3) diff --git a/src/lib/actions/analytics.ts b/src/lib/actions/analytics.ts index 98460c5964..de4c5f9ecf 100644 --- a/src/lib/actions/analytics.ts +++ b/src/lib/actions/analytics.ts @@ -343,6 +343,9 @@ export enum Submit { FileCreate = 'submit_file_create', FileDelete = 'submit_file_delete', FileUpdatePermissions = 'submit_file_update_permissions', + FileTokenCreate = 'submit_file_token', + FileTokenDelete = 'submit_file_delete', + FileTokenUpdate = 'submit_file_update_expiry', BudgetCapUpdate = 'submit_budget_cap_update', BudgetAlertsUpdate = 'submit_budget_alert_conditions_update', CreditRedeem = 'submit_credit_redeem', diff --git a/src/routes/(console)/project-[project]/overview/keys/expirationInput.svelte b/src/lib/components/expirationInput.svelte similarity index 77% rename from src/routes/(console)/project-[project]/overview/keys/expirationInput.svelte rename to src/lib/components/expirationInput.svelte index cafc292c64..3e8286e04f 100644 --- a/src/routes/(console)/project-[project]/overview/keys/expirationInput.svelte +++ b/src/lib/components/expirationInput.svelte @@ -1,5 +1,5 @@ - - - {#if expirationSelect !== 'custom' && expirationSelect !== null} - Your key will expire in {toLocaleDate(value)} - {/if} - + {#if expirationSelect === 'custom'} - + {/if} diff --git a/src/lib/components/index.ts b/src/lib/components/index.ts index b20b38d1f7..4e509c671b 100644 --- a/src/lib/components/index.ts +++ b/src/lib/components/index.ts @@ -82,3 +82,4 @@ export { default as BottomSheet } from './bottom-sheet/index'; export { default as Confirm } from './confirm.svelte'; export { default as UsageCard } from './usageCard.svelte'; export { default as ViewToggle } from './viewToggle.svelte'; +export { default as ExpirationInput } from './expirationInput.svelte'; diff --git a/src/lib/components/permissions/actions.svelte b/src/lib/components/permissions/actions.svelte index 4319e3d74a..4bdbb76378 100644 --- a/src/lib/components/permissions/actions.svelte +++ b/src/lib/components/permissions/actions.svelte @@ -12,6 +12,7 @@ export let showTeam: boolean; export let showLabel: boolean; export let showCustom: boolean; + export let hideOnClick: boolean = false; export let groups: Writable>; const dispatch = createEventDispatcher(); @@ -19,31 +20,52 @@ - + dispatch('create', ['any'])}> + on:click={(e) => { + if (hideOnClick) hide(e); + dispatch('create', ['any']); + }}> Any dispatch('create', ['guests'])}> + on:click={(e) => { + if (hideOnClick) hide(e); + dispatch('create', ['guests']); + }}> All guests dispatch('create', ['users'])}> + on:click={(e) => { + if (hideOnClick) hide(e); + dispatch('create', ['users']); + }}> All users - (showUser = true)} - >Select users - (showTeam = true)} - >Select teams - (showLabel = true)} - >Label - (showCustom = true)} - >Custom permission + { + showUser = true; + if (hideOnClick) hide(e); + }}>Select users + { + showTeam = true; + if (hideOnClick) hide(e); + }}>Select teams + { + showLabel = true; + if (hideOnClick) hide(e); + }}>Label + { + showCustom = true; + if (hideOnClick) hide(e); + }}>Custom permission diff --git a/src/lib/components/permissions/permissions.svelte b/src/lib/components/permissions/permissions.svelte index a4f6875e7e..0cab252ed7 100644 --- a/src/lib/components/permissions/permissions.svelte +++ b/src/lib/components/permissions/permissions.svelte @@ -21,6 +21,7 @@ import type { PinkColumn } from '$lib/helpers/types'; export let withCreate = false; + export let hideOnClick = false; export let permissions: string[] = []; let showUser = false; @@ -127,11 +128,11 @@ } const columns: PinkColumn[] = [ - { id: 'role', width: { min: 100 } }, - { id: 'create', width: { min: 100 }, hide: !withCreate }, - { id: 'read', width: { min: 100 } }, - { id: 'update', width: { min: 100 } }, - { id: 'delete', width: { min: 100 } }, + { id: 'role', width: { min: 80 } }, + { id: 'create', width: { min: 80 }, hide: !withCreate }, + { id: 'read', width: { min: 80 } }, + { id: 'update', width: { min: 80 } }, + { id: 'delete', width: { min: 80 } }, { id: 'action', width: 40 } ]; @@ -195,6 +196,7 @@ bind:showTeam bind:showUser {groups} + {hideOnClick} on:create={create} let:toggle> + + + + + {#each $columns as { id, title } (id)} + {title} + {/each} + + + {#each $tokens.tokens as token} + + {toLocaleDate(token.$createdAt)} + + {token.expire + ? cleanFormattedDate(token.expire) + : 'never'} + + {token.accessedAt + ? cleanFormattedDate(token.accessedAt, true) + : 'never'} + + + {#if token.$permissions.length} + + {getPermissionGroups(token.$permissions)} + + {:else} + none + {/if} + + + + + + + + + + + + + + + + Copy URL + + + + + { + toggle(e); + copyPreviewWithToken( + token + ); + }}> + Preview + + { + toggle(e); + copyPreviewWithToken( + token, + 'view' + ); + }}> + View + + { + toggle(e); + copyPreviewWithToken( + token, + 'download' + ); + }}> + Download + + + + + { + showManageToken = true; + selectedFileToken = token; + }}> + Edit expiry + + { + showManageToken = true; + tokenPermissionsMode = true; + selectedFileToken = token; + }}> + Edit Permissions + + { + tokenDeleteMode = true; + showManageToken = true; + selectedFileToken = token; + }}> + Delete + + + + + + + + {/each} + + {:else} + (showManageToken = true)} + >Create new file token + {/if} + + + + Permissions Assign read or write permissions at the bucket level or file level. If bucket level permissions @@ -135,8 +418,8 @@ {:else} - If you want to assign document permissions. Go to Bucket settings and - enable file security. Otherwise, only Bucket permissions will be used. + If you want to assign file permissions. Go to Bucket settings and enable + file security. Otherwise, only Bucket permissions will be used. {/if} @@ -175,3 +458,18 @@ + + createFileToken(expiry)} + on:updated={({ detail: token }) => updateFileToken(token)} + on:deleted={async () => await deleteFileToken(selectedFileToken)} /> + + diff --git a/src/routes/(console)/project-[project]/storage/bucket-[bucket]/file-[file]/deleteFile.svelte b/src/routes/(console)/project-[project]/storage/bucket-[bucket]/file-[file]/deleteFile.svelte index e4ba0b0439..a21f607280 100644 --- a/src/routes/(console)/project-[project]/storage/bucket-[bucket]/file-[file]/deleteFile.svelte +++ b/src/routes/(console)/project-[project]/storage/bucket-[bucket]/file-[file]/deleteFile.svelte @@ -13,12 +13,13 @@ let error: string; const deleteFile = async () => { try { + const fileName = $file.name; await sdk.forProject.storage.deleteFile($file.bucketId, $file.$id); showDelete = false; await goto(`${base}/project-${page.params.project}/storage/bucket-${$file.bucketId}`); addNotification({ type: 'success', - message: `${$file.name} has been deleted` + message: `${fileName} has been deleted` }); trackEvent(Submit.FileDelete); } catch (error) { diff --git a/src/routes/(console)/project-[project]/storage/bucket-[bucket]/file-[file]/manageFileToken.svelte b/src/routes/(console)/project-[project]/storage/bucket-[bucket]/file-[file]/manageFileToken.svelte new file mode 100644 index 0000000000..45e8b269de --- /dev/null +++ b/src/routes/(console)/project-[project]/storage/bucket-[bucket]/file-[file]/manageFileToken.svelte @@ -0,0 +1,98 @@ + + + + +{#if isDelete} + + {@const formattedDate = cleanFormattedDate(fileToken.$createdAt)} +

+ Are you sure you want to delete the file token created on {formattedDate}? +

+ +

+ {#if fileToken.accessedAt} + {@const formattedDate = cleanFormattedDate(fileToken.accessedAt, true)} + + This token was last accessed on {formattedDate} + {:else} + This token has never been accessed. + {/if} +

+
+{:else} + + + + {#if fileToken} + {@const formattedDate = cleanFormattedDate(fileToken.$createdAt)} + Edit the expiry of the file token created on {formattedDate} + {:else} + Create a file token to grant access to a file. + Learn more. + {/if} + + + {#if isUpdatePermissions} + + {:else} + + {/if} + + + + + + +{/if} diff --git a/src/routes/(console)/project-[project]/storage/bucket-[bucket]/file-[file]/store.ts b/src/routes/(console)/project-[project]/storage/bucket-[bucket]/file-[file]/store.ts index 7d42b415ad..8ce91c5087 100644 --- a/src/routes/(console)/project-[project]/storage/bucket-[bucket]/file-[file]/store.ts +++ b/src/routes/(console)/project-[project]/storage/bucket-[bucket]/file-[file]/store.ts @@ -1,5 +1,16 @@ -import { derived } from 'svelte/store'; +import { derived, writable } from 'svelte/store'; import { page } from '$app/stores'; import type { Models } from '@appwrite.io/console'; +import type { Column } from '$lib/helpers/types'; export const file = derived(page, ($page) => $page.data.file as Models.File); + +export const tokens = derived(page, ($page) => $page.data.tokens as Models.ResourceTokenList); + +export const columns = writable([ + { id: 'created', title: 'Created', type: 'datetime', width: 200 }, + { id: 'expiry', title: 'Expiration', type: 'datetime', width: 200 }, + { id: 'last_accessed', title: 'Last accessed', type: 'datetime', width: 200 }, + { id: 'permissions', title: 'Permissions', type: 'string', width: 200 }, + { id: 'actions', title: '', type: 'string', width: 60 } +]); diff --git a/src/routes/(console)/project-[project]/storage/bucket-[bucket]/settings/+page.svelte b/src/routes/(console)/project-[project]/storage/bucket-[bucket]/settings/+page.svelte index 8d9e5409d7..44d3d37d4e 100644 --- a/src/routes/(console)/project-[project]/storage/bucket-[bucket]/settings/+page.svelte +++ b/src/routes/(console)/project-[project]/storage/bucket-[bucket]/settings/+page.svelte @@ -113,15 +113,12 @@ let isExtensionsDisabled = true; $: if (permissions) { - if (symmetricDifference(permissions, data.bucket.$permissions).length) { - $arePermsDisabled = false; - } else $arePermsDisabled = true; + $arePermsDisabled = !symmetricDifference(permissions, data.bucket.$permissions).length; } $: if (extensions) { - if (JSON.stringify(extensions) !== JSON.stringify(data.bucket.allowedFileExtensions)) { - isExtensionsDisabled = false; - } else isExtensionsDisabled = true; + isExtensionsDisabled = + JSON.stringify(extensions) === JSON.stringify(data.bucket.allowedFileExtensions); } function toggleBucket() {