mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
fix: column encryption support for other attributes
This commit is contained in:
+2
-2
@@ -15,7 +15,7 @@
|
||||
Tooltip,
|
||||
Typography
|
||||
} from '@appwrite.io/pink-svelte';
|
||||
import { isRelationship, isSpatialType, isString } from '../rows/store';
|
||||
import { isRelationship, isSpatialType, isTextType } from '../rows/store';
|
||||
import {
|
||||
columns,
|
||||
type Columns,
|
||||
@@ -443,7 +443,7 @@
|
||||
{/if}
|
||||
</Typography.Text>
|
||||
|
||||
{#if isString(column) && column.encrypt}
|
||||
{#if isTextType(column) && 'encrypt' in column && column.encrypt}
|
||||
<Tooltip portal>
|
||||
<Icon
|
||||
size="s"
|
||||
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/state';
|
||||
import { isCloud } from '$lib/system';
|
||||
import { getChangePlanUrl } from '$lib/stores/billing';
|
||||
import { currentPlan } from '$lib/stores/organization';
|
||||
import {
|
||||
ActionMenu,
|
||||
Popover,
|
||||
Layout,
|
||||
Selector,
|
||||
Tag,
|
||||
Tooltip,
|
||||
Typography,
|
||||
Link
|
||||
} from '@appwrite.io/pink-svelte';
|
||||
|
||||
let {
|
||||
encrypt = $bindable(false),
|
||||
editing = false,
|
||||
disabled = false,
|
||||
id = 'encrypt'
|
||||
}: {
|
||||
encrypt?: boolean;
|
||||
editing?: boolean;
|
||||
disabled?: boolean;
|
||||
id?: string;
|
||||
} = $props();
|
||||
|
||||
const organizationId = page.data?.organization?.$id ?? page.data?.project?.$id;
|
||||
const supportsEncryption = isCloud ? $currentPlan?.databasesAllowEncrypt : true;
|
||||
</script>
|
||||
|
||||
<Tooltip disabled={!(editing || disabled)} maxWidth="275px" placement="bottom-start">
|
||||
<div
|
||||
class="popover-holder"
|
||||
class:cursor-not-allowed={editing || disabled}
|
||||
class:disabled-checkbox={!supportsEncryption || editing || disabled}>
|
||||
<Layout.Stack inline gap="s" alignItems="flex-start" direction="row">
|
||||
<Popover let:toggle placement="bottom-start">
|
||||
<Selector.Checkbox
|
||||
size="s"
|
||||
{id}
|
||||
bind:checked={encrypt}
|
||||
disabled={!supportsEncryption || editing || disabled} />
|
||||
|
||||
<Layout.Stack gap="xxs" direction="column">
|
||||
<button
|
||||
type="button"
|
||||
disabled={editing || disabled}
|
||||
class:cursor-pointer={!editing}
|
||||
class:cursor-not-allowed={editing || disabled}
|
||||
on:click={(e) => {
|
||||
if (!supportsEncryption) {
|
||||
toggle(e);
|
||||
} else {
|
||||
encrypt = !encrypt;
|
||||
}
|
||||
}}>
|
||||
<Layout.Stack inline gap="xxs" direction="row" alignItems="center">
|
||||
<Typography.Text variant="m-500">Encrypted</Typography.Text>
|
||||
{#if !supportsEncryption}
|
||||
<Tag variant="default" size="xs" on:click={toggle}>Pro</Tag>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
</button>
|
||||
<Typography.Text color="--fgcolor-neutral-tertiary">
|
||||
Protect column against data leaks for best privacy compliance. Encrypted
|
||||
columns cannot be queried.
|
||||
</Typography.Text>
|
||||
</Layout.Stack>
|
||||
|
||||
<ActionMenu.Root width="180px" slot="tooltip">
|
||||
<Typography.Text variant="m-500">
|
||||
Available on Pro plan. <Link.Anchor href={getChangePlanUrl(organizationId)}
|
||||
>Upgrade</Link.Anchor>
|
||||
to enable encrypted columns.
|
||||
</Typography.Text>
|
||||
</ActionMenu.Root>
|
||||
</Popover>
|
||||
</Layout.Stack>
|
||||
</div>
|
||||
|
||||
<svelte:fragment slot="tooltip">
|
||||
Encryption can only be set when creating the column.
|
||||
</svelte:fragment>
|
||||
</Tooltip>
|
||||
|
||||
<style lang="scss">
|
||||
.popover-holder {
|
||||
& :global([role='tooltip']) {
|
||||
margin-top: 4px;
|
||||
left: 8rem !important;
|
||||
}
|
||||
|
||||
&.disabled-checkbox :global(button) {
|
||||
cursor: unset;
|
||||
}
|
||||
}
|
||||
|
||||
.cursor-pointer {
|
||||
cursor: pointer !important;
|
||||
}
|
||||
|
||||
.cursor-not-allowed {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
</style>
|
||||
+11
-2
@@ -17,7 +17,8 @@
|
||||
key,
|
||||
required: data.required,
|
||||
xdefault: data.default,
|
||||
array: data.array
|
||||
array: data.array,
|
||||
encrypt: data.encrypt
|
||||
});
|
||||
}
|
||||
export async function updateLongtext(
|
||||
@@ -42,17 +43,21 @@
|
||||
<script lang="ts">
|
||||
import { createConservative } from '$lib/helpers/stores';
|
||||
import RequiredArrayCheckboxes from './requiredArrayCheckboxes.svelte';
|
||||
import EncryptCheckbox from './encryptCheckbox.svelte';
|
||||
import { InputTextarea } from '$lib/elements/forms';
|
||||
import { Layout, Typography } from '@appwrite.io/pink-svelte';
|
||||
|
||||
export let data: Partial<Models.ColumnLongtext> = {
|
||||
required: false,
|
||||
array: false
|
||||
array: false,
|
||||
encrypt: false
|
||||
};
|
||||
|
||||
export let editing = false;
|
||||
export let disabled = false;
|
||||
|
||||
if (data && (data.encrypt === undefined || data.encrypt === null)) data.encrypt = false;
|
||||
|
||||
let savedDefault = data.default;
|
||||
|
||||
function handleDefaultState(hideDefault: boolean) {
|
||||
@@ -97,3 +102,7 @@
|
||||
{disabled}
|
||||
bind:array={data.array}
|
||||
bind:required={data.required} />
|
||||
|
||||
<Layout.Stack gap="xs" direction="column">
|
||||
<EncryptCheckbox id="encrypt-longtext" bind:encrypt={data.encrypt} {editing} {disabled} />
|
||||
</Layout.Stack>
|
||||
|
||||
+11
-2
@@ -17,7 +17,8 @@
|
||||
key,
|
||||
required: data.required,
|
||||
xdefault: data.default,
|
||||
array: data.array
|
||||
array: data.array,
|
||||
encrypt: data.encrypt
|
||||
});
|
||||
}
|
||||
export async function updateMediumtext(
|
||||
@@ -42,17 +43,21 @@
|
||||
<script lang="ts">
|
||||
import { createConservative } from '$lib/helpers/stores';
|
||||
import RequiredArrayCheckboxes from './requiredArrayCheckboxes.svelte';
|
||||
import EncryptCheckbox from './encryptCheckbox.svelte';
|
||||
import { InputTextarea } from '$lib/elements/forms';
|
||||
import { Layout, Typography } from '@appwrite.io/pink-svelte';
|
||||
|
||||
export let data: Partial<Models.ColumnMediumtext> = {
|
||||
required: false,
|
||||
array: false
|
||||
array: false,
|
||||
encrypt: false
|
||||
};
|
||||
|
||||
export let editing = false;
|
||||
export let disabled = false;
|
||||
|
||||
if (data && (data.encrypt === undefined || data.encrypt === null)) data.encrypt = false;
|
||||
|
||||
let savedDefault = data.default;
|
||||
|
||||
function handleDefaultState(hideDefault: boolean) {
|
||||
@@ -97,3 +102,7 @@
|
||||
{disabled}
|
||||
bind:array={data.array}
|
||||
bind:required={data.required} />
|
||||
|
||||
<Layout.Stack gap="xs" direction="column">
|
||||
<EncryptCheckbox id="encrypt-mediumtext" bind:encrypt={data.encrypt} {editing} {disabled} />
|
||||
</Layout.Stack>
|
||||
|
||||
+11
-2
@@ -15,7 +15,8 @@
|
||||
key,
|
||||
required: data.required,
|
||||
xdefault: data.default,
|
||||
array: data.array
|
||||
array: data.array,
|
||||
encrypt: data.encrypt
|
||||
});
|
||||
}
|
||||
export async function updateText(
|
||||
@@ -38,17 +39,21 @@
|
||||
<script lang="ts">
|
||||
import { createConservative } from '$lib/helpers/stores';
|
||||
import RequiredArrayCheckboxes from './requiredArrayCheckboxes.svelte';
|
||||
import EncryptCheckbox from './encryptCheckbox.svelte';
|
||||
import { InputTextarea } from '$lib/elements/forms';
|
||||
import { Layout, Typography } from '@appwrite.io/pink-svelte';
|
||||
|
||||
export let data: Partial<Models.ColumnText> = {
|
||||
required: false,
|
||||
array: false
|
||||
array: false,
|
||||
encrypt: false
|
||||
};
|
||||
|
||||
export let editing = false;
|
||||
export let disabled = false;
|
||||
|
||||
if (data && (data.encrypt === undefined || data.encrypt === null)) data.encrypt = false;
|
||||
|
||||
let savedDefault = data.default;
|
||||
|
||||
function handleDefaultState(hideDefault: boolean) {
|
||||
@@ -93,3 +98,7 @@
|
||||
{disabled}
|
||||
bind:array={data.array}
|
||||
bind:required={data.required} />
|
||||
|
||||
<Layout.Stack gap="xs" direction="column">
|
||||
<EncryptCheckbox id="encrypt-text" bind:encrypt={data.encrypt} {editing} {disabled} />
|
||||
</Layout.Stack>
|
||||
|
||||
+20
-4
@@ -16,7 +16,8 @@
|
||||
size: data.size,
|
||||
required: data.required,
|
||||
xdefault: data.default,
|
||||
array: data.array
|
||||
array: data.array,
|
||||
encrypt: data.encrypt
|
||||
});
|
||||
}
|
||||
export async function updateVarchar(
|
||||
@@ -45,16 +46,20 @@
|
||||
import { ProgressBar } from '$lib/components';
|
||||
import { Layout, Typography, Tooltip, Icon } from '@appwrite.io/pink-svelte';
|
||||
import { IconInfo } from '@appwrite.io/pink-icons-svelte';
|
||||
import EncryptCheckbox from './encryptCheckbox.svelte';
|
||||
|
||||
export let data: Partial<Models.ColumnVarchar> = {
|
||||
required: false,
|
||||
size: 255,
|
||||
array: false
|
||||
array: false,
|
||||
encrypt: false
|
||||
};
|
||||
|
||||
export let editing = false;
|
||||
export let disabled = false;
|
||||
|
||||
if (data && (data.encrypt === undefined || data.encrypt === null)) data.encrypt = false;
|
||||
|
||||
// Local size for reactivity
|
||||
let size = data.size ?? 255;
|
||||
$: data.size = size;
|
||||
@@ -118,6 +123,10 @@
|
||||
$: listen(data);
|
||||
|
||||
$: handleDefaultState($required || $array);
|
||||
|
||||
$: if (data.encrypt && size < 150) {
|
||||
size = 150;
|
||||
}
|
||||
</script>
|
||||
|
||||
<InputNumber
|
||||
@@ -127,8 +136,11 @@
|
||||
{disabled}
|
||||
placeholder="Enter size"
|
||||
bind:value={size}
|
||||
min={1}
|
||||
max={16383} />
|
||||
min={data.encrypt ? 150 : 1}
|
||||
max={16383}
|
||||
helper={data.encrypt
|
||||
? 'Encrypted varchar columns require a minimum size of 150.'
|
||||
: undefined} />
|
||||
|
||||
{#if !editing}
|
||||
<Layout.Stack gap="xs">
|
||||
@@ -173,3 +185,7 @@
|
||||
{disabled}
|
||||
bind:array={data.array}
|
||||
bind:required={data.required} />
|
||||
|
||||
<Layout.Stack gap="xs" direction="column">
|
||||
<EncryptCheckbox id="encrypt-varchar" bind:encrypt={data.encrypt} {editing} {disabled} />
|
||||
</Layout.Stack>
|
||||
|
||||
+3
-1
@@ -47,6 +47,7 @@
|
||||
required: column?.required ?? false,
|
||||
array: column?.array ?? false,
|
||||
default: column?.default ?? null,
|
||||
encrypt: (column as { encrypt?: boolean })?.encrypt ?? false,
|
||||
...column
|
||||
} as Partial<Columns>);
|
||||
|
||||
@@ -60,7 +61,8 @@
|
||||
data = {
|
||||
required: false,
|
||||
array: false,
|
||||
default: null
|
||||
default: null,
|
||||
encrypt: false
|
||||
};
|
||||
|
||||
/* default to text */
|
||||
|
||||
+2
-3
@@ -16,8 +16,7 @@
|
||||
buildWildcardColumnsQuery,
|
||||
isRelationship,
|
||||
isRelationshipToMany,
|
||||
isSpatialType,
|
||||
isString
|
||||
isSpatialType, isTextType
|
||||
} from './rows/store';
|
||||
import {
|
||||
columns,
|
||||
@@ -1072,7 +1071,7 @@
|
||||
{@const isEmptyArray = formatted === 'Empty'}
|
||||
{@const isDatetimeAttribute = rowColumn.type === 'datetime'}
|
||||
{@const isEncryptedAttribute =
|
||||
isString(rowColumn) && rowColumn.encrypt}
|
||||
isTextType(rowColumn) && 'encrypt' in rowColumn && rowColumn.encrypt}
|
||||
{#if isDatetimeAttribute}
|
||||
<DualTimeView time={value}>
|
||||
<span slot="title">Timestamp</span>
|
||||
|
||||
Reference in New Issue
Block a user