Files
stash/ui/v2.5/src/utils/bulkUpdate.ts
WithoutPants bcf0fda7ac 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
2024-08-30 11:43:44 +10:00

187 lines
4.1 KiB
TypeScript

import * as GQL from "src/core/generated-graphql";
import isEqual from "lodash-es/isEqual";
import { IHasID } from "./data";
interface IHasRating {
rating100?: GQL.Maybe<number> | undefined;
}
export function getAggregateRating(state: IHasRating[]) {
let ret: number | undefined;
let first = true;
state.forEach((o) => {
if (first) {
ret = o.rating100 ?? undefined;
first = false;
} else if (ret !== o.rating100) {
ret = undefined;
}
});
return ret;
}
interface IHasStudio {
studio?: GQL.Maybe<IHasID> | undefined;
}
export function getAggregateStudioId(state: IHasStudio[]) {
let ret: string | undefined;
let first = true;
state.forEach((o) => {
if (first) {
ret = o?.studio?.id;
first = false;
} else {
const studio = o?.studio?.id;
if (ret !== studio) {
ret = undefined;
}
}
});
return ret;
}
export function getAggregateIds<T>(
sortedLists: T[][],
isEqualFn: (a: T[], b: T[]) => boolean = isEqual
) {
let ret: T[] = [];
let first = true;
sortedLists.forEach((l) => {
if (first) {
ret = l;
first = false;
} else {
if (!isEqualFn(ret, l)) {
ret = [];
}
}
});
return ret;
}
export function getAggregateGalleryIds(state: { galleries: IHasID[] }[]) {
const sortedLists = state.map((o) => o.galleries.map((oo) => oo.id).sort());
return getAggregateIds(sortedLists);
}
export function getAggregatePerformerIds(state: { performers: IHasID[] }[]) {
const sortedLists = state.map((o) => o.performers.map((oo) => oo.id).sort());
return getAggregateIds(sortedLists);
}
export function getAggregateTagIds(state: { tags: IHasID[] }[]) {
const sortedLists = state.map((o) => o.tags.map((oo) => oo.id).sort());
return getAggregateIds(sortedLists);
}
interface IGroup {
group: IHasID;
}
export function getAggregateGroupIds(state: { groups: IGroup[] }[]) {
const sortedLists = state.map((o) =>
o.groups.map((oo) => oo.group.id).sort()
);
return getAggregateIds(sortedLists);
}
export function makeBulkUpdateIds(
ids: string[],
mode: GQL.BulkUpdateIdMode
): GQL.BulkUpdateIds {
return {
mode,
ids,
};
}
export function getAggregateInputValue<V>(
inputValue: V | null | undefined,
aggregateValue: V | null | undefined
) {
if (inputValue === undefined) {
// and all objects have the same value, then we are unsetting the value.
if (aggregateValue !== undefined) {
// null to unset rating
return null;
}
// otherwise not setting the rating
return undefined;
} else {
// if value is set, then we are setting the value for all
return inputValue;
}
}
// TODO - remove - this is incorrect
export function getAggregateInputIDs(
mode: GQL.BulkUpdateIdMode,
inputIds: string[] | undefined,
aggregateIds: string[]
) {
if (
mode === GQL.BulkUpdateIdMode.Set &&
(!inputIds || inputIds.length === 0)
) {
// and all scenes have the same ids,
if (aggregateIds.length > 0) {
// then unset the performerIds, otherwise ignore
return makeBulkUpdateIds(inputIds || [], mode);
}
} else {
// if performerIds non-empty, then we are setting them
return makeBulkUpdateIds(inputIds || [], mode);
}
return undefined;
}
export function getAggregateState<T, U>(
currentValue: T,
newValue: U,
first: boolean
) {
if (!first && !isEqual(currentValue, newValue)) {
return undefined;
}
return newValue;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function setProperty<T, K extends keyof T>(obj: T, key: K, value: any) {
obj[key] = value;
}
function getProperty<T, K extends keyof T>(obj: T, key: K) {
return obj[key];
}
export function getAggregateStateObject<O, I>(
output: O,
input: I,
fields: string[],
first: boolean
) {
fields.forEach((key) => {
const outputKey = key as keyof O;
const inputKey = key as keyof I;
const currentValue = getProperty(output, outputKey);
const performerValue = getProperty(input, inputKey);
setProperty(
output,
outputKey,
getAggregateState(currentValue, performerValue, first)
);
});
}