1
0
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:
martin 2024-08-13 19:01:30 +02:00 committed by GitHub
parent c924f6c27c
commit fdf0b16fe3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 136 additions and 49 deletions

View File

@ -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();

View File

@ -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);

View File

@ -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 />

View File

@ -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}
/>

View File

@ -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'}

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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">

View File

@ -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>

View File

@ -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",

View File

@ -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>