mirror of
https://github.com/immich-app/immich.git
synced 2024-12-27 10:58:13 +02:00
feat(web): add privacy step in the onboarding (#11359)
* feat: add privacy step in the onboarding * fix: remove console.log * feat:Details the implications of enabling the map on the settings page Added a link to the guide on customizing map styles as well * feat: add map implication * refactor: onboarding style * fix: tile provider * fix: remove long explanations * chore: cleanup --------- Co-authored-by: pcouy <contact@pierre-couy.dev> Co-authored-by: Jason Rasmussen <jason@rasm.me>
This commit is contained in:
parent
c924f6c27c
commit
fdf0b16fe3
@ -33,6 +33,7 @@ test.describe('Registration', () => {
|
||||
// onboarding
|
||||
await expect(page).toHaveURL('/auth/onboarding');
|
||||
await page.getByRole('button', { name: 'Theme' }).click();
|
||||
await page.getByRole('button', { name: 'Privacy' }).click();
|
||||
await page.getByRole('button', { name: 'Storage Template' }).click();
|
||||
await page.getByRole('button', { name: 'Done' }).click();
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { getConfig, getConfigDefaults, updateConfig, type SystemConfigDto } from '@immich/sdk';
|
||||
import { loadConfig } from '$lib/stores/server-config.store';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { cloneDeep, isEqual } from 'lodash-es';
|
||||
import { onMount } from 'svelte';
|
||||
import type { SettingsResetOptions } from './admin-settings';
|
||||
import { t } from 'svelte-i18n';
|
||||
@ -23,12 +23,16 @@
|
||||
};
|
||||
|
||||
export const handleSave = async (update: Partial<SystemConfigDto>) => {
|
||||
let systemConfigDto = {
|
||||
...savedConfig,
|
||||
...update,
|
||||
};
|
||||
if (isEqual(systemConfigDto, savedConfig)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const newConfig = await updateConfig({
|
||||
systemConfigDto: {
|
||||
...savedConfig,
|
||||
...update,
|
||||
},
|
||||
systemConfigDto,
|
||||
});
|
||||
|
||||
config = cloneDeep(newConfig);
|
||||
|
@ -26,7 +26,12 @@
|
||||
<div class="flex flex-col gap-4">
|
||||
<SettingAccordion key="map" title={$t('admin.map_settings')} subtitle={$t('admin.map_settings_description')}>
|
||||
<div class="ml-4 mt-4 flex flex-col gap-4">
|
||||
<SettingSwitch title={$t('admin.map_enable_description')} {disabled} bind:checked={config.map.enabled} />
|
||||
<SettingSwitch
|
||||
title={$t('admin.map_enable_description')}
|
||||
subtitle={$t('admin.map_implications')}
|
||||
{disabled}
|
||||
bind:checked={config.map.enabled}
|
||||
/>
|
||||
|
||||
<hr />
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
<div class="ml-4 mt-4">
|
||||
<SettingSwitch
|
||||
title={$t('admin.version_check_enabled_description')}
|
||||
subtitle={$t('admin.version_check_implications')}
|
||||
bind:checked={config.newVersionCheck.enabled}
|
||||
{disabled}
|
||||
/>
|
||||
|
@ -29,6 +29,7 @@
|
||||
export let minified = false;
|
||||
export let onReset: SettingsResetEvent;
|
||||
export let onSave: SettingsSaveEvent;
|
||||
export let duration: number = 500;
|
||||
|
||||
let templateOptions: SystemConfigTemplateStorageOptionDto;
|
||||
let selectedPreset = '';
|
||||
@ -87,7 +88,7 @@
|
||||
</script>
|
||||
|
||||
<section class="dark:text-immich-dark-fg mt-2">
|
||||
<div in:fade={{ duration: 500 }} class="mx-4 flex flex-col gap-4 py-4">
|
||||
<div in:fade={{ duration }} class="mx-4 flex flex-col gap-4 py-4">
|
||||
<p class="text-sm dark:text-immich-dark-fg">
|
||||
<FormatMessage key="admin.storage_template_more_details" let:tag let:message>
|
||||
{#if tag === 'template-link'}
|
||||
|
@ -1,11 +1,27 @@
|
||||
<script lang="ts">
|
||||
import Icon from '$lib/components/elements/icon.svelte';
|
||||
import { fade } from 'svelte/transition';
|
||||
|
||||
export let title: string | undefined = undefined;
|
||||
export let icon: string | undefined = undefined;
|
||||
</script>
|
||||
|
||||
<div
|
||||
id="onboarding-card"
|
||||
class="flex w-full max-w-4xl flex-col gap-4 rounded-3xl border-2 border-gray-500 px-8 py-14 dark:border-immich-dark-gray dark:bg-immich-dark-gray text-black dark:text-immich-dark-fg bg-gray-50"
|
||||
class="flex w-full max-w-4xl flex-col gap-4 rounded-3xl border-2 border-gray-500 px-8 py-8 dark:border-immich-dark-gray dark:bg-immich-dark-gray text-black dark:text-immich-dark-fg bg-gray-50"
|
||||
in:fade={{ duration: 250 }}
|
||||
>
|
||||
{#if title || icon}
|
||||
<div class="flex gap-2 items-center justify-center w-fit">
|
||||
{#if icon}
|
||||
<Icon path={icon} size="30" class="text-immich-primary dark:text-immich-dark-primary" />
|
||||
{/if}
|
||||
{#if title}
|
||||
<p class="text-xl text-immich-primary dark:text-immich-dark-primary">
|
||||
{title.toUpperCase()}
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
<slot />
|
||||
</div>
|
||||
|
@ -3,14 +3,11 @@
|
||||
import Button from '$lib/components/elements/buttons/button.svelte';
|
||||
import { mdiArrowRight } from '@mdi/js';
|
||||
import Icon from '$lib/components/elements/icon.svelte';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import ImmichLogo from '../shared-components/immich-logo.svelte';
|
||||
import ImmichLogo from '$lib/components/shared-components/immich-logo.svelte';
|
||||
import { user } from '$lib/stores/user.store';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
const dispatch = createEventDispatcher<{
|
||||
done: void;
|
||||
}>();
|
||||
export let onDone: () => void;
|
||||
</script>
|
||||
|
||||
<OnboardingCard>
|
||||
@ -21,7 +18,7 @@
|
||||
<p class="text-3xl pb-6 font-light">{$t('onboarding_welcome_description')}</p>
|
||||
|
||||
<div class="w-full flex place-content-end">
|
||||
<Button class="flex gap-2 place-content-center" on:click={() => dispatch('done')}>
|
||||
<Button class="flex gap-2 place-content-center" on:click={() => onDone()}>
|
||||
<p>{$t('theme')}</p>
|
||||
<Icon path={mdiArrowRight} size="18" />
|
||||
</Button>
|
||||
|
@ -0,0 +1,63 @@
|
||||
<script lang="ts">
|
||||
import { user } from '$lib/stores/user.store';
|
||||
import { getConfig, type SystemConfigDto } from '@immich/sdk';
|
||||
import { mdiArrowLeft, mdiArrowRight, mdiIncognito } from '@mdi/js';
|
||||
import { onMount } from 'svelte';
|
||||
import AdminSettings from '$lib/components/admin-page/settings/admin-settings.svelte';
|
||||
import Button from '$lib/components/elements/buttons/button.svelte';
|
||||
import Icon from '$lib/components/elements/icon.svelte';
|
||||
import OnboardingCard from './onboarding-card.svelte';
|
||||
import { t } from 'svelte-i18n';
|
||||
import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte';
|
||||
|
||||
export let onDone: () => void;
|
||||
export let onPrevious: () => void;
|
||||
|
||||
let config: SystemConfigDto | null = null;
|
||||
|
||||
onMount(async () => {
|
||||
config = await getConfig();
|
||||
});
|
||||
</script>
|
||||
|
||||
<OnboardingCard title={$t('privacy')} icon={mdiIncognito}>
|
||||
<p>
|
||||
{$t('onboarding_privacy_description')}
|
||||
</p>
|
||||
|
||||
{#if config && $user}
|
||||
<AdminSettings bind:config let:handleSave>
|
||||
<SettingSwitch
|
||||
title={$t('admin.map_settings')}
|
||||
subtitle={$t('admin.map_implications')}
|
||||
bind:checked={config.map.enabled}
|
||||
/>
|
||||
<SettingSwitch
|
||||
title={$t('admin.version_check_settings')}
|
||||
subtitle={$t('admin.version_check_implications')}
|
||||
bind:checked={config.newVersionCheck.enabled}
|
||||
/>
|
||||
<div class="flex pt-4">
|
||||
<div class="w-full flex place-content-start">
|
||||
<Button class="flex gap-2 place-content-center" on:click={() => onPrevious()}>
|
||||
<Icon path={mdiArrowLeft} size="18" />
|
||||
<p>{$t('theme')}</p>
|
||||
</Button>
|
||||
</div>
|
||||
<div class="flex w-full place-content-end">
|
||||
<Button
|
||||
on:click={() => {
|
||||
handleSave({ map: config?.map, newVersionCheck: config?.newVersionCheck });
|
||||
onDone();
|
||||
}}
|
||||
>
|
||||
<span class="flex place-content-center place-items-center gap-2">
|
||||
{$t('admin.storage_template_settings')}
|
||||
<Icon path={mdiArrowRight} size="18" />
|
||||
</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</AdminSettings>
|
||||
{/if}
|
||||
</OnboardingCard>
|
@ -2,20 +2,18 @@
|
||||
import { featureFlags } from '$lib/stores/server-config.store';
|
||||
import { user } from '$lib/stores/user.store';
|
||||
import { getConfig, type SystemConfigDto } from '@immich/sdk';
|
||||
import { mdiArrowLeft, mdiCheck } from '@mdi/js';
|
||||
import { createEventDispatcher, onMount } from 'svelte';
|
||||
import AdminSettings from '../admin-page/settings/admin-settings.svelte';
|
||||
import StorageTemplateSettings from '../admin-page/settings/storage-template/storage-template-settings.svelte';
|
||||
import Button from '../elements/buttons/button.svelte';
|
||||
import Icon from '../elements/icon.svelte';
|
||||
import { mdiArrowLeft, mdiCheck, mdiHarddisk } from '@mdi/js';
|
||||
import { onMount } from 'svelte';
|
||||
import AdminSettings from '$lib/components/admin-page/settings/admin-settings.svelte';
|
||||
import StorageTemplateSettings from '$lib/components/admin-page/settings/storage-template/storage-template-settings.svelte';
|
||||
import Button from '$lib/components/elements/buttons/button.svelte';
|
||||
import Icon from '$lib/components/elements/icon.svelte';
|
||||
import OnboardingCard from './onboarding-card.svelte';
|
||||
import { t } from 'svelte-i18n';
|
||||
import FormatMessage from '$lib/components/i18n/format-message.svelte';
|
||||
|
||||
const dispatch = createEventDispatcher<{
|
||||
done: void;
|
||||
previous: void;
|
||||
}>();
|
||||
export let onDone: () => void;
|
||||
export let onPrevious: () => void;
|
||||
|
||||
let config: SystemConfigDto | null = null;
|
||||
|
||||
@ -24,11 +22,7 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<OnboardingCard>
|
||||
<p class="text-xl text-immich-primary dark:text-immich-dark-primary">
|
||||
{$t('admin.storage_template_settings').toUpperCase()}
|
||||
</p>
|
||||
|
||||
<OnboardingCard title={$t('admin.storage_template_settings')} icon={mdiHarddisk}>
|
||||
<p>
|
||||
<FormatMessage key="admin.storage_template_onboarding_description" let:message>
|
||||
<a class="underline" href="https://immich.app/docs/administration/storage-template">{message}</a>
|
||||
@ -45,10 +39,11 @@
|
||||
{savedConfig}
|
||||
onSave={(config) => handleSave(config)}
|
||||
onReset={(options) => handleReset(options)}
|
||||
duration={0}
|
||||
>
|
||||
<div class="flex pt-4">
|
||||
<div class="w-full flex place-content-start">
|
||||
<Button class="flex gap-2 place-content-center" on:click={() => dispatch('previous')}>
|
||||
<Button class="flex gap-2 place-content-center" on:click={() => onPrevious()}>
|
||||
<Icon path={mdiArrowLeft} size="18" />
|
||||
<p>{$t('theme')}</p>
|
||||
</Button>
|
||||
@ -57,7 +52,7 @@
|
||||
<Button
|
||||
on:click={() => {
|
||||
handleSave({ storageTemplate: config?.storageTemplate });
|
||||
dispatch('done');
|
||||
onDone();
|
||||
}}
|
||||
>
|
||||
<span class="flex place-content-center place-items-center gap-2">
|
||||
|
@ -1,23 +1,17 @@
|
||||
<script lang="ts">
|
||||
import { mdiArrowRight } from '@mdi/js';
|
||||
import Button from '../elements/buttons/button.svelte';
|
||||
import Icon from '../elements/icon.svelte';
|
||||
import { mdiArrowRight, mdiThemeLightDark } from '@mdi/js';
|
||||
import Button from '$lib/components/elements/buttons/button.svelte';
|
||||
import Icon from '$lib/components/elements/icon.svelte';
|
||||
import OnboardingCard from './onboarding-card.svelte';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import { colorTheme } from '$lib/stores/preferences.store';
|
||||
import { moonPath, moonViewBox, sunPath, sunViewBox } from '$lib/assets/svg-paths';
|
||||
import { Theme } from '$lib/constants';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
const dispatch = createEventDispatcher<{
|
||||
done: void;
|
||||
previous: void;
|
||||
}>();
|
||||
export let onDone: () => void;
|
||||
</script>
|
||||
|
||||
<OnboardingCard>
|
||||
<p class="text-xl text-immich-primary dark:text-immich-dark-primary">{$t('color_theme').toUpperCase()}</p>
|
||||
|
||||
<OnboardingCard icon={mdiThemeLightDark} title={$t('color_theme')}>
|
||||
<div>
|
||||
<p class="pb-6 font-light">{$t('onboarding_theme_description')}</p>
|
||||
</div>
|
||||
@ -51,8 +45,8 @@
|
||||
|
||||
<div class="flex">
|
||||
<div class="w-full flex place-content-end">
|
||||
<Button class="flex gap-2 place-content-center" on:click={() => dispatch('done')}>
|
||||
<p>{$t('admin.storage_template_settings')}</p>
|
||||
<Button class="flex gap-2 place-content-center" on:click={() => onDone()}>
|
||||
<p>{$t('privacy')}</p>
|
||||
<Icon path={mdiArrowRight} size="18" />
|
||||
</Button>
|
||||
</div>
|
||||
|
@ -127,12 +127,13 @@
|
||||
"map_enable_description": "Enable map features",
|
||||
"map_gps_settings": "Map & GPS Settings",
|
||||
"map_gps_settings_description": "Manage Map & GPS (Reverse Geocoding) Settings",
|
||||
"map_implications": "The map feature relies on an external tile service (tiles.immich.cloud)",
|
||||
"map_light_style": "Light style",
|
||||
"map_manage_reverse_geocoding_settings": "Manage <link>Reverse Geocoding</link> settings",
|
||||
"map_reverse_geocoding": "Reverse Geocoding",
|
||||
"map_reverse_geocoding_enable_description": "Enable reverse geocoding",
|
||||
"map_reverse_geocoding_settings": "Reverse Geocoding Settings",
|
||||
"map_settings": "Map Settings",
|
||||
"map_settings": "Map",
|
||||
"map_settings_description": "Manage map settings",
|
||||
"map_style_description": "URL to a style.json map theme",
|
||||
"metadata_extraction_job": "Extract metadata",
|
||||
@ -317,7 +318,8 @@
|
||||
"user_settings": "User Settings",
|
||||
"user_settings_description": "Manage user settings",
|
||||
"user_successfully_removed": "User {email} has been successfully removed.",
|
||||
"version_check_enabled_description": "Enable periodic requests to GitHub to check for new releases",
|
||||
"version_check_enabled_description": "Enable version check",
|
||||
"version_check_implications": "The version check feature relies on periodic communication with github.com",
|
||||
"version_check_settings": "Version Check",
|
||||
"version_check_settings_description": "Enable/disable the new version notification",
|
||||
"video_conversion_job": "Transcode videos",
|
||||
@ -850,6 +852,7 @@
|
||||
"ok": "Ok",
|
||||
"oldest_first": "Oldest first",
|
||||
"onboarding": "Onboarding",
|
||||
"onboarding_privacy_description": "The following (optional) features rely on external services, and can by disabled at any time in the administration settings.",
|
||||
"onboarding_theme_description": "Choose a color theme for your instance. You can change this later in your settings.",
|
||||
"onboarding_welcome_description": "Let's get your instance set up with some common settings.",
|
||||
"onboarding_welcome_user": "Welcome, {user}",
|
||||
@ -920,6 +923,7 @@
|
||||
"previous_memory": "Previous memory",
|
||||
"previous_or_next_photo": "Previous or next photo",
|
||||
"primary": "Primary",
|
||||
"privacy": "Privacy",
|
||||
"profile_image_of_user": "Profile image of {user}",
|
||||
"profile_picture_set": "Profile picture set.",
|
||||
"public_album": "Public album",
|
||||
|
@ -2,6 +2,7 @@
|
||||
import { goto } from '$app/navigation';
|
||||
import { page } from '$app/stores';
|
||||
import OnboardingHello from '$lib/components/onboarding-page/onboarding-hello.svelte';
|
||||
import OnboardingPrivacy from '$lib/components/onboarding-page/onboarding-privacy.svelte';
|
||||
import OnboadingStorageTemplate from '$lib/components/onboarding-page/onboarding-storage-template.svelte';
|
||||
import OnboardingTheme from '$lib/components/onboarding-page/onboarding-theme.svelte';
|
||||
import { AppRoute, QueryParameter } from '$lib/constants';
|
||||
@ -11,12 +12,17 @@
|
||||
|
||||
interface OnboardingStep {
|
||||
name: string;
|
||||
component: typeof OnboardingHello | typeof OnboardingTheme | typeof OnboadingStorageTemplate;
|
||||
component:
|
||||
| typeof OnboardingHello
|
||||
| typeof OnboardingTheme
|
||||
| typeof OnboadingStorageTemplate
|
||||
| typeof OnboardingPrivacy;
|
||||
}
|
||||
|
||||
const onboardingSteps: OnboardingStep[] = [
|
||||
{ name: 'hello', component: OnboardingHello },
|
||||
{ name: 'theme', component: OnboardingTheme },
|
||||
{ name: 'privacy', component: OnboardingPrivacy },
|
||||
{ name: 'storage', component: OnboadingStorageTemplate },
|
||||
];
|
||||
|
||||
@ -55,8 +61,8 @@
|
||||
<div class="w-full min-w-screen py-8 flex h-full place-content-center place-items-center">
|
||||
<svelte:component
|
||||
this={onboardingSteps[index].component}
|
||||
on:done={handleDoneClicked}
|
||||
on:previous={handlePrevious}
|
||||
onDone={handleDoneClicked}
|
||||
onPrevious={handlePrevious}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user