mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 04:44:37 +03:00
Containing Group/Sub-Group relationships (#5105)
* Add UI support for setting containing groups * Show containing groups in group details panel * Move tag hierarchical filter code into separate type * Add depth to scene_count and add sub_group_count * Add sub-groups tab to groups page * Add containing groups to edit groups dialog * Show containing group description in sub-group view * Show group scene number in group scenes view * Add ability to drag move grid cards * Add sub group order option * Add reorder sub-groups interface * Separate page size selector component * Add interfaces to add and remove sub-groups to a group * Separate MultiSet components * Allow setting description while setting containing groups
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { PropsWithChildren, useState } from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
import cloneDeep from "lodash-es/cloneDeep";
|
||||
import Mousetrap from "mousetrap";
|
||||
@@ -17,6 +17,35 @@ import { DeleteEntityDialog } from "../Shared/DeleteEntityDialog";
|
||||
import { GroupCardGrid } from "./GroupCardGrid";
|
||||
import { EditGroupsDialog } from "./EditGroupsDialog";
|
||||
import { View } from "../List/views";
|
||||
import {
|
||||
IFilteredListToolbar,
|
||||
IItemListOperation,
|
||||
} from "../List/FilteredListToolbar";
|
||||
|
||||
const GroupExportDialog: React.FC<{
|
||||
open?: boolean;
|
||||
selectedIds: Set<string>;
|
||||
isExportAll?: boolean;
|
||||
onClose: () => void;
|
||||
}> = ({ open = false, selectedIds, isExportAll = false, onClose }) => {
|
||||
if (!open) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<ExportDialog
|
||||
exportInput={{
|
||||
groups: {
|
||||
ids: Array.from(selectedIds.values()),
|
||||
all: isExportAll,
|
||||
},
|
||||
}}
|
||||
onClose={onClose}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const filterMode = GQL.FilterMode.Groups;
|
||||
|
||||
function getItems(result: GQL.FindGroupsQueryResult) {
|
||||
return result?.data?.findGroups?.groups ?? [];
|
||||
@@ -26,24 +55,57 @@ function getCount(result: GQL.FindGroupsQueryResult) {
|
||||
return result?.data?.findGroups?.count ?? 0;
|
||||
}
|
||||
|
||||
interface IGroupList {
|
||||
interface IGroupListContext {
|
||||
filterHook?: (filter: ListFilterModel) => ListFilterModel;
|
||||
defaultFilter?: ListFilterModel;
|
||||
view?: View;
|
||||
alterQuery?: boolean;
|
||||
selectable?: boolean;
|
||||
}
|
||||
|
||||
export const GroupListContext: React.FC<
|
||||
PropsWithChildren<IGroupListContext>
|
||||
> = ({ alterQuery, filterHook, defaultFilter, view, selectable, children }) => {
|
||||
return (
|
||||
<ItemListContext
|
||||
filterMode={filterMode}
|
||||
defaultFilter={defaultFilter}
|
||||
useResult={useFindGroups}
|
||||
getItems={getItems}
|
||||
getCount={getCount}
|
||||
alterQuery={alterQuery}
|
||||
filterHook={filterHook}
|
||||
view={view}
|
||||
selectable={selectable}
|
||||
>
|
||||
{children}
|
||||
</ItemListContext>
|
||||
);
|
||||
};
|
||||
|
||||
interface IGroupList extends IGroupListContext {
|
||||
fromGroupId?: string;
|
||||
onMove?: (srcIds: string[], targetId: string, after: boolean) => void;
|
||||
renderToolbar?: (props: IFilteredListToolbar) => React.ReactNode;
|
||||
otherOperations?: IItemListOperation<GQL.FindGroupsQueryResult>[];
|
||||
}
|
||||
|
||||
export const GroupList: React.FC<IGroupList> = ({
|
||||
filterHook,
|
||||
alterQuery,
|
||||
defaultFilter,
|
||||
view,
|
||||
fromGroupId,
|
||||
onMove,
|
||||
selectable,
|
||||
renderToolbar,
|
||||
otherOperations: providedOperations = [],
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const history = useHistory();
|
||||
const [isExportDialogOpen, setIsExportDialogOpen] = useState(false);
|
||||
const [isExportAll, setIsExportAll] = useState(false);
|
||||
|
||||
const filterMode = GQL.FilterMode.Groups;
|
||||
|
||||
const otherOperations = [
|
||||
{
|
||||
text: intl.formatMessage({ id: "actions.view_random" }),
|
||||
@@ -58,6 +120,7 @@ export const GroupList: React.FC<IGroupList> = ({
|
||||
text: intl.formatMessage({ id: "actions.export_all" }),
|
||||
onClick: onExportAll,
|
||||
},
|
||||
...providedOperations,
|
||||
];
|
||||
|
||||
function addKeybinds(
|
||||
@@ -110,42 +173,23 @@ export const GroupList: React.FC<IGroupList> = ({
|
||||
selectedIds: Set<string>,
|
||||
onSelectChange: (id: string, selected: boolean, shiftKey: boolean) => void
|
||||
) {
|
||||
function maybeRenderGroupExportDialog() {
|
||||
if (isExportDialogOpen) {
|
||||
return (
|
||||
<ExportDialog
|
||||
exportInput={{
|
||||
groups: {
|
||||
ids: Array.from(selectedIds.values()),
|
||||
all: isExportAll,
|
||||
},
|
||||
}}
|
||||
onClose={() => setIsExportDialogOpen(false)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function renderGroups() {
|
||||
if (!result.data?.findGroups) return;
|
||||
|
||||
if (filter.displayMode === DisplayMode.Grid) {
|
||||
return (
|
||||
<GroupCardGrid
|
||||
groups={result.data.findGroups.groups}
|
||||
selectedIds={selectedIds}
|
||||
onSelectChange={onSelectChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
if (filter.displayMode === DisplayMode.List) {
|
||||
return <h1>TODO</h1>;
|
||||
}
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{maybeRenderGroupExportDialog()}
|
||||
{renderGroups()}
|
||||
<GroupExportDialog
|
||||
open={isExportDialogOpen}
|
||||
selectedIds={selectedIds}
|
||||
isExportAll={isExportAll}
|
||||
onClose={() => setIsExportDialogOpen(false)}
|
||||
/>
|
||||
{filter.displayMode === DisplayMode.Grid && (
|
||||
<GroupCardGrid
|
||||
groups={result.data?.findGroups.groups ?? []}
|
||||
selectedIds={selectedIds}
|
||||
onSelectChange={onSelectChange}
|
||||
fromGroupId={fromGroupId}
|
||||
onMove={onMove}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -173,15 +217,12 @@ export const GroupList: React.FC<IGroupList> = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<ItemListContext
|
||||
filterMode={filterMode}
|
||||
useResult={useFindGroups}
|
||||
getItems={getItems}
|
||||
getCount={getCount}
|
||||
<GroupListContext
|
||||
alterQuery={alterQuery}
|
||||
filterHook={filterHook}
|
||||
view={view}
|
||||
selectable
|
||||
defaultFilter={defaultFilter}
|
||||
selectable={selectable}
|
||||
>
|
||||
<ItemList
|
||||
view={view}
|
||||
@@ -190,7 +231,8 @@ export const GroupList: React.FC<IGroupList> = ({
|
||||
renderContent={renderContent}
|
||||
renderEditDialog={renderEditDialog}
|
||||
renderDeleteDialog={renderDeleteDialog}
|
||||
renderToolbar={renderToolbar}
|
||||
/>
|
||||
</ItemListContext>
|
||||
</GroupListContext>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user