mirror of
https://github.com/immich-app/immich
synced 2025-11-07 17:27:20 +00:00
feat(web,server): user storage label (#2418)
* feat: user storage label * chore: open api * fix: checks * fix: api update validation and tests * feat: default admin storage label * fix: linting * fix: user create/update dto * fix: delete library with custom label
This commit is contained in:
parent
0ccb73cf2b
commit
74353193f8
43 changed files with 452 additions and 137 deletions
|
|
@ -2,15 +2,24 @@
|
|||
import { api, UserResponseDto } from '@api';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import Button from '../elements/buttons/button.svelte';
|
||||
import { handleError } from '../../utils/handle-error';
|
||||
|
||||
export let user: UserResponseDto;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
const deleteUser = async () => {
|
||||
const deletedUser = await api.userApi.deleteUser(user.id);
|
||||
if (deletedUser.data.deletedAt != null) dispatch('user-delete-success');
|
||||
else dispatch('user-delete-fail');
|
||||
try {
|
||||
const deletedUser = await api.userApi.deleteUser(user.id);
|
||||
if (deletedUser.data.deletedAt != null) {
|
||||
dispatch('user-delete-success');
|
||||
} else {
|
||||
dispatch('user-delete-fail');
|
||||
}
|
||||
} catch (error) {
|
||||
handleError(error, 'Unable to delete user');
|
||||
dispatch('user-delete-fail');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -171,14 +171,14 @@
|
|||
</p>
|
||||
|
||||
<p class="text-xs">
|
||||
{user.id} is the user's ID
|
||||
<code>{user.storageLabel || user.id}</code> is the user's Storage Label
|
||||
</p>
|
||||
|
||||
<p
|
||||
class="text-xs p-4 bg-gray-200 dark:bg-gray-700 dark:text-immich-dark-fg py-2 rounded-lg mt-2"
|
||||
>
|
||||
<span class="text-immich-fg/25 dark:text-immich-dark-fg/50"
|
||||
>UPLOAD_LOCATION/{user.id}</span
|
||||
>UPLOAD_LOCATION/{user.storageLabel || user.id}</span
|
||||
>/{parsedTemplate()}.jpg
|
||||
</p>
|
||||
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@
|
|||
await getSharedLinks();
|
||||
const { data } = await api.userApi.getAllUsers(false);
|
||||
|
||||
// remove soft deleted users
|
||||
users = data.filter((user) => !user.deletedAt);
|
||||
// remove invalid users
|
||||
users = data.filter((user) => !(user.deletedAt || user.id === album.ownerId));
|
||||
|
||||
// Remove the existed shared users from the album
|
||||
sharedUsersInAlbum.forEach((sharedUser) => {
|
||||
|
|
|
|||
|
|
@ -7,8 +7,10 @@
|
|||
NotificationType
|
||||
} from '../shared-components/notification/notification';
|
||||
import Button from '../elements/buttons/button.svelte';
|
||||
import { handleError } from '../../utils/handle-error';
|
||||
|
||||
export let user: UserResponseDto;
|
||||
export let canResetPassword = true;
|
||||
|
||||
let error: string;
|
||||
let success: string;
|
||||
|
|
@ -17,18 +19,20 @@
|
|||
|
||||
const editUser = async () => {
|
||||
try {
|
||||
const { id, email, firstName, lastName } = user;
|
||||
const { status } = await api.userApi.updateUser({ id, email, firstName, lastName });
|
||||
const { id, email, firstName, lastName, storageLabel } = user;
|
||||
const { status } = await api.userApi.updateUser({
|
||||
id,
|
||||
email,
|
||||
firstName,
|
||||
lastName,
|
||||
storageLabel: storageLabel || ''
|
||||
});
|
||||
|
||||
if (status === 200) {
|
||||
dispatch('edit-success');
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error updating user ', e);
|
||||
notificationController.show({
|
||||
message: 'Error updating user, check console for more details',
|
||||
type: NotificationType.Error
|
||||
});
|
||||
} catch (error) {
|
||||
handleError(error, 'Unable to update user');
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -105,6 +109,24 @@
|
|||
/>
|
||||
</div>
|
||||
|
||||
<div class="m-4 flex flex-col gap-2">
|
||||
<label class="immich-form-label" for="storage-label">Storage Label</label>
|
||||
<input
|
||||
class="immich-form-input"
|
||||
id="storage-label"
|
||||
name="storage-label"
|
||||
type="text"
|
||||
bind:value={user.storageLabel}
|
||||
/>
|
||||
|
||||
<p>
|
||||
Note: To apply the Storage Label to previously uploaded assets, run the <a
|
||||
href="/admin/jobs-status"
|
||||
class="text-immich-primary dark:text-immich-dark-primary">Storage Migration Job</a
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{#if error}
|
||||
<p class="text-red-400 ml-4 text-sm">{error}</p>
|
||||
{/if}
|
||||
|
|
@ -113,7 +135,9 @@
|
|||
<p class="text-immich-primary ml-4 text-sm">{success}</p>
|
||||
{/if}
|
||||
<div class="flex w-full px-4 gap-4 mt-8">
|
||||
<Button color="light-red" fullwidth on:click={resetPassword}>Reset password</Button>
|
||||
{#if canResetPassword}
|
||||
<Button color="light-red" fullwidth on:click={resetPassword}>Reset password</Button>
|
||||
{/if}
|
||||
<Button type="submit" fullwidth>Confirm</Button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
import Button from '../elements/buttons/button.svelte';
|
||||
import { createEventDispatcher, onMount } from 'svelte';
|
||||
|
||||
export let user: UserResponseDto;
|
||||
|
||||
let availableUsers: UserResponseDto[] = [];
|
||||
let selectedUsers: UserResponseDto[] = [];
|
||||
|
||||
|
|
@ -15,8 +17,8 @@
|
|||
// TODO: update endpoint to have a query param for deleted users
|
||||
let { data: users } = await api.userApi.getAllUsers(false);
|
||||
|
||||
// remove soft deleted users
|
||||
users = users.filter((user) => !user.deletedAt);
|
||||
// remove invalid users
|
||||
users = users.filter((_user) => !(_user.deletedAt || _user.id === user.id));
|
||||
|
||||
// exclude partners from the list of users available for selection
|
||||
const { data: partners } = await api.partnerApi.getPartners('shared-by');
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
import ConfirmDialogue from '../shared-components/confirm-dialogue.svelte';
|
||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
||||
|
||||
export let user: UserResponseDto;
|
||||
|
||||
let partners: UserResponseDto[] = [];
|
||||
let createPartner = false;
|
||||
let removePartner: UserResponseDto | null = null;
|
||||
|
|
@ -83,6 +85,7 @@
|
|||
|
||||
{#if createPartner}
|
||||
<PartnerSelectionModal
|
||||
{user}
|
||||
on:close={() => (createPartner = false)}
|
||||
on:add-users={(event) => handleCreatePartners(event.detail)}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -65,6 +65,14 @@
|
|||
required={true}
|
||||
/>
|
||||
|
||||
<SettingInputField
|
||||
inputType={SettingInputFieldType.TEXT}
|
||||
label="STORAGE LABEL"
|
||||
disabled={true}
|
||||
value={user.storageLabel || ''}
|
||||
required={false}
|
||||
/>
|
||||
|
||||
<div class="flex justify-end">
|
||||
<Button type="submit" size="sm" on:click={() => handleSaveProfile()}>Save</Button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -54,5 +54,5 @@
|
|||
</SettingAccordion>
|
||||
|
||||
<SettingAccordion title="Sharing" subtitle="Manage sharing with partners">
|
||||
<PartnerSettings />
|
||||
<PartnerSettings {user} />
|
||||
</SettingAccordion>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue