mirror of
https://github.com/jeffvli/feishin.git
synced 2024-11-20 06:27:09 +01:00
Add owner to playlist update query
- Support smart playlist rules - Add user list query
This commit is contained in:
parent
75ef43dffb
commit
d63e5f5784
@ -35,6 +35,8 @@ import type {
|
||||
RawArtistListResponse,
|
||||
UpdatePlaylistArgs,
|
||||
RawUpdatePlaylistResponse,
|
||||
UserListArgs,
|
||||
RawUserListResponse,
|
||||
} from '/@/renderer/api/types';
|
||||
import { subsonicApi } from '/@/renderer/api/subsonic.api';
|
||||
import { jellyfinApi } from '/@/renderer/api/jellyfin.api';
|
||||
@ -62,6 +64,7 @@ export type ControllerEndpoint = Partial<{
|
||||
getPlaylistSongList: (args: PlaylistSongListArgs) => Promise<RawSongListResponse>;
|
||||
getSongDetail: (args: SongDetailArgs) => Promise<RawSongDetailResponse>;
|
||||
getSongList: (args: SongListArgs) => Promise<RawSongListResponse>;
|
||||
getUserList: (args: UserListArgs) => Promise<RawUserListResponse>;
|
||||
updatePlaylist: (args: UpdatePlaylistArgs) => Promise<RawUpdatePlaylistResponse>;
|
||||
updateRating: (args: RatingArgs) => Promise<RawRatingResponse>;
|
||||
}>;
|
||||
@ -96,6 +99,7 @@ const endpoints: ApiController = {
|
||||
getPlaylistSongList: jellyfinApi.getPlaylistSongList,
|
||||
getSongDetail: undefined,
|
||||
getSongList: jellyfinApi.getSongList,
|
||||
getUserList: undefined,
|
||||
updatePlaylist: jellyfinApi.updatePlaylist,
|
||||
updateRating: undefined,
|
||||
},
|
||||
@ -122,6 +126,7 @@ const endpoints: ApiController = {
|
||||
getPlaylistSongList: navidromeApi.getPlaylistSongList,
|
||||
getSongDetail: navidromeApi.getSongDetail,
|
||||
getSongList: navidromeApi.getSongList,
|
||||
getUserList: navidromeApi.getUserList,
|
||||
updatePlaylist: navidromeApi.updatePlaylist,
|
||||
updateRating: subsonicApi.updateRating,
|
||||
},
|
||||
@ -147,6 +152,7 @@ const endpoints: ApiController = {
|
||||
getPlaylistList: undefined,
|
||||
getSongDetail: undefined,
|
||||
getSongList: undefined,
|
||||
getUserList: undefined,
|
||||
updatePlaylist: undefined,
|
||||
updateRating: undefined,
|
||||
},
|
||||
@ -227,6 +233,10 @@ const getPlaylistSongList = async (args: PlaylistSongListArgs) => {
|
||||
);
|
||||
};
|
||||
|
||||
const getUserList = async (args: UserListArgs) => {
|
||||
return (apiController('getUserList') as ControllerEndpoint['getUserList'])?.(args);
|
||||
};
|
||||
|
||||
export const controller = {
|
||||
createPlaylist,
|
||||
deletePlaylist,
|
||||
@ -240,5 +250,6 @@ export const controller = {
|
||||
getPlaylistList,
|
||||
getPlaylistSongList,
|
||||
getSongList,
|
||||
getUserList,
|
||||
updatePlaylist,
|
||||
};
|
||||
|
@ -433,26 +433,26 @@ const getPlaylistList = async (args: PlaylistListArgs): Promise<JFPlaylistList>
|
||||
};
|
||||
|
||||
const createPlaylist = async (args: CreatePlaylistArgs): Promise<CreatePlaylistResponse> => {
|
||||
const { query, server } = args;
|
||||
const { body, server } = args;
|
||||
|
||||
const body = {
|
||||
const json = {
|
||||
MediaType: 'Audio',
|
||||
Name: query.name,
|
||||
Overview: query.comment || '',
|
||||
Name: body.name,
|
||||
Overview: body.comment || '',
|
||||
UserId: server?.userId,
|
||||
};
|
||||
|
||||
const data = await api
|
||||
.post('playlists', {
|
||||
headers: { 'X-MediaBrowser-Token': server?.credential },
|
||||
json: body,
|
||||
json,
|
||||
prefixUrl: server?.url,
|
||||
})
|
||||
.json<JFCreatePlaylistResponse>();
|
||||
|
||||
return {
|
||||
id: data.Id,
|
||||
name: query.name,
|
||||
name: body.name,
|
||||
};
|
||||
};
|
||||
|
||||
@ -760,12 +760,13 @@ const normalizePlaylist = (
|
||||
imagePlaceholderUrl,
|
||||
imageUrl: imageUrl || null,
|
||||
name: item.Name,
|
||||
owner: null,
|
||||
ownerId: null,
|
||||
public: null,
|
||||
rules: null,
|
||||
size: null,
|
||||
songCount: item?.ChildCount || null,
|
||||
userId: null,
|
||||
username: null,
|
||||
sync: null,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -37,9 +37,13 @@ import type {
|
||||
NDPlaylistSongListResponse,
|
||||
NDPlaylistSongList,
|
||||
NDPlaylistSong,
|
||||
NDUserList,
|
||||
NDUserListResponse,
|
||||
NDUserListParams,
|
||||
NDUser,
|
||||
} from '/@/renderer/api/navidrome.types';
|
||||
import { NDPlaylistListSort, NDSongListSort, NDSortOrder } from '/@/renderer/api/navidrome.types';
|
||||
import type {
|
||||
import { NDSongListSort, NDSortOrder } from '/@/renderer/api/navidrome.types';
|
||||
import {
|
||||
Album,
|
||||
Song,
|
||||
AuthenticationResponse,
|
||||
@ -60,13 +64,14 @@ import type {
|
||||
Playlist,
|
||||
UpdatePlaylistResponse,
|
||||
UpdatePlaylistArgs,
|
||||
} from '/@/renderer/api/types';
|
||||
import {
|
||||
UserListArgs,
|
||||
userListSortMap,
|
||||
playlistListSortMap,
|
||||
albumArtistListSortMap,
|
||||
songListSortMap,
|
||||
albumListSortMap,
|
||||
sortOrderMap,
|
||||
User,
|
||||
} from '/@/renderer/api/types';
|
||||
import { toast } from '/@/renderer/components/toast';
|
||||
import { useAuthStore } from '/@/renderer/store';
|
||||
@ -132,6 +137,34 @@ const authenticate = async (
|
||||
};
|
||||
};
|
||||
|
||||
const getUserList = async (args: UserListArgs): Promise<NDUserList> => {
|
||||
const { query, server, signal } = args;
|
||||
|
||||
const searchParams: NDUserListParams = {
|
||||
_end: query.startIndex + (query.limit || 0),
|
||||
_order: sortOrderMap.navidrome[query.sortOrder],
|
||||
_sort: userListSortMap.navidrome[query.sortBy],
|
||||
_start: query.startIndex,
|
||||
...query.ndParams,
|
||||
};
|
||||
|
||||
const res = await api.get('api/user', {
|
||||
headers: { 'x-nd-authorization': `Bearer ${server?.ndCredential}` },
|
||||
prefixUrl: server?.url,
|
||||
searchParams: parseSearchParams(searchParams),
|
||||
signal,
|
||||
});
|
||||
|
||||
const data = await res.json<NDUserListResponse>();
|
||||
const itemCount = res.headers.get('x-total-count');
|
||||
|
||||
return {
|
||||
items: data,
|
||||
startIndex: query?.startIndex || 0,
|
||||
totalRecordCount: Number(itemCount),
|
||||
};
|
||||
};
|
||||
|
||||
const getGenreList = async (args: GenreListArgs): Promise<NDGenreList> => {
|
||||
const { server, signal } = args;
|
||||
|
||||
@ -293,12 +326,14 @@ const getSongDetail = async (args: SongDetailArgs): Promise<NDSongDetail> => {
|
||||
};
|
||||
|
||||
const createPlaylist = async (args: CreatePlaylistArgs): Promise<CreatePlaylistResponse> => {
|
||||
const { query, server } = args;
|
||||
const { body, server } = args;
|
||||
|
||||
const json: NDCreatePlaylistParams = {
|
||||
comment: query.comment,
|
||||
name: query.name,
|
||||
public: query.public || false,
|
||||
comment: body.comment,
|
||||
name: body.name,
|
||||
...body.ndParams,
|
||||
public: body.ndParams?.public || false,
|
||||
rules: body.ndParams?.rules ? body.ndParams.rules : undefined,
|
||||
};
|
||||
|
||||
const data = await api
|
||||
@ -311,7 +346,7 @@ const createPlaylist = async (args: CreatePlaylistArgs): Promise<CreatePlaylistR
|
||||
|
||||
return {
|
||||
id: data.id,
|
||||
name: query.name,
|
||||
name: body.name,
|
||||
};
|
||||
};
|
||||
|
||||
@ -321,7 +356,11 @@ const updatePlaylist = async (args: UpdatePlaylistArgs): Promise<UpdatePlaylistR
|
||||
const json: NDUpdatePlaylistParams = {
|
||||
comment: body.comment || '',
|
||||
name: body.name,
|
||||
public: body.public || false,
|
||||
ownerId: body.ndParams?.ownerId || undefined,
|
||||
ownerName: body.ndParams?.owner || undefined,
|
||||
public: body.ndParams?.public || false,
|
||||
rules: body.ndParams?.rules ? body.ndParams?.rules : undefined,
|
||||
sync: body.ndParams?.sync || undefined,
|
||||
};
|
||||
|
||||
const data = await api
|
||||
@ -357,8 +396,8 @@ const getPlaylistList = async (args: PlaylistListArgs): Promise<NDPlaylistList>
|
||||
|
||||
const searchParams: NDPlaylistListParams = {
|
||||
_end: query.startIndex + (query.limit || 0),
|
||||
_order: query.sortOrder ? sortOrderMap.navidrome[query.sortOrder] : NDSortOrder.ASC,
|
||||
_sort: query.sortBy ? playlistListSortMap.navidrome[query.sortBy] : NDPlaylistListSort.NAME,
|
||||
_order: query.sortOrder ? sortOrderMap.navidrome[query.sortOrder] : undefined,
|
||||
_sort: query.sortBy ? playlistListSortMap.navidrome[query.sortBy] : undefined,
|
||||
_start: query.startIndex,
|
||||
...query.ndParams,
|
||||
};
|
||||
@ -583,12 +622,25 @@ const normalizePlaylist = (
|
||||
imagePlaceholderUrl,
|
||||
imageUrl,
|
||||
name: item.name,
|
||||
owner: item.ownerName,
|
||||
ownerId: item.ownerId,
|
||||
public: item.public,
|
||||
rules: item?.rules || null,
|
||||
size: item.size,
|
||||
songCount: item.songCount,
|
||||
userId: item.ownerId,
|
||||
username: item.ownerName,
|
||||
sync: item.sync,
|
||||
};
|
||||
};
|
||||
|
||||
const normalizeUser = (item: NDUser): User => {
|
||||
return {
|
||||
createdAt: item.createdAt,
|
||||
email: item.email,
|
||||
id: item.id,
|
||||
isAdmin: item.isAdmin,
|
||||
lastLoginAt: item.lastLoginAt,
|
||||
name: item.userName,
|
||||
updatedAt: item.updatedAt,
|
||||
};
|
||||
};
|
||||
|
||||
@ -606,6 +658,7 @@ export const navidromeApi = {
|
||||
getPlaylistSongList,
|
||||
getSongDetail,
|
||||
getSongList,
|
||||
getUserList,
|
||||
updatePlaylist,
|
||||
};
|
||||
|
||||
@ -614,4 +667,5 @@ export const ndNormalize = {
|
||||
albumArtist: normalizeAlbumArtist,
|
||||
playlist: normalizePlaylist,
|
||||
song: normalizeSong,
|
||||
user: normalizeUser,
|
||||
};
|
||||
|
@ -8,6 +8,18 @@ export type NDAuthenticate = {
|
||||
username: string;
|
||||
};
|
||||
|
||||
export type NDUser = {
|
||||
createdAt: string;
|
||||
email: string;
|
||||
id: string;
|
||||
isAdmin: boolean;
|
||||
lastAccessAt: string;
|
||||
lastLoginAt: string;
|
||||
name: string;
|
||||
updatedAt: string;
|
||||
userName: string;
|
||||
};
|
||||
|
||||
export type NDGenre = {
|
||||
id: string;
|
||||
name: string;
|
||||
@ -376,3 +388,20 @@ export const NDSongQueryFields = [
|
||||
{ label: 'Play count', value: 'playcount' },
|
||||
{ label: 'Rating', value: 'rating' },
|
||||
];
|
||||
|
||||
export type NDUserListParams = {
|
||||
_sort?: NDUserListSort;
|
||||
} & NDPagination &
|
||||
NDOrder;
|
||||
|
||||
export type NDUserListResponse = NDUser[];
|
||||
|
||||
export type NDUserList = {
|
||||
items: NDUser[];
|
||||
startIndex: number;
|
||||
totalRecordCount: number;
|
||||
};
|
||||
|
||||
export enum NDUserListSort {
|
||||
NAME = 'name',
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import type {
|
||||
NDGenreList,
|
||||
NDPlaylist,
|
||||
NDSong,
|
||||
NDUser,
|
||||
} from '/@/renderer/api/navidrome.types';
|
||||
import { SSGenreList, SSMusicFolderList } from '/@/renderer/api/subsonic.types';
|
||||
import type {
|
||||
@ -26,6 +27,7 @@ import type {
|
||||
RawPlaylistDetailResponse,
|
||||
RawPlaylistListResponse,
|
||||
RawSongListResponse,
|
||||
RawUserListResponse,
|
||||
} from '/@/renderer/api/types';
|
||||
import { ServerListItem } from '/@/renderer/types';
|
||||
|
||||
@ -211,6 +213,25 @@ const playlistDetail = (
|
||||
return playlist;
|
||||
};
|
||||
|
||||
const userList = (data: RawUserListResponse | undefined, server: ServerListItem | null) => {
|
||||
let users;
|
||||
switch (server?.type) {
|
||||
case 'jellyfin':
|
||||
break;
|
||||
case 'navidrome':
|
||||
users = data?.items.map((item) => ndNormalize.user(item as NDUser));
|
||||
break;
|
||||
case 'subsonic':
|
||||
break;
|
||||
}
|
||||
|
||||
return {
|
||||
items: users,
|
||||
startIndex: data?.startIndex,
|
||||
totalRecordCount: data?.totalRecordCount,
|
||||
};
|
||||
};
|
||||
|
||||
export const normalize = {
|
||||
albumArtistList,
|
||||
albumDetail,
|
||||
@ -220,4 +241,5 @@ export const normalize = {
|
||||
playlistDetail,
|
||||
playlistList,
|
||||
songList,
|
||||
userList,
|
||||
};
|
||||
|
@ -7,6 +7,7 @@ import type {
|
||||
PlaylistListQuery,
|
||||
PlaylistDetailQuery,
|
||||
PlaylistSongListQuery,
|
||||
UserListQuery,
|
||||
} from './types';
|
||||
|
||||
export const queryKeys = {
|
||||
@ -79,4 +80,11 @@ export const queryKeys = {
|
||||
},
|
||||
root: (serverId: string) => [serverId, 'songs'] as const,
|
||||
},
|
||||
users: {
|
||||
list: (serverId: string, query?: UserListQuery) => {
|
||||
if (query) return [serverId, 'users', 'list', query] as const;
|
||||
return [serverId, 'users', 'list'] as const;
|
||||
},
|
||||
root: (serverId: string) => [serverId, 'users'] as const,
|
||||
},
|
||||
};
|
||||
|
@ -33,6 +33,8 @@ import {
|
||||
NDPlaylistListSort,
|
||||
NDPlaylistDetail,
|
||||
NDSongListSort,
|
||||
NDUserList,
|
||||
NDUserListSort,
|
||||
} from '/@/renderer/api/navidrome.types';
|
||||
import {
|
||||
SSAlbumList,
|
||||
@ -48,6 +50,16 @@ export enum SortOrder {
|
||||
DESC = 'DESC',
|
||||
}
|
||||
|
||||
export type User = {
|
||||
createdAt: string | null;
|
||||
email: string | null;
|
||||
id: string;
|
||||
isAdmin: boolean | null;
|
||||
lastLoginAt: string | null;
|
||||
name: string;
|
||||
updatedAt: string | null;
|
||||
};
|
||||
|
||||
export type ServerListItem = {
|
||||
credential: string;
|
||||
id: string;
|
||||
@ -242,12 +254,13 @@ export type Playlist = {
|
||||
imagePlaceholderUrl: string | null;
|
||||
imageUrl: string | null;
|
||||
name: string;
|
||||
owner: string | null;
|
||||
ownerId: string | null;
|
||||
public: boolean | null;
|
||||
rules?: Record<string, any> | null;
|
||||
size: number | null;
|
||||
songCount: number | null;
|
||||
userId: string | null;
|
||||
username: string | null;
|
||||
sync?: boolean | null;
|
||||
};
|
||||
|
||||
export type GenresResponse = Genre[];
|
||||
@ -739,14 +752,19 @@ export type RawCreatePlaylistResponse = CreatePlaylistResponse | undefined;
|
||||
|
||||
export type CreatePlaylistResponse = { id: string; name: string };
|
||||
|
||||
export type CreatePlaylistQuery = {
|
||||
export type CreatePlaylistBody = {
|
||||
comment?: string;
|
||||
name: string;
|
||||
public?: boolean;
|
||||
rules?: Record<string, any>;
|
||||
ndParams?: {
|
||||
owner?: string;
|
||||
ownerId?: string;
|
||||
public?: boolean;
|
||||
rules?: Record<string, any>;
|
||||
sync?: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
export type CreatePlaylistArgs = { query: CreatePlaylistQuery } & BaseEndpointArgs;
|
||||
export type CreatePlaylistArgs = { body: CreatePlaylistBody } & BaseEndpointArgs;
|
||||
|
||||
// Update Playlist
|
||||
export type RawUpdatePlaylistResponse = UpdatePlaylistResponse | undefined;
|
||||
@ -761,8 +779,13 @@ export type UpdatePlaylistBody = {
|
||||
comment?: string;
|
||||
genres?: Genre[];
|
||||
name: string;
|
||||
public?: boolean;
|
||||
rules?: Record<string, any>;
|
||||
ndParams?: {
|
||||
owner?: string;
|
||||
ownerId?: string;
|
||||
public?: boolean;
|
||||
rules?: Record<string, any>;
|
||||
sync?: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
export type UpdatePlaylistArgs = {
|
||||
@ -880,3 +903,44 @@ export type CreateFavoriteResponse = { id: string };
|
||||
export type CreateFavoriteQuery = { comment?: string; name: string; public?: boolean };
|
||||
|
||||
export type CreateFavoriteArgs = { query: CreateFavoriteQuery } & BaseEndpointArgs;
|
||||
|
||||
// User list
|
||||
// Playlist List
|
||||
export type RawUserListResponse = NDUserList | undefined;
|
||||
|
||||
export type UserListResponse = BasePaginatedResponse<User[]>;
|
||||
|
||||
export enum UserListSort {
|
||||
NAME = 'name',
|
||||
}
|
||||
|
||||
export type UserListQuery = {
|
||||
limit?: number;
|
||||
ndParams?: {
|
||||
owner_id?: string;
|
||||
};
|
||||
searchTerm?: string;
|
||||
sortBy: UserListSort;
|
||||
sortOrder: SortOrder;
|
||||
startIndex: number;
|
||||
};
|
||||
|
||||
export type UserListArgs = { query: UserListQuery } & BaseEndpointArgs;
|
||||
|
||||
type UserListSortMap = {
|
||||
jellyfin: Record<UserListSort, undefined>;
|
||||
navidrome: Record<UserListSort, NDUserListSort | undefined>;
|
||||
subsonic: Record<UserListSort, undefined>;
|
||||
};
|
||||
|
||||
export const userListSortMap: UserListSortMap = {
|
||||
jellyfin: {
|
||||
name: undefined,
|
||||
},
|
||||
navidrome: {
|
||||
name: NDUserListSort.NAME,
|
||||
},
|
||||
subsonic: {
|
||||
name: undefined,
|
||||
},
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Group, Stack } from '@mantine/core';
|
||||
import { useForm } from '@mantine/form';
|
||||
import { CreatePlaylistQuery, ServerType } from '/@/renderer/api/types';
|
||||
import { CreatePlaylistBody, ServerType } from '/@/renderer/api/types';
|
||||
import { Button, Switch, TextInput, toast } from '/@/renderer/components';
|
||||
import { useCreatePlaylist } from '/@/renderer/features/playlists/mutations/create-playlist-mutation';
|
||||
import { useCurrentServer } from '/@/renderer/store';
|
||||
@ -13,18 +13,20 @@ export const CreatePlaylistForm = ({ onCancel }: CreatePlaylistFormProps) => {
|
||||
const mutation = useCreatePlaylist();
|
||||
const server = useCurrentServer();
|
||||
|
||||
const form = useForm<CreatePlaylistQuery>({
|
||||
const form = useForm<CreatePlaylistBody>({
|
||||
initialValues: {
|
||||
comment: '',
|
||||
name: '',
|
||||
public: false,
|
||||
rules: undefined,
|
||||
ndParams: {
|
||||
public: false,
|
||||
rules: undefined,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const handleSubmit = form.onSubmit((values) => {
|
||||
mutation.mutate(
|
||||
{ query: values },
|
||||
{ body: values },
|
||||
{
|
||||
onError: (err) => {
|
||||
toast.error({ message: err.message, title: 'Error creating playlist' });
|
||||
@ -56,7 +58,7 @@ export const CreatePlaylistForm = ({ onCancel }: CreatePlaylistFormProps) => {
|
||||
{isPublicDisplayed && (
|
||||
<Switch
|
||||
label="Is Public?"
|
||||
{...form.getInputProps('public')}
|
||||
{...form.getInputProps('ndParams.public')}
|
||||
/>
|
||||
)}
|
||||
<Group position="right">
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { forwardRef, Fragment, Ref } from 'react';
|
||||
import { Group, Stack } from '@mantine/core';
|
||||
import { closeAllModals, openModal } from '@mantine/modals';
|
||||
import { forwardRef, Fragment, Ref } from 'react';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { RiMoreFill } from 'react-icons/ri';
|
||||
import { generatePath, useNavigate, useParams } from 'react-router';
|
||||
import { Link } from 'react-router-dom';
|
||||
@ -14,6 +15,10 @@ import { AppRoute } from '/@/renderer/router/routes';
|
||||
import { usePlayButtonBehavior } from '/@/renderer/store/settings.store';
|
||||
import { LibraryItem, Play } from '/@/renderer/types';
|
||||
import { formatDurationString } from '/@/renderer/utils';
|
||||
import { UserListSort, SortOrder, UserListQuery } from '/@/renderer/api/types';
|
||||
import { useCurrentServer } from '/@/renderer/store';
|
||||
import { api } from '/@/renderer/api';
|
||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||
|
||||
interface PlaylistDetailHeaderProps {
|
||||
background: string;
|
||||
@ -27,10 +32,12 @@ export const PlaylistDetailHeader = forwardRef(
|
||||
ref: Ref<HTMLDivElement>,
|
||||
) => {
|
||||
const navigate = useNavigate();
|
||||
const queryClient = useQueryClient();
|
||||
const { playlistId } = useParams() as { playlistId: string };
|
||||
const detailQuery = usePlaylistDetail({ id: playlistId });
|
||||
const handlePlayQueueAdd = usePlayQueueAdd();
|
||||
const playButtonBehavior = usePlayButtonBehavior();
|
||||
const server = useCurrentServer();
|
||||
|
||||
const handlePlay = (playType?: Play) => {
|
||||
handlePlayQueueAdd?.({
|
||||
@ -42,7 +49,20 @@ export const PlaylistDetailHeader = forwardRef(
|
||||
});
|
||||
};
|
||||
|
||||
const openUpdatePlaylistModal = () => {
|
||||
const openUpdatePlaylistModal = async () => {
|
||||
const query: UserListQuery = {
|
||||
sortBy: UserListSort.NAME,
|
||||
sortOrder: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
};
|
||||
|
||||
const users = await queryClient.fetchQuery({
|
||||
queryFn: ({ signal }) => api.controller.getUserList({ query, server, signal }),
|
||||
queryKey: queryKeys.users.list(server?.id || '', query),
|
||||
});
|
||||
|
||||
const normalizedUsers = api.normalize.userList(users, server);
|
||||
|
||||
openModal({
|
||||
children: (
|
||||
<UpdatePlaylistForm
|
||||
@ -50,10 +70,16 @@ export const PlaylistDetailHeader = forwardRef(
|
||||
comment: detailQuery?.data?.description || undefined,
|
||||
genres: detailQuery?.data?.genres,
|
||||
name: detailQuery?.data?.name,
|
||||
public: detailQuery?.data?.public || false,
|
||||
rules: detailQuery?.data?.rules || undefined,
|
||||
ndParams: {
|
||||
owner: detailQuery?.data?.owner || undefined,
|
||||
ownerId: detailQuery?.data?.ownerId || undefined,
|
||||
public: detailQuery?.data?.public || false,
|
||||
rules: detailQuery?.data?.rules || undefined,
|
||||
sync: detailQuery?.data?.sync || undefined,
|
||||
},
|
||||
}}
|
||||
query={{ id: playlistId }}
|
||||
users={normalizedUsers.items}
|
||||
onCancel={closeAllModals}
|
||||
/>
|
||||
),
|
||||
|
@ -1,27 +1,37 @@
|
||||
import { Group, Stack } from '@mantine/core';
|
||||
import { useForm } from '@mantine/form';
|
||||
import { ServerType, UpdatePlaylistBody, UpdatePlaylistQuery } from '/@/renderer/api/types';
|
||||
import { Button, Switch, TextInput, toast } from '/@/renderer/components';
|
||||
import { ServerType, UpdatePlaylistBody, UpdatePlaylistQuery, User } from '/@/renderer/api/types';
|
||||
import { Button, Select, Switch, TextInput, toast } from '/@/renderer/components';
|
||||
import { useUpdatePlaylist } from '/@/renderer/features/playlists/mutations/update-playlist-mutation';
|
||||
import { useCurrentServer } from '/@/renderer/store';
|
||||
|
||||
interface CreatePlaylistFormProps {
|
||||
interface UpdatePlaylistFormProps {
|
||||
body: Partial<UpdatePlaylistBody>;
|
||||
onCancel: () => void;
|
||||
query: UpdatePlaylistQuery;
|
||||
users?: User[];
|
||||
}
|
||||
|
||||
export const UpdatePlaylistForm = ({ query, body, onCancel }: CreatePlaylistFormProps) => {
|
||||
export const UpdatePlaylistForm = ({ users, query, body, onCancel }: UpdatePlaylistFormProps) => {
|
||||
const mutation = useUpdatePlaylist();
|
||||
const server = useCurrentServer();
|
||||
|
||||
const userList = users?.map((user) => ({
|
||||
label: user.name,
|
||||
value: user.id,
|
||||
}));
|
||||
|
||||
const form = useForm<UpdatePlaylistBody>({
|
||||
initialValues: {
|
||||
comment: '',
|
||||
name: '',
|
||||
public: false,
|
||||
rules: undefined,
|
||||
...body,
|
||||
comment: body?.comment || '',
|
||||
name: body?.name || '',
|
||||
ndParams: {
|
||||
owner: body?.ndParams?.owner || '',
|
||||
ownerId: body?.ndParams?.ownerId || '',
|
||||
public: body?.ndParams?.public || false,
|
||||
rules: undefined,
|
||||
sync: body?.ndParams?.sync || false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -56,6 +66,11 @@ export const UpdatePlaylistForm = ({ query, body, onCancel }: CreatePlaylistForm
|
||||
label="Description"
|
||||
{...form.getInputProps('comment')}
|
||||
/>
|
||||
<Select
|
||||
data={userList || []}
|
||||
{...form.getInputProps('ndParams.ownerId')}
|
||||
label="Owner"
|
||||
/>
|
||||
{isPublicDisplayed && (
|
||||
<Switch
|
||||
label="Is Public?"
|
||||
|
1
src/renderer/features/users/index.ts
Normal file
1
src/renderer/features/users/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './queries/user-list-query';
|
22
src/renderer/features/users/queries/user-list-query.ts
Normal file
22
src/renderer/features/users/queries/user-list-query.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useCallback } from 'react';
|
||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||
import type { RawUserListResponse, UserListQuery } from '/@/renderer/api/types';
|
||||
import { useCurrentServer } from '/@/renderer/store';
|
||||
import { api } from '/@/renderer/api';
|
||||
import type { QueryOptions } from '/@/renderer/lib/react-query';
|
||||
|
||||
export const useUserList = (query: UserListQuery, options?: QueryOptions) => {
|
||||
const server = useCurrentServer();
|
||||
|
||||
return useQuery({
|
||||
enabled: !!server?.id,
|
||||
queryFn: ({ signal }) => api.controller.getUserList({ query, server, signal }),
|
||||
queryKey: queryKeys.users.list(server?.id || '', query),
|
||||
select: useCallback(
|
||||
(data: RawUserListResponse | undefined) => api.normalize.userList(data, server),
|
||||
[server],
|
||||
),
|
||||
...options,
|
||||
});
|
||||
};
|
@ -111,22 +111,17 @@ export interface UniqueId {
|
||||
uniqueId: string;
|
||||
}
|
||||
|
||||
export enum FilterGroupType {
|
||||
AND = 'AND',
|
||||
OR = 'OR',
|
||||
}
|
||||
|
||||
export type AdvancedFilterRule = {
|
||||
export type QueryBuilderRule = {
|
||||
field?: string | null;
|
||||
operator?: string | null;
|
||||
uniqueId: string;
|
||||
value?: string | number | Date | undefined | null | any;
|
||||
};
|
||||
|
||||
export type AdvancedFilterGroup = {
|
||||
group: AdvancedFilterGroup[];
|
||||
rules: AdvancedFilterRule[];
|
||||
type: FilterGroupType;
|
||||
export type QueryBuilderGroup = {
|
||||
group: QueryBuilderGroup[];
|
||||
rules: QueryBuilderRule[];
|
||||
type: 'any' | 'all';
|
||||
uniqueId: string;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user