mirror of
https://github.com/immich-app/immich.git
synced 2024-12-25 10:43:13 +02:00
fix(web): user management responsive design (#5698)
* fix: user management tailwind * use top instead of inset-y-0 * add types to createEventDispatcher
This commit is contained in:
parent
8e39d389b5
commit
f2270ad757
@ -22,6 +22,7 @@
|
||||
import SettingAccordion from '../setting-accordion.svelte';
|
||||
import { mdiHelpCircleOutline } from '@mdi/js';
|
||||
import Icon from '$lib/components/elements/icon.svelte';
|
||||
import type { ResetOptions } from '$lib/utils/dipatch';
|
||||
|
||||
export let ffmpegConfig: SystemConfigFFmpegDto; // this is the config that is being edited
|
||||
export let disabled = false;
|
||||
@ -63,6 +64,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
const handleReset = (detail: ResetOptions) => {
|
||||
if (detail.default) {
|
||||
resetToDefault();
|
||||
} else {
|
||||
reset();
|
||||
}
|
||||
};
|
||||
|
||||
async function reset() {
|
||||
const { data: resetConfig } = await api.systemConfigApi.getConfig();
|
||||
|
||||
@ -354,9 +363,8 @@
|
||||
|
||||
<div class="ml-4">
|
||||
<SettingButtonsRow
|
||||
on:reset={reset}
|
||||
on:reset={({ detail }) => handleReset(detail)}
|
||||
on:save={saveSetting}
|
||||
on:reset-to-default={resetToDefault}
|
||||
showResetToDefault={!isEqual(savedConfig, defaultConfig)}
|
||||
{disabled}
|
||||
/>
|
||||
|
@ -9,6 +9,7 @@
|
||||
import { handleError } from '../../../../utils/handle-error';
|
||||
import SettingButtonsRow from '../setting-buttons-row.svelte';
|
||||
import SettingInputField, { SettingInputFieldType } from '../setting-input-field.svelte';
|
||||
import type { ResetOptions } from '$lib/utils/dipatch';
|
||||
|
||||
export let jobConfig: SystemConfigJobDto; // this is the config that is being edited
|
||||
export let disabled = false;
|
||||
@ -29,6 +30,14 @@
|
||||
JobName.Migration,
|
||||
];
|
||||
|
||||
const handleReset = (detail: ResetOptions) => {
|
||||
if (detail.default) {
|
||||
resetToDefault();
|
||||
} else {
|
||||
reset();
|
||||
}
|
||||
};
|
||||
|
||||
async function getConfigs() {
|
||||
[savedConfig, defaultConfig] = await Promise.all([
|
||||
api.systemConfigApi.getConfig().then((res) => res.data.job),
|
||||
@ -101,9 +110,8 @@
|
||||
|
||||
<div class="ml-4">
|
||||
<SettingButtonsRow
|
||||
on:reset={reset}
|
||||
on:reset={({ detail }) => handleReset(detail)}
|
||||
on:save={saveSetting}
|
||||
on:reset-to-default={resetToDefault}
|
||||
showResetToDefault={!isEqual(savedConfig, defaultConfig)}
|
||||
{disabled}
|
||||
/>
|
||||
|
@ -11,6 +11,7 @@
|
||||
import { fade } from 'svelte/transition';
|
||||
import { handleError } from '../../../../utils/handle-error';
|
||||
import SettingAccordion from '../setting-accordion.svelte';
|
||||
import type { ResetOptions } from '$lib/utils/dipatch';
|
||||
|
||||
export let libraryConfig: SystemConfigLibraryDto; // this is the config that is being edited
|
||||
export let disabled = false;
|
||||
@ -25,6 +26,14 @@
|
||||
let savedConfig: SystemConfigLibraryDto;
|
||||
let defaultConfig: SystemConfigLibraryDto;
|
||||
|
||||
const handleReset = (detail: ResetOptions) => {
|
||||
if (detail.default) {
|
||||
resetToDefault();
|
||||
} else {
|
||||
reset();
|
||||
}
|
||||
};
|
||||
|
||||
async function getConfigs() {
|
||||
[savedConfig, defaultConfig] = await Promise.all([
|
||||
api.systemConfigApi.getConfig().then((res) => res.data.library),
|
||||
@ -131,9 +140,8 @@
|
||||
|
||||
<div class="ml-4">
|
||||
<SettingButtonsRow
|
||||
on:reset={reset}
|
||||
on:reset={({ detail }) => handleReset(detail)}
|
||||
on:save={saveSetting}
|
||||
on:reset-to-default={resetToDefault}
|
||||
showResetToDefault={!isEqual(savedConfig, defaultConfig)}
|
||||
{disabled}
|
||||
/>
|
||||
|
@ -12,6 +12,7 @@
|
||||
import SettingSwitch from '../setting-switch.svelte';
|
||||
import SettingAccordion from '../setting-accordion.svelte';
|
||||
import SettingSelect from '../setting-select.svelte';
|
||||
import type { ResetOptions } from '$lib/utils/dipatch';
|
||||
|
||||
export let machineLearningConfig: SystemConfigMachineLearningDto; // this is the config that is being edited
|
||||
export let disabled = false;
|
||||
@ -33,6 +34,14 @@
|
||||
notificationController.show({ message: 'Reset to the last saved settings', type: NotificationType.Info });
|
||||
}
|
||||
|
||||
const handleReset = (detail: ResetOptions) => {
|
||||
if (detail.default) {
|
||||
resetToDefault();
|
||||
} else {
|
||||
reset();
|
||||
}
|
||||
};
|
||||
|
||||
async function saveSetting() {
|
||||
try {
|
||||
const { data: current } = await api.systemConfigApi.getConfig();
|
||||
@ -212,9 +221,8 @@
|
||||
</SettingAccordion>
|
||||
|
||||
<SettingButtonsRow
|
||||
on:reset={reset}
|
||||
on:reset={({ detail }) => handleReset(detail)}
|
||||
on:save={saveSetting}
|
||||
on:reset-to-default={resetToDefault}
|
||||
showResetToDefault={!isEqual(savedConfig, defaultConfig)}
|
||||
{disabled}
|
||||
/>
|
||||
|
@ -11,6 +11,7 @@
|
||||
import SettingButtonsRow from '../setting-buttons-row.svelte';
|
||||
import SettingSwitch from '../setting-switch.svelte';
|
||||
import SettingInputField, { SettingInputFieldType } from '../setting-input-field.svelte';
|
||||
import type { ResetOptions } from '$lib/utils/dipatch';
|
||||
|
||||
export let config: SystemConfigDto; // this is the config that is being edited
|
||||
export let disabled = false;
|
||||
@ -18,6 +19,14 @@
|
||||
let savedConfig: SystemConfigDto;
|
||||
let defaultConfig: SystemConfigDto;
|
||||
|
||||
const handleReset = (detail: ResetOptions) => {
|
||||
if (detail.default) {
|
||||
resetToDefault();
|
||||
} else {
|
||||
reset();
|
||||
}
|
||||
};
|
||||
|
||||
async function refreshConfig() {
|
||||
[savedConfig, defaultConfig] = await Promise.all([
|
||||
api.systemConfigApi.getConfig().then((res) => res.data),
|
||||
@ -133,9 +142,8 @@
|
||||
>
|
||||
|
||||
<SettingButtonsRow
|
||||
on:reset={reset}
|
||||
on:reset={({ detail }) => handleReset(detail)}
|
||||
on:save={saveSetting}
|
||||
on:reset-to-default={resetToDefault}
|
||||
showResetToDefault={!isEqual(
|
||||
{ ...savedConfig.map, ...savedConfig.reverseGeocoding },
|
||||
{ ...defaultConfig.map, ...defaultConfig.reverseGeocoding },
|
||||
|
@ -9,6 +9,7 @@
|
||||
import { fade } from 'svelte/transition';
|
||||
import SettingButtonsRow from '../setting-buttons-row.svelte';
|
||||
import SettingSwitch from '../setting-switch.svelte';
|
||||
import type { ResetOptions } from '$lib/utils/dipatch';
|
||||
|
||||
export let newVersionCheckConfig: SystemConfigNewVersionCheckDto; // this is the config that is being edited
|
||||
|
||||
@ -22,6 +23,14 @@
|
||||
]);
|
||||
}
|
||||
|
||||
const handleReset = (detail: ResetOptions) => {
|
||||
if (detail.default) {
|
||||
resetToDefault();
|
||||
} else {
|
||||
reset();
|
||||
}
|
||||
};
|
||||
|
||||
async function saveSetting() {
|
||||
try {
|
||||
const { data: configs } = await api.systemConfigApi.getConfig();
|
||||
@ -79,9 +88,8 @@
|
||||
bind:checked={newVersionCheckConfig.enabled}
|
||||
/>
|
||||
<SettingButtonsRow
|
||||
on:reset={reset}
|
||||
on:reset={({ detail }) => handleReset(detail)}
|
||||
on:save={saveSetting}
|
||||
on:reset-to-default={resetToDefault}
|
||||
showResetToDefault={!isEqual(savedConfig, defaultConfig)}
|
||||
/>
|
||||
</div>
|
||||
|
@ -11,6 +11,7 @@
|
||||
import SettingButtonsRow from '../setting-buttons-row.svelte';
|
||||
import SettingInputField, { SettingInputFieldType } from '../setting-input-field.svelte';
|
||||
import SettingSwitch from '../setting-switch.svelte';
|
||||
import type { ResetOptions } from '$lib/utils/dipatch';
|
||||
|
||||
export let oauthConfig: SystemConfigOAuthDto;
|
||||
export let disabled = false;
|
||||
@ -18,6 +19,14 @@
|
||||
let savedConfig: SystemConfigOAuthDto;
|
||||
let defaultConfig: SystemConfigOAuthDto;
|
||||
|
||||
const handleReset = (detail: ResetOptions) => {
|
||||
if (detail.default) {
|
||||
resetToDefault();
|
||||
} else {
|
||||
reset();
|
||||
}
|
||||
};
|
||||
|
||||
const handleToggleOverride = () => {
|
||||
// click runs before bind
|
||||
const previouslyEnabled = oauthConfig.mobileOverrideEnabled;
|
||||
@ -209,9 +218,8 @@
|
||||
{/if}
|
||||
|
||||
<SettingButtonsRow
|
||||
on:reset={reset}
|
||||
on:reset={({ detail }) => handleReset(detail)}
|
||||
on:save={saveSetting}
|
||||
on:reset-to-default={resetToDefault}
|
||||
showResetToDefault={!isEqual(savedConfig, defaultConfig)}
|
||||
{disabled}
|
||||
/>
|
||||
|
@ -10,6 +10,7 @@
|
||||
import ConfirmDisableLogin from '../confirm-disable-login.svelte';
|
||||
import SettingButtonsRow from '../setting-buttons-row.svelte';
|
||||
import SettingSwitch from '../setting-switch.svelte';
|
||||
import type { ResetOptions } from '$lib/utils/dipatch';
|
||||
|
||||
export let passwordLoginConfig: SystemConfigPasswordLoginDto; // this is the config that is being edited
|
||||
export let disabled = false;
|
||||
@ -17,6 +18,14 @@
|
||||
let savedConfig: SystemConfigPasswordLoginDto;
|
||||
let defaultConfig: SystemConfigPasswordLoginDto;
|
||||
|
||||
const handleReset = (detail: ResetOptions) => {
|
||||
if (detail.default) {
|
||||
resetToDefault();
|
||||
} else {
|
||||
reset();
|
||||
}
|
||||
};
|
||||
|
||||
async function getConfigs() {
|
||||
[savedConfig, defaultConfig] = await Promise.all([
|
||||
api.systemConfigApi.getConfig().then((res) => res.data.passwordLogin),
|
||||
@ -107,9 +116,8 @@
|
||||
/>
|
||||
|
||||
<SettingButtonsRow
|
||||
on:reset={reset}
|
||||
on:reset={({ detail }) => handleReset(detail)}
|
||||
on:save={saveSetting}
|
||||
on:reset-to-default={resetToDefault}
|
||||
showResetToDefault={!isEqual(savedConfig, defaultConfig)}
|
||||
{disabled}
|
||||
/>
|
||||
|
@ -1,8 +1,12 @@
|
||||
<script lang="ts">
|
||||
import Button from '$lib/components/elements/buttons/button.svelte';
|
||||
import type { ResetOptions } from '$lib/utils/dipatch';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
reset: ResetOptions;
|
||||
save: void;
|
||||
}>();
|
||||
|
||||
export let showResetToDefault = true;
|
||||
export let disabled = false;
|
||||
@ -12,7 +16,7 @@
|
||||
<div class="left">
|
||||
{#if showResetToDefault}
|
||||
<button
|
||||
on:click={() => dispatch('reset-to-default')}
|
||||
on:click={() => dispatch('reset', { default: true })}
|
||||
class="bg-none text-sm font-medium text-immich-primary hover:text-immich-primary/75 dark:text-immich-dark-primary hover:dark:text-immich-dark-primary/75"
|
||||
>
|
||||
Reset to default
|
||||
@ -21,7 +25,7 @@
|
||||
</div>
|
||||
|
||||
<div class="right">
|
||||
<Button {disabled} size="sm" color="gray" on:click={() => dispatch('reset')}>Reset</Button>
|
||||
<Button {disabled} size="sm" color="gray" on:click={() => dispatch('reset', { default: false })}>Reset</Button>
|
||||
<Button {disabled} size="sm" on:click={() => dispatch('save')}>Save</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -14,6 +14,7 @@
|
||||
} from '$lib/components/shared-components/notification/notification';
|
||||
import SettingInputField, { SettingInputFieldType } from '../setting-input-field.svelte';
|
||||
import { user } from '$lib/stores/user.store';
|
||||
import type { ResetOptions } from '$lib/utils/dipatch';
|
||||
|
||||
export let storageConfig: SystemConfigStorageTemplateDto;
|
||||
export let disabled = false;
|
||||
@ -23,6 +24,14 @@
|
||||
let templateOptions: SystemConfigTemplateStorageOptionDto;
|
||||
let selectedPreset = '';
|
||||
|
||||
const handleReset = (detail: ResetOptions) => {
|
||||
if (detail.default) {
|
||||
resetToDefault();
|
||||
} else {
|
||||
reset();
|
||||
}
|
||||
};
|
||||
|
||||
async function getConfigs() {
|
||||
[savedConfig, defaultConfig, templateOptions] = await Promise.all([
|
||||
api.systemConfigApi.getConfig().then((res) => res.data.storageTemplate),
|
||||
@ -232,9 +241,8 @@
|
||||
</div>
|
||||
|
||||
<SettingButtonsRow
|
||||
on:reset={reset}
|
||||
on:reset={({ detail }) => handleReset(detail)}
|
||||
on:save={saveSetting}
|
||||
on:reset-to-default={resetToDefault}
|
||||
showResetToDefault={!isEqual(savedConfig, defaultConfig)}
|
||||
{disabled}
|
||||
/>
|
||||
|
@ -9,6 +9,7 @@
|
||||
import { fade } from 'svelte/transition';
|
||||
import SettingButtonsRow from '../setting-buttons-row.svelte';
|
||||
import SettingTextarea from '../setting-textarea.svelte';
|
||||
import type { ResetOptions } from '$lib/utils/dipatch';
|
||||
|
||||
export let themeConfig: SystemConfigThemeDto; // this is the config that is being edited
|
||||
export let disabled = false;
|
||||
@ -16,6 +17,14 @@
|
||||
let savedConfig: SystemConfigThemeDto;
|
||||
let defaultConfig: SystemConfigThemeDto;
|
||||
|
||||
const handleReset = (detail: ResetOptions) => {
|
||||
if (detail.default) {
|
||||
resetToDefault();
|
||||
} else {
|
||||
reset();
|
||||
}
|
||||
};
|
||||
|
||||
async function getConfigs() {
|
||||
[savedConfig, defaultConfig] = await Promise.all([
|
||||
api.systemConfigApi.getConfig().then((res) => res.data.theme),
|
||||
@ -84,9 +93,8 @@
|
||||
/>
|
||||
|
||||
<SettingButtonsRow
|
||||
on:reset={reset}
|
||||
on:reset={({ detail }) => handleReset(detail)}
|
||||
on:save={saveSetting}
|
||||
on:reset-to-default={resetToDefault}
|
||||
showResetToDefault={!isEqual(savedConfig, defaultConfig)}
|
||||
{disabled}
|
||||
/>
|
||||
|
@ -10,6 +10,7 @@
|
||||
} from '$lib/components/shared-components/notification/notification';
|
||||
import SettingInputField, { SettingInputFieldType } from '../setting-input-field.svelte';
|
||||
import SettingSwitch from '../setting-switch.svelte';
|
||||
import type { ResetOptions } from '$lib/utils/dipatch';
|
||||
|
||||
export let thumbnailConfig: SystemConfigThumbnailDto; // this is the config that is being edited
|
||||
export let disabled = false;
|
||||
@ -17,6 +18,14 @@
|
||||
let savedConfig: SystemConfigThumbnailDto;
|
||||
let defaultConfig: SystemConfigThumbnailDto;
|
||||
|
||||
const handleReset = (detail: ResetOptions) => {
|
||||
if (detail.default) {
|
||||
resetToDefault();
|
||||
} else {
|
||||
reset();
|
||||
}
|
||||
};
|
||||
|
||||
async function getConfigs() {
|
||||
[savedConfig, defaultConfig] = await Promise.all([
|
||||
api.systemConfigApi.getConfig().then((res) => res.data.thumbnail),
|
||||
@ -133,9 +142,8 @@
|
||||
|
||||
<div class="ml-4">
|
||||
<SettingButtonsRow
|
||||
on:reset={reset}
|
||||
on:reset={({ detail }) => handleReset(detail)}
|
||||
on:save={saveSetting}
|
||||
on:reset-to-default={resetToDefault}
|
||||
showResetToDefault={!isEqual(savedConfig, defaultConfig)}
|
||||
{disabled}
|
||||
/>
|
||||
|
@ -10,6 +10,7 @@
|
||||
import SettingButtonsRow from '../setting-buttons-row.svelte';
|
||||
import SettingSwitch from '../setting-switch.svelte';
|
||||
import SettingInputField, { SettingInputFieldType } from '../setting-input-field.svelte';
|
||||
import type { ResetOptions } from '$lib/utils/dipatch';
|
||||
|
||||
export let trashConfig: SystemConfigTrashDto; // this is the config that is being edited
|
||||
export let disabled = false;
|
||||
@ -17,6 +18,14 @@
|
||||
let savedConfig: SystemConfigTrashDto;
|
||||
let defaultConfig: SystemConfigTrashDto;
|
||||
|
||||
const handleReset = (detail: ResetOptions) => {
|
||||
if (detail.default) {
|
||||
resetToDefault();
|
||||
} else {
|
||||
reset();
|
||||
}
|
||||
};
|
||||
|
||||
async function getConfigs() {
|
||||
[savedConfig, defaultConfig] = await Promise.all([
|
||||
api.systemConfigApi.getConfig().then((res) => res.data.trash),
|
||||
@ -90,9 +99,8 @@
|
||||
/>
|
||||
|
||||
<SettingButtonsRow
|
||||
on:reset={reset}
|
||||
on:reset={({ detail }) => handleReset(detail)}
|
||||
on:save={saveSetting}
|
||||
on:reset-to-default={resetToDefault}
|
||||
showResetToDefault={!isEqual(savedConfig, defaultConfig)}
|
||||
{disabled}
|
||||
/>
|
||||
|
@ -50,7 +50,12 @@
|
||||
let message = '';
|
||||
let isSendingMessage = false;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
deleteComment: void;
|
||||
deleteLike: void;
|
||||
addComment: void;
|
||||
close: void;
|
||||
}>();
|
||||
|
||||
$: showDeleteReaction = Array(reactions.length).fill(false);
|
||||
$: {
|
||||
|
@ -725,9 +725,9 @@
|
||||
albumId={album?.id}
|
||||
albums={appearsInAlbums}
|
||||
on:close={() => ($isShowDetail = false)}
|
||||
on:close-viewer={handleCloseViewer}
|
||||
on:description-focus-in={disableKeyDownEvent}
|
||||
on:description-focus-out={enableKeyDownEvent}
|
||||
on:closeViewer={handleCloseViewer}
|
||||
on:descriptionFocusIn={disableKeyDownEvent}
|
||||
on:descriptionFocusOut={enableKeyDownEvent}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -87,7 +87,13 @@
|
||||
unsubscribe();
|
||||
});
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
close: void;
|
||||
descriptionFocusIn: void;
|
||||
descriptionFocusOut: void;
|
||||
click: AlbumResponseDto;
|
||||
closeViewer: void;
|
||||
}>();
|
||||
|
||||
const getMegapixel = (width: number, height: number): number | undefined => {
|
||||
const megapixel = Math.round((height * width) / 1_000_000);
|
||||
@ -114,11 +120,11 @@
|
||||
};
|
||||
|
||||
const handleFocusIn = () => {
|
||||
dispatch('description-focus-in');
|
||||
dispatch('descriptionFocusIn');
|
||||
};
|
||||
|
||||
const handleFocusOut = async () => {
|
||||
dispatch('description-focus-out');
|
||||
dispatch('descriptionFocusOut');
|
||||
try {
|
||||
await api.assetApi.updateAsset({
|
||||
id: asset.id,
|
||||
@ -241,7 +247,7 @@
|
||||
href="{AppRoute.PEOPLE}/{person.id}?previousRoute={albumId
|
||||
? `${AppRoute.ALBUMS}/${albumId}`
|
||||
: AppRoute.PHOTOS}"
|
||||
on:click={() => dispatch('close-viewer')}
|
||||
on:click={() => dispatch('closeViewer')}
|
||||
>
|
||||
<div class="relative">
|
||||
<ImageThumbnail
|
||||
|
@ -11,7 +11,13 @@
|
||||
|
||||
let intersecting = false;
|
||||
let container: HTMLDivElement;
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
hidden: HTMLDivElement;
|
||||
intersected: {
|
||||
container: HTMLDivElement;
|
||||
position: BucketPosition;
|
||||
};
|
||||
}>();
|
||||
|
||||
onMount(() => {
|
||||
if (typeof IntersectionObserver !== 'undefined') {
|
||||
|
@ -8,7 +8,10 @@
|
||||
|
||||
export let album: AlbumResponseDto;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
editSuccess: void;
|
||||
cancel: void;
|
||||
}>();
|
||||
|
||||
const editUser = async () => {
|
||||
try {
|
||||
@ -21,7 +24,7 @@
|
||||
});
|
||||
|
||||
if (status === 200) {
|
||||
dispatch('edit-success');
|
||||
dispatch('editSuccess');
|
||||
}
|
||||
} catch (error) {
|
||||
handleError(error, 'Unable to update user');
|
||||
|
@ -6,8 +6,9 @@
|
||||
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
|
||||
import { handleError } from '../../utils/handle-error';
|
||||
import Icon from '$lib/components/elements/icon.svelte';
|
||||
import { mdiAccountEditOutline } from '@mdi/js';
|
||||
import { mdiAccountEditOutline, mdiClose } from '@mdi/js';
|
||||
import { AppRoute } from '$lib/constants';
|
||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
||||
|
||||
export let user: UserResponseDto;
|
||||
export let canResetPassword = true;
|
||||
@ -17,7 +18,11 @@
|
||||
|
||||
let isShowResetPasswordConfirmation = false;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
close: void;
|
||||
resetPasswordSuccess: void;
|
||||
editSuccess: void;
|
||||
}>();
|
||||
|
||||
const editUser = async () => {
|
||||
try {
|
||||
@ -33,7 +38,7 @@
|
||||
});
|
||||
|
||||
if (status === 200) {
|
||||
dispatch('edit-success');
|
||||
dispatch('editSuccess');
|
||||
}
|
||||
} catch (error) {
|
||||
handleError(error, 'Unable to update user');
|
||||
@ -53,7 +58,7 @@
|
||||
});
|
||||
|
||||
if (status == 200) {
|
||||
dispatch('reset-password-success');
|
||||
dispatch('resetPasswordSuccess');
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error reseting user password', e);
|
||||
@ -68,8 +73,12 @@
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="max-h-screen w-[500px] max-w-[95vw] overflow-y-auto rounded-3xl border bg-immich-bg p-4 py-8 shadow-sm dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:text-immich-dark-fg"
|
||||
class="relative max-h-screen w-[500px] max-w-[95vw] overflow-y-auto rounded-3xl border bg-immich-bg p-4 py-8 shadow-sm dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:text-immich-dark-fg"
|
||||
>
|
||||
<div class="absolute top-0 right-0 px-2 py-2 h-fit">
|
||||
<CircleIconButton icon={mdiClose} on:click={() => dispatch('close')} />
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex flex-col place-content-center place-items-center gap-4 px-4 text-immich-primary dark:text-immich-dark-primary"
|
||||
>
|
||||
|
@ -16,7 +16,10 @@
|
||||
let loading = false;
|
||||
let oauthLoading = true;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
success: void;
|
||||
firstLogin: void;
|
||||
}>();
|
||||
|
||||
onMount(async () => {
|
||||
if (!$featureFlags.oauth) {
|
||||
@ -62,7 +65,7 @@
|
||||
});
|
||||
|
||||
if (!data.isAdmin && data.shouldChangePassword) {
|
||||
dispatch('first-login');
|
||||
dispatch('firstLogin');
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,9 @@
|
||||
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
|
||||
|
||||
let showModal = false;
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
escape: void;
|
||||
}>();
|
||||
const { getAssets } = getAssetControlContext();
|
||||
const escape = () => {
|
||||
dispatch('escape');
|
||||
|
@ -19,7 +19,9 @@
|
||||
|
||||
const { clearSelect, getOwnedAssets } = getAssetControlContext();
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
escape: void;
|
||||
}>();
|
||||
|
||||
let isShowConfirmation = false;
|
||||
let loading = false;
|
||||
|
@ -12,7 +12,18 @@
|
||||
let loading = true;
|
||||
let search = '';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
newAlbum: {
|
||||
albumName: string;
|
||||
};
|
||||
album: {
|
||||
album: AlbumResponseDto;
|
||||
};
|
||||
newSharedAlbum: {
|
||||
albumName: string;
|
||||
};
|
||||
close: void;
|
||||
}>();
|
||||
|
||||
export let shared: boolean;
|
||||
|
||||
|
@ -7,7 +7,10 @@
|
||||
import { clickOutside } from '$lib/utils/click-outside';
|
||||
import { mdiClose } from '@mdi/js';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
escape: void;
|
||||
close: void;
|
||||
}>();
|
||||
export let zIndex = 9999;
|
||||
export let ignoreClickOutside = false;
|
||||
|
||||
|
@ -29,7 +29,10 @@
|
||||
let canCopyImagesToClipboard = true;
|
||||
let enablePassword = false;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
close: void;
|
||||
escape: void;
|
||||
}>();
|
||||
|
||||
const expiredDateOption: ImmichDropDownOption = {
|
||||
default: 'Never',
|
||||
|
@ -11,7 +11,9 @@
|
||||
let viewWidth: number;
|
||||
$: thumbnailSize = getThumbnailSize(assets.length, viewWidth);
|
||||
|
||||
let dispatch = createEventDispatcher();
|
||||
let dispatch = createEventDispatcher<{
|
||||
select: { asset: AssetResponseDto; selectedAssets: Set<AssetResponseDto> };
|
||||
}>();
|
||||
|
||||
const selectAssetHandler = (event: CustomEvent) => {
|
||||
const { asset }: { asset: AssetResponseDto } = event.detail;
|
||||
|
@ -16,7 +16,10 @@
|
||||
|
||||
let isShowSelectAvatar = false;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
logout: void;
|
||||
close: void;
|
||||
}>();
|
||||
|
||||
const handleSaveProfile = async (color: UserAvatarColor) => {
|
||||
try {
|
||||
|
@ -8,7 +8,10 @@
|
||||
|
||||
export let user: UserResponseDto;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
close: void;
|
||||
choose: UserAvatarColor;
|
||||
}>();
|
||||
const colors: UserAvatarColor[] = Object.values(UserAvatarColor);
|
||||
</script>
|
||||
|
||||
|
@ -23,7 +23,9 @@
|
||||
let shouldShowAccountInfo = false;
|
||||
let shouldShowAccountInfoPanel = false;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
uploadClicked: void;
|
||||
}>();
|
||||
|
||||
const logOut = async () => {
|
||||
const { data } = await api.authenticationApi.logout();
|
||||
|
@ -10,7 +10,9 @@
|
||||
|
||||
export let asset: AssetResponseDto;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
close: void;
|
||||
}>();
|
||||
let imgElement: HTMLDivElement;
|
||||
|
||||
onMount(() => {
|
||||
|
@ -19,7 +19,9 @@
|
||||
{ key: ['Del'], action: 'Delete Asset' },
|
||||
],
|
||||
};
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
close: void;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<FullScreenModal on:clickOutside={() => dispatch('close')} on:escape={() => dispatch('close')}>
|
||||
|
@ -11,7 +11,9 @@
|
||||
|
||||
let showMoreInformation = false;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
selected: void;
|
||||
}>();
|
||||
const onButtonClicked = () => dispatch('selected');
|
||||
</script>
|
||||
|
||||
|
@ -17,7 +17,9 @@
|
||||
|
||||
export let device: AuthDeviceResponseDto;
|
||||
|
||||
const dispatcher = createEventDispatcher();
|
||||
const dispatcher = createEventDispatcher<{
|
||||
delete: void;
|
||||
}>();
|
||||
|
||||
const options: ToRelativeCalendarOptions = {
|
||||
unit: 'days',
|
||||
|
3
web/src/lib/utils/dipatch.ts
Normal file
3
web/src/lib/utils/dipatch.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export interface ResetOptions {
|
||||
default?: boolean;
|
||||
}
|
@ -239,7 +239,7 @@
|
||||
<FullScreenModal on:clickOutside={() => (shouldShowEditUserForm = false)}>
|
||||
<EditAlbumForm
|
||||
album={selectedAlbum}
|
||||
on:edit-success={() => successModifyAlbum()}
|
||||
on:editSuccess={() => successModifyAlbum()}
|
||||
on:cancel={() => (shouldShowEditUserForm = false)}
|
||||
/>
|
||||
</FullScreenModal>
|
||||
|
@ -107,7 +107,7 @@
|
||||
|
||||
<UserPageLayout title={data.meta.title} admin>
|
||||
<section id="setting-content" class="flex place-content-center sm:mx-4">
|
||||
<section class="w-full pb-28 sm:w-5/6 md:w-[850px]">
|
||||
<section class="w-full pb-28 lg:w-[850px]">
|
||||
{#if shouldShowCreateUserForm}
|
||||
<FullScreenModal on:clickOutside={() => (shouldShowCreateUserForm = false)}>
|
||||
<CreateUserForm on:user-created={onUserCreated} on:cancel={() => (shouldShowCreateUserForm = false)} />
|
||||
@ -119,8 +119,9 @@
|
||||
<EditUserForm
|
||||
user={selectedUser}
|
||||
canResetPassword={selectedUser?.id !== $user.id}
|
||||
on:edit-success={onEditUserSuccess}
|
||||
on:editSuccess={onEditUserSuccess}
|
||||
on:reset-password-success={onEditPasswordSuccess}
|
||||
on:close={() => (shouldShowEditUserForm = false)}
|
||||
/>
|
||||
</FullScreenModal>
|
||||
{/if}
|
||||
@ -163,32 +164,34 @@
|
||||
</FullScreenModal>
|
||||
{/if}
|
||||
|
||||
<table class="my-5 hidden w-full text-left sm:block">
|
||||
<table class="my-5 w-full text-left">
|
||||
<thead
|
||||
class="mb-4 flex h-12 w-full rounded-md border bg-gray-50 text-immich-primary dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:text-immich-dark-primary"
|
||||
>
|
||||
<tr class="flex w-full place-items-center">
|
||||
<th class="w-4/12 text-center text-sm font-medium">Email</th>
|
||||
<th class="w-2/12 text-center text-sm font-medium">Name</th>
|
||||
<th class="w-2/12 text-center text-sm font-medium">Can import</th>
|
||||
<th class="w-2/12 text-center text-sm font-medium">Action</th>
|
||||
<th class="w-8/12 sm:w-5/12 lg:w-6/12 xl:w-4/12 2xl:w-5/12 text-center text-sm font-medium">Email</th>
|
||||
<th class="hidden sm:block w-3/12 text-center text-sm font-medium">Name</th>
|
||||
<th class="hidden xl:block w-3/12 2xl:w-2/12 text-center text-sm font-medium">Can import</th>
|
||||
<th class="w-4/12 lg:w-3/12 xl:w-2/12 text-center text-sm font-medium">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="block max-h-[320px] w-full overflow-y-auto rounded-md border dark:border-immich-dark-gray">
|
||||
{#if allUsers}
|
||||
{#each allUsers as immichUser, i}
|
||||
<tr
|
||||
class={`flex h-[80px] w-full place-items-center text-center dark:text-immich-dark-fg ${
|
||||
isDeleted(immichUser)
|
||||
? 'bg-red-300 dark:bg-red-900'
|
||||
: i % 2 == 0
|
||||
? 'bg-immich-gray dark:bg-immich-dark-gray/75'
|
||||
: 'bg-immich-bg dark:bg-immich-dark-gray/50'
|
||||
}`}
|
||||
class="flex h-[80px] overflow-hidden w-full place-items-center text-center dark:text-immich-dark-fg {isDeleted(
|
||||
immichUser,
|
||||
)
|
||||
? 'bg-red-300 dark:bg-red-900'
|
||||
: i % 2 == 0
|
||||
? 'bg-immich-gray dark:bg-immich-dark-gray/75'
|
||||
: 'bg-immich-bg dark:bg-immich-dark-gray/50'}"
|
||||
>
|
||||
<td class="w-4/12 text-ellipsis break-all px-2 text-sm">{immichUser.email}</td>
|
||||
<td class="w-2/12 text-ellipsis break-all px-2 text-sm">{immichUser.name}</td>
|
||||
<td class="w-2/12 text-ellipsis break-all px-2 text-sm">
|
||||
<td class="w-8/12 sm:w-5/12 lg:w-6/12 xl:w-4/12 2xl:w-5/12 text-ellipsis break-all px-2 text-sm"
|
||||
>{immichUser.email}</td
|
||||
>
|
||||
<td class="hidden sm:block w-3/12 text-ellipsis break-all px-2 text-sm">{immichUser.name}</td>
|
||||
<td class="hidden xl:block w-3/12 2xl:w-2/12 text-ellipsis break-all px-2 text-sm">
|
||||
<div class="container mx-auto flex flex-wrap justify-center">
|
||||
{#if immichUser.externalPath}
|
||||
<Icon path={mdiCheck} size="16" />
|
||||
@ -197,18 +200,18 @@
|
||||
{/if}
|
||||
</div>
|
||||
</td>
|
||||
<td class="w-2/12 text-ellipsis break-all px-4 text-sm">
|
||||
<td class="w-4/12 lg:w-3/12 xl:w-2/12 text-ellipsis break-all px-4 text-sm">
|
||||
{#if !isDeleted(immichUser)}
|
||||
<button
|
||||
on:click={() => editUserHandler(immichUser)}
|
||||
class="rounded-full bg-immich-primary p-3 text-gray-100 transition-all duration-150 hover:bg-immich-primary/75 dark:bg-immich-dark-primary dark:text-gray-700"
|
||||
class="rounded-full bg-immich-primary p-2 sm:p-3 text-gray-100 transition-all duration-150 hover:bg-immich-primary/75 dark:bg-immich-dark-primary dark:text-gray-700 max-sm:mb-1"
|
||||
>
|
||||
<Icon path={mdiPencilOutline} size="16" />
|
||||
</button>
|
||||
{#if immichUser.id !== $user.id}
|
||||
<button
|
||||
on:click={() => deleteUserHandler(immichUser)}
|
||||
class="rounded-full bg-immich-primary p-3 text-gray-100 transition-all duration-150 hover:bg-immich-primary/75 dark:bg-immich-dark-primary dark:text-gray-700"
|
||||
class="rounded-full bg-immich-primary p-2 sm:p-3 text-gray-100 transition-all duration-150 hover:bg-immich-primary/75 dark:bg-immich-dark-primary dark:text-gray-700"
|
||||
>
|
||||
<Icon path={mdiTrashCanOutline} size="16" />
|
||||
</button>
|
||||
@ -218,62 +221,7 @@
|
||||
<button
|
||||
on:click={() => restoreUserHandler(immichUser)}
|
||||
class="rounded-full bg-immich-primary p-3 text-gray-100 transition-all duration-150 hover:bg-immich-primary/75 dark:bg-immich-dark-primary dark:text-gray-700"
|
||||
title={`scheduled removal on ${getDeleteDate(immichUser)}`}
|
||||
>
|
||||
<Icon path={mdiDeleteRestore} size="16" />
|
||||
</button>
|
||||
{/if}
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
{/if}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table class="my-5 block w-full text-left sm:hidden">
|
||||
<thead
|
||||
class="mb-4 flex h-12 w-full rounded-md border bg-gray-50 text-immich-primary dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:text-immich-dark-primary"
|
||||
>
|
||||
<tr class="flex w-full place-items-center">
|
||||
<th class="w-1/4 text-center text-sm font-medium">Name</th>
|
||||
<th class="w-1/2 text-center text-sm font-medium">Email</th>
|
||||
<th class="w-1/4 text-center text-sm font-medium">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="block max-h-[320px] w-full overflow-y-auto rounded-md border dark:border-immich-dark-gray">
|
||||
{#if allUsers}
|
||||
{#each allUsers as user, i}
|
||||
<tr
|
||||
class={`flex h-[80px] w-full place-items-center text-center dark:text-immich-dark-fg ${
|
||||
isDeleted(user)
|
||||
? 'bg-red-300 dark:bg-red-900'
|
||||
: i % 2 == 0
|
||||
? 'bg-immich-gray dark:bg-immich-dark-gray/75'
|
||||
: 'bg-immich-bg dark:bg-immich-dark-gray/50'
|
||||
}`}
|
||||
>
|
||||
<td class="w-1/4 text-ellipsis break-words px-2 text-sm">{user.name}</td>
|
||||
<td class="w-1/2 text-ellipsis break-all px-2 text-sm">{user.email}</td>
|
||||
<td class="w-1/4 text-ellipsis px-2 text-sm">
|
||||
{#if !isDeleted(user)}
|
||||
<button
|
||||
on:click={() => editUserHandler(user)}
|
||||
class="rounded-full bg-immich-primary p-2 text-gray-100 transition-all duration-150 hover:bg-immich-primary/75 dark:bg-immich-dark-primary dark:text-gray-700 max-sm:mb-1 sm:p-3"
|
||||
>
|
||||
<Icon path={mdiPencilOutline} size="16" />
|
||||
</button>
|
||||
<button
|
||||
on:click={() => deleteUserHandler(user)}
|
||||
class="rounded-full bg-immich-primary p-2 text-gray-100 transition-all duration-150 hover:bg-immich-primary/75 dark:bg-immich-dark-primary dark:text-gray-700 sm:p-3"
|
||||
>
|
||||
<Icon path={mdiTrashCanOutline} size="16" />
|
||||
</button>
|
||||
{/if}
|
||||
{#if isDeleted(user)}
|
||||
<button
|
||||
on:click={() => restoreUserHandler(user)}
|
||||
class="rounded-full bg-immich-primary p-2 text-gray-100 transition-all duration-150 hover:bg-immich-primary/75 dark:bg-immich-dark-primary dark:text-gray-700 sm:p-3"
|
||||
title={`scheduled removal on ${getDeleteDate(user)}`}
|
||||
title="scheduled removal on {getDeleteDate(immichUser)}"
|
||||
>
|
||||
<Icon path={mdiDeleteRestore} size="16" />
|
||||
</button>
|
||||
|
Loading…
Reference in New Issue
Block a user