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:
Jason Rasmussen 2023-05-21 23:18:10 -04:00 committed by GitHub
parent 0ccb73cf2b
commit 74353193f8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
43 changed files with 452 additions and 137 deletions

View file

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

View file

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

View file

@ -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) => {

View file

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

View file

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

View file

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

View file

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

View file

@ -54,5 +54,5 @@
</SettingAccordion>
<SettingAccordion title="Sharing" subtitle="Manage sharing with partners">
<PartnerSettings />
<PartnerSettings {user} />
</SettingAccordion>