mirror of https://github.com/stashapp/stash.git
Improve client-side graphql scalar types (#4511)
* Add types to graphql scalars * Upgrade dependencies * Override UI config type * Remove all IUIConfig casts * Add tableColumns to IUIConfig * Add BoolMap type, set strictScalars * Add PluginConfigMap * Replace any with unknown * Add SavedObjectFilter and SavedUIOptions * Remove unused items from CriterionType
This commit is contained in:
parent
9ac6505241
commit
2d73912f15
|
@ -17,7 +17,7 @@
|
|||
|
||||
# GraphQL generated output
|
||||
pkg/models/generated_*.go
|
||||
ui/v2.5/src/core/generated-*.tsx
|
||||
ui/v2.5/src/core/generated-graphql.ts
|
||||
|
||||
####
|
||||
# Jetbrains
|
||||
|
|
|
@ -36,6 +36,8 @@ models:
|
|||
model: github.com/stashapp/stash/internal/api.Timestamp
|
||||
BoolMap:
|
||||
model: github.com/stashapp/stash/internal/api.BoolMap
|
||||
PluginConfigMap:
|
||||
model: github.com/stashapp/stash/internal/api.PluginConfigMap
|
||||
# define to force resolvers
|
||||
Image:
|
||||
model: github.com/stashapp/stash/pkg/models.Image
|
||||
|
|
|
@ -535,7 +535,7 @@ type ConfigResult {
|
|||
scraping: ConfigScrapingResult!
|
||||
defaults: ConfigDefaultSettingsResult!
|
||||
ui: Map!
|
||||
plugins(include: [String!]): Map!
|
||||
plugins(include: [ID!]): PluginConfigMap!
|
||||
}
|
||||
|
||||
"Directory structure of a path"
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
"Log entries"
|
||||
scalar Time
|
||||
|
||||
enum LogLevel {
|
||||
Trace
|
||||
Debug
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
scalar Upload
|
||||
|
||||
input GenerateMetadataInput {
|
||||
covers: Boolean
|
||||
sprites: Boolean
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
"An RFC3339 timestamp"
|
||||
scalar Time
|
||||
|
||||
"""
|
||||
Timestamp is a point in time. It is always output as RFC3339-compatible time points.
|
||||
It can be input as a RFC3339 string, or as "<4h" for "4 hours in the past" or ">5m"
|
||||
|
@ -5,12 +8,18 @@ for "5 minutes in the future"
|
|||
"""
|
||||
scalar Timestamp
|
||||
|
||||
# generic JSON object
|
||||
"A String -> Any map"
|
||||
scalar Map
|
||||
|
||||
# string, boolean map
|
||||
"A String -> Boolean map"
|
||||
scalar BoolMap
|
||||
|
||||
"A plugin ID -> Map (String -> Any map) map"
|
||||
scalar PluginConfigMap
|
||||
|
||||
scalar Any
|
||||
|
||||
scalar Int64
|
||||
|
||||
"A multipart file upload"
|
||||
scalar Upload
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
)
|
||||
|
||||
func MarshalPluginConfigMap(val map[string]map[string]interface{}) graphql.Marshaler {
|
||||
return graphql.WriterFunc(func(w io.Writer) {
|
||||
err := json.NewEncoder(w).Encode(val)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func UnmarshalPluginConfigMap(v interface{}) (map[string]map[string]interface{}, error) {
|
||||
m, ok := v.(map[string]interface{})
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%T is not a plugin config map", v)
|
||||
}
|
||||
|
||||
result := make(map[string]map[string]interface{})
|
||||
for k, v := range m {
|
||||
val, ok := v.(map[string]interface{})
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("key %s (%T) is not a map", k, v)
|
||||
}
|
||||
|
||||
result[k] = val
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
|
@ -6,13 +6,13 @@ import (
|
|||
"github.com/stashapp/stash/internal/manager/config"
|
||||
)
|
||||
|
||||
func (r *configResultResolver) Plugins(ctx context.Context, obj *ConfigResult, include []string) (map[string]interface{}, error) {
|
||||
func (r *configResultResolver) Plugins(ctx context.Context, obj *ConfigResult, include []string) (map[string]map[string]interface{}, error) {
|
||||
if len(include) == 0 {
|
||||
ret := config.GetInstance().GetAllPluginConfiguration()
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
ret := make(map[string]interface{})
|
||||
ret := make(map[string]map[string]interface{})
|
||||
|
||||
for _, plugin := range include {
|
||||
c := config.GetInstance().GetPluginConfiguration(plugin)
|
||||
|
|
|
@ -735,11 +735,11 @@ func (i *Config) GetPluginsPath() string {
|
|||
return i.getString(PluginsPath)
|
||||
}
|
||||
|
||||
func (i *Config) GetAllPluginConfiguration() map[string]interface{} {
|
||||
func (i *Config) GetAllPluginConfiguration() map[string]map[string]interface{} {
|
||||
i.RLock()
|
||||
defer i.RUnlock()
|
||||
|
||||
ret := make(map[string]interface{})
|
||||
ret := make(map[string]map[string]interface{})
|
||||
|
||||
sub := i.viper(PluginsSetting).GetStringMap(PluginsSetting)
|
||||
if sub == nil {
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
"version": "detect"
|
||||
}
|
||||
},
|
||||
"ignorePatterns": ["node_modules/", "src/core/generated-graphql.tsx"],
|
||||
"ignorePatterns": ["node_modules/", "src/core/generated-graphql.ts"],
|
||||
"rules": {
|
||||
"@typescript-eslint/lines-between-class-members": "off",
|
||||
"@typescript-eslint/naming-convention": [
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# generated
|
||||
src/core/generated-*.tsx
|
||||
src/core/generated-graphql.ts
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
|
|
@ -15,4 +15,4 @@ src/locales/**/*.json
|
|||
/build
|
||||
|
||||
# generated
|
||||
src/core/generated-graphql.tsx
|
||||
src/core/generated-graphql.ts
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
import type { CodegenConfig } from "@graphql-codegen/cli";
|
||||
|
||||
const config: CodegenConfig = {
|
||||
schema: [
|
||||
"../../graphql/schema/**/*.graphql",
|
||||
"graphql/client-schema.graphql",
|
||||
],
|
||||
config: {
|
||||
// makes conflicting fields override rather than error
|
||||
onFieldTypeConflict: (_existing: unknown, other: unknown) => other,
|
||||
},
|
||||
documents: "graphql/**/*.graphql",
|
||||
generates: {
|
||||
"src/core/generated-graphql.ts": {
|
||||
plugins: [
|
||||
"time",
|
||||
"typescript",
|
||||
"typescript-operations",
|
||||
"typescript-react-apollo",
|
||||
],
|
||||
config: {
|
||||
strictScalars: true,
|
||||
scalars: {
|
||||
Time: "string",
|
||||
Timestamp: "string",
|
||||
Map: "{ [key: string]: unknown }",
|
||||
BoolMap: "{ [key: string]: boolean }",
|
||||
PluginConfigMap: "{ [id: string]: { [key: string]: unknown } }",
|
||||
Any: "unknown",
|
||||
Int64: "number",
|
||||
Upload: "File",
|
||||
UIConfig: "src/core/config#IUIConfig",
|
||||
SavedObjectFilter: "src/models/list-filter/types#SavedObjectFilter",
|
||||
SavedUIOptions: "src/models/list-filter/types#SavedUIOptions",
|
||||
},
|
||||
withRefetchFn: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
|
@ -1,12 +0,0 @@
|
|||
overwrite: true
|
||||
schema: "../../graphql/schema/**/*.graphql"
|
||||
documents: "../../graphql/documents/**/*.graphql"
|
||||
generates:
|
||||
src/core/generated-graphql.tsx:
|
||||
plugins:
|
||||
- time
|
||||
- typescript
|
||||
- typescript-operations
|
||||
- typescript-react-apollo
|
||||
config:
|
||||
withRefetchFn: true
|
|
@ -0,0 +1,26 @@
|
|||
scalar UIConfig
|
||||
scalar SavedObjectFilter
|
||||
scalar SavedUIOptions
|
||||
|
||||
extend type ConfigResult {
|
||||
ui: UIConfig!
|
||||
}
|
||||
|
||||
extend type SavedFilter {
|
||||
object_filter: SavedObjectFilter
|
||||
ui_options: SavedUIOptions
|
||||
}
|
||||
|
||||
extend input SaveFilterInput {
|
||||
object_filter: SavedObjectFilter
|
||||
ui_options: SavedUIOptions
|
||||
}
|
||||
|
||||
extend input SetDefaultFilterInput {
|
||||
object_filter: SavedObjectFilter
|
||||
ui_options: SavedUIOptions
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
configureUI(input: UIConfig!): UIConfig!
|
||||
}
|
|
@ -36,7 +36,7 @@ mutation ConfigureDefaults($input: ConfigDefaultSettingsInput!) {
|
|||
}
|
||||
}
|
||||
|
||||
mutation ConfigureUI($input: Map!) {
|
||||
mutation ConfigureUI($input: UIConfig!) {
|
||||
configureUI(input: $input)
|
||||
}
|
||||
|
|
@ -14,12 +14,12 @@
|
|||
"check": "tsc --noEmit",
|
||||
"format": "prettier --write . ../../graphql",
|
||||
"format-check": "prettier --check . ../../graphql",
|
||||
"gqlgen": "gql-gen --config codegen.yml",
|
||||
"gqlgen": "gql-gen --config codegen.ts",
|
||||
"extract": "NODE_ENV=development extract-messages -l=en,de -o src/locale -d en --flat false 'src/**/!(*.test).tsx'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ant-design/react-slick": "^1.0.0",
|
||||
"@apollo/client": "^3.7.17",
|
||||
"@apollo/client": "^3.8.10",
|
||||
"@formatjs/intl-getcanonicallocales": "^2.0.5",
|
||||
"@formatjs/intl-locale": "^3.0.11",
|
||||
"@formatjs/intl-numberformat": "^8.3.3",
|
||||
|
@ -31,7 +31,7 @@
|
|||
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||
"@silvermine/videojs-airplay": "^1.2.0",
|
||||
"@silvermine/videojs-chromecast": "^1.4.1",
|
||||
"apollo-upload-client": "^17.0.0",
|
||||
"apollo-upload-client": "^18.0.1",
|
||||
"base64-blob": "^1.4.1",
|
||||
"bootstrap": "^4.6.2",
|
||||
"classnames": "^2.3.2",
|
||||
|
@ -40,7 +40,7 @@
|
|||
"formik": "^2.4.5",
|
||||
"graphql": "^16.8.1",
|
||||
"graphql-tag": "^2.12.6",
|
||||
"graphql-ws": "^5.11.3",
|
||||
"graphql-ws": "^5.14.3",
|
||||
"i18n-iso-countries": "^7.5.0",
|
||||
"intersection-observer": "^0.12.2",
|
||||
"localforage": "^1.10.0",
|
||||
|
@ -78,12 +78,12 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.20.12",
|
||||
"@graphql-codegen/cli": "^3.0.0",
|
||||
"@graphql-codegen/time": "^4.0.0",
|
||||
"@graphql-codegen/typescript": "^3.0.0",
|
||||
"@graphql-codegen/typescript-operations": "^3.0.0",
|
||||
"@graphql-codegen/typescript-react-apollo": "^3.3.7",
|
||||
"@types/apollo-upload-client": "^17.0.2",
|
||||
"@graphql-codegen/cli": "^5.0.0",
|
||||
"@graphql-codegen/time": "^5.0.0",
|
||||
"@graphql-codegen/typescript": "^4.0.1",
|
||||
"@graphql-codegen/typescript-operations": "^4.0.1",
|
||||
"@graphql-codegen/typescript-react-apollo": "^4.1.0",
|
||||
"@types/apollo-upload-client": "^18.0.0",
|
||||
"@types/lodash-es": "^4.17.6",
|
||||
"@types/mousetrap": "^1.6.11",
|
||||
"@types/node": "^18.13.0",
|
||||
|
|
|
@ -36,7 +36,6 @@ import { ConfigurationProvider } from "./hooks/Config";
|
|||
import { ManualProvider } from "./components/Help/context";
|
||||
import { InteractiveProvider } from "./hooks/Interactive/context";
|
||||
import { ReleaseNotesDialog } from "./components/Dialogs/ReleaseNotesDialog";
|
||||
import { IUIConfig } from "./core/config";
|
||||
import { releaseNotes } from "./docs/en/ReleaseNotes";
|
||||
import { getPlatformURL } from "./core/createClient";
|
||||
import { lazyComponent } from "./utils/lazyComponent";
|
||||
|
@ -324,8 +323,7 @@ export const App: React.FC = () => {
|
|||
return;
|
||||
}
|
||||
|
||||
const lastNoteSeen = (config.data?.configuration.ui as IUIConfig)
|
||||
?.lastNoteSeen;
|
||||
const lastNoteSeen = config.data?.configuration.ui.lastNoteSeen;
|
||||
const notes = releaseNotes.filter((n) => {
|
||||
return !lastNoteSeen || n.date > lastNoteSeen;
|
||||
});
|
||||
|
|
|
@ -11,7 +11,6 @@ import {
|
|||
FrontPageContent,
|
||||
generateDefaultFrontPageContent,
|
||||
getFrontPageContent,
|
||||
IUIConfig,
|
||||
} from "src/core/config";
|
||||
import { useScrollToTopOnMount } from "src/hooks/scrollToTop";
|
||||
|
||||
|
@ -59,7 +58,7 @@ const FrontPage: React.FC = () => {
|
|||
return <FrontPageConfig onClose={(content) => onUpdateConfig(content)} />;
|
||||
}
|
||||
|
||||
const ui = (configuration?.ui ?? {}) as IUIConfig;
|
||||
const ui = configuration?.ui ?? {};
|
||||
|
||||
if (!ui.frontPageContent) {
|
||||
const defaultContent = generateDefaultFrontPageContent(intl);
|
||||
|
|
|
@ -6,7 +6,6 @@ import { Button, Form, Modal } from "react-bootstrap";
|
|||
import * as GQL from "src/core/generated-graphql";
|
||||
import { ConfigurationContext } from "src/hooks/Config";
|
||||
import {
|
||||
IUIConfig,
|
||||
ISavedFilterRow,
|
||||
ICustomFilter,
|
||||
FrontPageContent,
|
||||
|
@ -283,7 +282,7 @@ export const FrontPageConfig: React.FC<IFrontPageConfigProps> = ({
|
|||
}) => {
|
||||
const { configuration, loading } = React.useContext(ConfigurationContext);
|
||||
|
||||
const ui = configuration?.ui as IUIConfig;
|
||||
const ui = configuration?.ui;
|
||||
|
||||
const { data: allFilters, loading: loading2 } = useFindSavedFilters();
|
||||
|
||||
|
|
|
@ -161,7 +161,7 @@ export const GalleryEditPanel: React.FC<IProps> = ({
|
|||
|
||||
useRatingKeybinds(
|
||||
isVisible,
|
||||
stashConfig?.ui?.ratingSystemOptions?.type,
|
||||
stashConfig?.ui.ratingSystemOptions?.type,
|
||||
setRating
|
||||
);
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ export const ImageEditPanel: React.FC<IProps> = ({
|
|||
|
||||
useRatingKeybinds(
|
||||
true,
|
||||
configuration?.ui?.ratingSystemOptions?.type,
|
||||
configuration?.ui.ratingSystemOptions?.type,
|
||||
setRating
|
||||
);
|
||||
|
||||
|
|
|
@ -32,7 +32,6 @@ import { ExportDialog } from "../Shared/ExportDialog";
|
|||
import { objectTitle } from "src/core/files";
|
||||
import TextUtils from "src/utils/text";
|
||||
import { ConfigurationContext } from "src/hooks/Config";
|
||||
import { IUIConfig } from "src/core/config";
|
||||
import { useContainerDimensions } from "../Shared/GridCard";
|
||||
|
||||
interface IImageWallProps {
|
||||
|
@ -45,7 +44,7 @@ interface IImageWallProps {
|
|||
|
||||
const ImageWall: React.FC<IImageWallProps> = ({ images, handleImageOpen }) => {
|
||||
const { configuration } = useContext(ConfigurationContext);
|
||||
const uiConfig = configuration?.ui as IUIConfig | undefined;
|
||||
const uiConfig = configuration?.ui;
|
||||
|
||||
let photos: {
|
||||
src: string;
|
||||
|
|
|
@ -31,7 +31,6 @@ import { useCompare, usePrevious } from "src/hooks/state";
|
|||
import { CriterionType } from "src/models/list-filter/types";
|
||||
import { useToast } from "src/hooks/Toast";
|
||||
import { useConfigureUI } from "src/core/StashService";
|
||||
import { IUIConfig } from "src/core/config";
|
||||
import { FilterMode } from "src/core/generated-graphql";
|
||||
import { useFocusOnce } from "src/utils/focus";
|
||||
import Mousetrap from "mousetrap";
|
||||
|
@ -270,7 +269,7 @@ export const EditFilterDialog: React.FC<IEditFilterProps> = ({
|
|||
[filter, criteria]
|
||||
);
|
||||
|
||||
const ui = (configuration?.ui ?? {}) as IUIConfig;
|
||||
const ui = configuration?.ui ?? {};
|
||||
const [saveUI] = useConfigureUI();
|
||||
|
||||
const filteredOptions = useMemo(() => {
|
||||
|
|
|
@ -67,8 +67,8 @@ export const SavedFilterList: React.FC<ISavedFilterListProps> = ({
|
|||
mode: filter.mode,
|
||||
name,
|
||||
find_filter: filterCopy.makeFindFilter(),
|
||||
object_filter: filterCopy.makeSavedFindFilter(),
|
||||
ui_options: filterCopy.makeUIOptions(),
|
||||
object_filter: filterCopy.makeSavedFilter(),
|
||||
ui_options: filterCopy.makeSavedUIOptions(),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -137,8 +137,8 @@ export const SavedFilterList: React.FC<ISavedFilterListProps> = ({
|
|||
input: {
|
||||
mode: filter.mode,
|
||||
find_filter: filterCopy.makeFindFilter(),
|
||||
object_filter: filterCopy.makeSavedFindFilter(),
|
||||
ui_options: filterCopy.makeUIOptions(),
|
||||
object_filter: filterCopy.makeSavedFilter(),
|
||||
ui_options: filterCopy.makeSavedUIOptions(),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -33,7 +33,6 @@ import TextUtils from "src/utils/text";
|
|||
import { Icon } from "src/components/Shared/Icon";
|
||||
import { RatingSystem } from "src/components/Shared/Rating/RatingSystem";
|
||||
import { ConfigurationContext } from "src/hooks/Config";
|
||||
import { IUIConfig } from "src/core/config";
|
||||
import { DetailImage } from "src/components/Shared/DetailImage";
|
||||
import { useRatingKeybinds } from "src/hooks/keybinds";
|
||||
import { useLoadStickyHeader } from "src/hooks/detailsPanel";
|
||||
|
@ -55,7 +54,7 @@ const MoviePage: React.FC<IProps> = ({ movie }) => {
|
|||
|
||||
// Configuration settings
|
||||
const { configuration } = React.useContext(ConfigurationContext);
|
||||
const uiConfig = configuration?.ui as IUIConfig | undefined;
|
||||
const uiConfig = configuration?.ui;
|
||||
const enableBackgroundImage = uiConfig?.enableMovieBackgroundImage ?? false;
|
||||
const compactExpandedDetails = uiConfig?.compactExpandedDetails ?? false;
|
||||
const showAllDetails = uiConfig?.showAllDetails ?? true;
|
||||
|
@ -130,7 +129,7 @@ const MoviePage: React.FC<IProps> = ({ movie }) => {
|
|||
|
||||
useRatingKeybinds(
|
||||
true,
|
||||
configuration?.ui?.ratingSystemOptions?.type,
|
||||
configuration?.ui.ratingSystemOptions?.type,
|
||||
setRating
|
||||
);
|
||||
|
||||
|
|
|
@ -40,7 +40,6 @@ import {
|
|||
faLink,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { faInstagram, faTwitter } from "@fortawesome/free-brands-svg-icons";
|
||||
import { IUIConfig } from "src/core/config";
|
||||
import { useRatingKeybinds } from "src/hooks/keybinds";
|
||||
import { DetailImage } from "src/components/Shared/DetailImage";
|
||||
import { useLoadStickyHeader } from "src/hooks/detailsPanel";
|
||||
|
@ -80,7 +79,7 @@ const PerformerPage: React.FC<IProps> = ({ performer, tabKey }) => {
|
|||
|
||||
// Configuration settings
|
||||
const { configuration } = React.useContext(ConfigurationContext);
|
||||
const uiConfig = configuration?.ui as IUIConfig | undefined;
|
||||
const uiConfig = configuration?.ui;
|
||||
const abbreviateCounter = uiConfig?.abbreviateCounters ?? false;
|
||||
const enableBackgroundImage =
|
||||
uiConfig?.enablePerformerBackgroundImage ?? false;
|
||||
|
@ -160,7 +159,7 @@ const PerformerPage: React.FC<IProps> = ({ performer, tabKey }) => {
|
|||
|
||||
useRatingKeybinds(
|
||||
true,
|
||||
configuration?.ui?.ratingSystemOptions?.type,
|
||||
configuration?.ui.ratingSystemOptions?.type,
|
||||
setRating
|
||||
);
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ import {
|
|||
} from "src/core/StashService";
|
||||
import { ConfigurationContext } from "src/hooks/Config";
|
||||
import { useIntl } from "react-intl";
|
||||
import { defaultMaxOptionsShown, IUIConfig } from "src/core/config";
|
||||
import { defaultMaxOptionsShown } from "src/core/config";
|
||||
import { ListFilterModel } from "src/models/list-filter/filter";
|
||||
import {
|
||||
FilterSelectComponent,
|
||||
|
@ -47,7 +47,7 @@ export const PerformerSelect: React.FC<
|
|||
const { configuration } = React.useContext(ConfigurationContext);
|
||||
const intl = useIntl();
|
||||
const maxOptionsShown =
|
||||
(configuration?.ui as IUIConfig).maxOptionsShown ?? defaultMaxOptionsShown;
|
||||
configuration?.ui.maxOptionsShown ?? defaultMaxOptionsShown;
|
||||
const defaultCreatable =
|
||||
!configuration?.interface.disableDropdownCreate.performer ?? true;
|
||||
|
||||
|
|
|
@ -38,7 +38,6 @@ import {
|
|||
import { SceneInteractiveStatus } from "src/hooks/Interactive/status";
|
||||
import { languageMap } from "src/utils/caption";
|
||||
import { VIDEO_PLAYER_ID } from "./util";
|
||||
import { IUIConfig } from "src/core/config";
|
||||
|
||||
// @ts-ignore
|
||||
import airplay from "@silvermine/videojs-airplay";
|
||||
|
@ -223,7 +222,7 @@ export const ScenePlayer: React.FC<IScenePlayerProps> = ({
|
|||
}) => {
|
||||
const { configuration } = useContext(ConfigurationContext);
|
||||
const interfaceConfig = configuration?.interface;
|
||||
const uiConfig = configuration?.ui as IUIConfig | undefined;
|
||||
const uiConfig = configuration?.ui;
|
||||
const videoRef = useRef<HTMLDivElement>(null);
|
||||
const [_player, setPlayer] = useState<VideoJsPlayer>();
|
||||
const sceneId = useRef<string>();
|
||||
|
|
|
@ -224,7 +224,7 @@ export const SceneEditPanel: React.FC<IProps> = ({
|
|||
|
||||
useRatingKeybinds(
|
||||
isVisible,
|
||||
stashConfig?.ui?.ratingSystemOptions?.type,
|
||||
stashConfig?.ui.ratingSystemOptions?.type,
|
||||
setRating
|
||||
);
|
||||
|
||||
|
|
|
@ -137,7 +137,7 @@ export const SettingsServicesPanel: React.FC = () => {
|
|||
}
|
||||
}
|
||||
|
||||
function renderDeadline(until?: string) {
|
||||
function renderDeadline(until?: string | null) {
|
||||
if (until) {
|
||||
const deadline = new Date(until);
|
||||
return `until ${intl.formatDate(deadline)}`;
|
||||
|
|
|
@ -95,6 +95,8 @@ export const ImportDialog: React.FC<IImportDialogProps> = (
|
|||
}
|
||||
|
||||
async function onImport() {
|
||||
if (!file) return;
|
||||
|
||||
try {
|
||||
setIsRunning(true);
|
||||
await mutateImportObjects({
|
||||
|
|
|
@ -22,7 +22,8 @@ import { useToast } from "src/hooks/Toast";
|
|||
import { withoutTypename } from "src/utils/data";
|
||||
import { Icon } from "../Shared/Icon";
|
||||
|
||||
type PluginSettings = Record<string, Record<string, unknown>>;
|
||||
type PluginConfigs = Record<string, Record<string, unknown>>;
|
||||
|
||||
export interface ISettingsContextState {
|
||||
loading: boolean;
|
||||
error: ApolloError | undefined;
|
||||
|
@ -32,7 +33,7 @@ export interface ISettingsContextState {
|
|||
scraping: GQL.ConfigScrapingInput;
|
||||
dlna: GQL.ConfigDlnaInput;
|
||||
ui: IUIConfig;
|
||||
plugins: PluginSettings;
|
||||
plugins: PluginConfigs;
|
||||
|
||||
advancedMode: boolean;
|
||||
|
||||
|
@ -137,8 +138,8 @@ export const SettingsContext: React.FC = ({ children }) => {
|
|||
const [pendingUI, setPendingUI] = useState<{}>();
|
||||
const [updateUIConfig] = useConfigureUI();
|
||||
|
||||
const [plugins, setPlugins] = useState<PluginSettings>({});
|
||||
const [pendingPlugins, setPendingPlugins] = useState<PluginSettings>();
|
||||
const [plugins, setPlugins] = useState<PluginConfigs>({});
|
||||
const [pendingPlugins, setPendingPlugins] = useState<PluginConfigs>();
|
||||
const [updatePluginConfig] = useConfigurePlugin();
|
||||
|
||||
const [updateSuccess, setUpdateSuccess] = useState<boolean>();
|
||||
|
@ -479,7 +480,7 @@ export const SettingsContext: React.FC = ({ children }) => {
|
|||
}
|
||||
|
||||
// saves the configuration if no further changes are made after a half second
|
||||
const savePluginConfig = useDebounce(async (input: PluginSettings) => {
|
||||
const savePluginConfig = useDebounce(async (input: PluginConfigs) => {
|
||||
try {
|
||||
setUpdateSuccess(undefined);
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ import React, { useMemo } from "react";
|
|||
import { Button, OverlayTrigger, Tooltip } from "react-bootstrap";
|
||||
import { FormattedNumber, useIntl } from "react-intl";
|
||||
import { Link } from "react-router-dom";
|
||||
import { IUIConfig } from "src/core/config";
|
||||
import { ConfigurationContext } from "src/hooks/Config";
|
||||
import TextUtils from "src/utils/text";
|
||||
import { Icon } from "./Icon";
|
||||
|
@ -37,8 +36,7 @@ export const PopoverCountButton: React.FC<IProps> = ({
|
|||
count,
|
||||
}) => {
|
||||
const { configuration } = React.useContext(ConfigurationContext);
|
||||
const abbreviateCounter =
|
||||
(configuration?.ui as IUIConfig)?.abbreviateCounters ?? false;
|
||||
const abbreviateCounter = configuration?.ui.abbreviateCounters ?? false;
|
||||
|
||||
const intl = useIntl();
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import React from "react";
|
||||
import { IUIConfig } from "src/core/config";
|
||||
import { ConfigurationContext } from "src/hooks/Config";
|
||||
import {
|
||||
defaultRatingStarPrecision,
|
||||
|
@ -21,8 +20,7 @@ export const RatingSystem: React.FC<IRatingSystemProps> = (
|
|||
) => {
|
||||
const { configuration: config } = React.useContext(ConfigurationContext);
|
||||
const ratingSystemOptions =
|
||||
(config?.ui as IUIConfig)?.ratingSystemOptions ??
|
||||
defaultRatingSystemOptions;
|
||||
config?.ui.ratingSystemOptions ?? defaultRatingSystemOptions;
|
||||
|
||||
if (ratingSystemOptions.type === RatingSystemType.Stars) {
|
||||
return (
|
||||
|
|
|
@ -7,7 +7,6 @@ import {
|
|||
RatingSystemType,
|
||||
} from "src/utils/rating";
|
||||
import { ConfigurationContext } from "src/hooks/Config";
|
||||
import { IUIConfig } from "src/core/config";
|
||||
|
||||
interface IProps {
|
||||
rating?: number | null;
|
||||
|
@ -16,8 +15,7 @@ interface IProps {
|
|||
export const RatingBanner: React.FC<IProps> = ({ rating }) => {
|
||||
const { configuration: config } = useContext(ConfigurationContext);
|
||||
const ratingSystemOptions =
|
||||
(config?.ui as IUIConfig)?.ratingSystemOptions ??
|
||||
defaultRatingSystemOptions;
|
||||
config?.ui.ratingSystemOptions ?? defaultRatingSystemOptions;
|
||||
const isLegacy =
|
||||
ratingSystemOptions.type === RatingSystemType.Stars &&
|
||||
ratingSystemOptions.starPrecision === RatingStarPrecision.Full;
|
||||
|
|
|
@ -24,7 +24,7 @@ import { ConfigurationContext } from "src/hooks/Config";
|
|||
import { useIntl } from "react-intl";
|
||||
import { objectTitle } from "src/core/files";
|
||||
import { galleryTitle } from "src/core/galleries";
|
||||
import { defaultMaxOptionsShown, IUIConfig } from "src/core/config";
|
||||
import { defaultMaxOptionsShown } from "src/core/config";
|
||||
import { useDebounce } from "src/hooks/debounce";
|
||||
import { Placement } from "react-bootstrap/esm/Overlay";
|
||||
import { PerformerIDSelect } from "../Performers/PerformerSelect";
|
||||
|
@ -132,7 +132,7 @@ const LimitedSelectMenu = <T extends boolean>(
|
|||
) => {
|
||||
const { configuration } = React.useContext(ConfigurationContext);
|
||||
const maxOptionsShown =
|
||||
(configuration?.ui as IUIConfig).maxOptionsShown ?? defaultMaxOptionsShown;
|
||||
configuration?.ui.maxOptionsShown ?? defaultMaxOptionsShown;
|
||||
|
||||
const [hiddenCount, setHiddenCount] = useState<number>(0);
|
||||
const hiddenCountStyle = {
|
||||
|
|
|
@ -38,7 +38,6 @@ import {
|
|||
faChevronDown,
|
||||
faChevronUp,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { IUIConfig } from "src/core/config";
|
||||
import TextUtils from "src/utils/text";
|
||||
import { RatingSystem } from "src/components/Shared/Rating/RatingSystem";
|
||||
import { DetailImage } from "src/components/Shared/DetailImage";
|
||||
|
@ -81,7 +80,7 @@ const StudioPage: React.FC<IProps> = ({ studio, tabKey }) => {
|
|||
|
||||
// Configuration settings
|
||||
const { configuration } = React.useContext(ConfigurationContext);
|
||||
const uiConfig = configuration?.ui as IUIConfig | undefined;
|
||||
const uiConfig = configuration?.ui;
|
||||
const abbreviateCounter = uiConfig?.abbreviateCounters ?? false;
|
||||
const enableBackgroundImage = uiConfig?.enableStudioBackgroundImage ?? false;
|
||||
const showAllDetails = uiConfig?.showAllDetails ?? true;
|
||||
|
@ -101,8 +100,7 @@ const StudioPage: React.FC<IProps> = ({ studio, tabKey }) => {
|
|||
const [updateStudio] = useStudioUpdate();
|
||||
const [deleteStudio] = useStudioDestroy({ id: studio.id });
|
||||
|
||||
const showAllCounts = (configuration?.ui as IUIConfig)
|
||||
?.showChildStudioContent;
|
||||
const showAllCounts = uiConfig?.showChildStudioContent;
|
||||
const sceneCount =
|
||||
(showAllCounts ? studio.scene_count_all : studio.scene_count) ?? 0;
|
||||
const galleryCount =
|
||||
|
@ -161,7 +159,7 @@ const StudioPage: React.FC<IProps> = ({ studio, tabKey }) => {
|
|||
|
||||
useRatingKeybinds(
|
||||
true,
|
||||
configuration?.ui?.ratingSystemOptions?.type,
|
||||
configuration?.ui.ratingSystemOptions?.type,
|
||||
setRating
|
||||
);
|
||||
|
||||
|
|
|
@ -37,7 +37,6 @@ import {
|
|||
faSignOutAlt,
|
||||
faTrashAlt,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { IUIConfig } from "src/core/config";
|
||||
import { DetailImage } from "src/components/Shared/DetailImage";
|
||||
import { useLoadStickyHeader } from "src/hooks/detailsPanel";
|
||||
import { useScrollToTopOnMount } from "src/hooks/scrollToTop";
|
||||
|
@ -75,7 +74,7 @@ const TagPage: React.FC<IProps> = ({ tag, tabKey }) => {
|
|||
|
||||
// Configuration settings
|
||||
const { configuration } = React.useContext(ConfigurationContext);
|
||||
const uiConfig = configuration?.ui as IUIConfig | undefined;
|
||||
const uiConfig = configuration?.ui;
|
||||
const abbreviateCounter = uiConfig?.abbreviateCounters ?? false;
|
||||
const enableBackgroundImage = uiConfig?.enableTagBackgroundImage ?? false;
|
||||
const showAllDetails = uiConfig?.showAllDetails ?? true;
|
||||
|
@ -96,7 +95,7 @@ const TagPage: React.FC<IProps> = ({ tag, tabKey }) => {
|
|||
const [updateTag] = useTagUpdate();
|
||||
const [deleteTag] = useTagDestroy({ id: tag.id });
|
||||
|
||||
const showAllCounts = (configuration?.ui as IUIConfig)?.showChildTagContent;
|
||||
const showAllCounts = uiConfig?.showChildTagContent;
|
||||
const sceneCount =
|
||||
(showAllCounts ? tag.scene_count_all : tag.scene_count) ?? 0;
|
||||
const imageCount =
|
||||
|
|
|
@ -5,7 +5,6 @@ import { HoverPopover } from "../Shared/HoverPopover";
|
|||
import { useFindTag } from "../../core/StashService";
|
||||
import { TagCard } from "./TagCard";
|
||||
import { ConfigurationContext } from "../../hooks/Config";
|
||||
import { IUIConfig } from "src/core/config";
|
||||
import { Placement } from "react-bootstrap/esm/Overlay";
|
||||
|
||||
interface ITagPopoverCardProps {
|
||||
|
@ -50,8 +49,7 @@ export const TagPopover: React.FC<ITagPopoverProps> = ({
|
|||
}) => {
|
||||
const { configuration: config } = React.useContext(ConfigurationContext);
|
||||
|
||||
const showTagCardOnHover =
|
||||
(config?.ui as IUIConfig)?.showTagCardOnHover ?? true;
|
||||
const showTagCardOnHover = config?.ui.showTagCardOnHover ?? true;
|
||||
|
||||
if (hide || !showTagCardOnHover) {
|
||||
return <>{children}</>;
|
||||
|
|
|
@ -15,7 +15,7 @@ import {
|
|||
} from "src/core/StashService";
|
||||
import { ConfigurationContext } from "src/hooks/Config";
|
||||
import { useIntl } from "react-intl";
|
||||
import { defaultMaxOptionsShown, IUIConfig } from "src/core/config";
|
||||
import { defaultMaxOptionsShown } from "src/core/config";
|
||||
import { ListFilterModel } from "src/models/list-filter/filter";
|
||||
import {
|
||||
FilterSelectComponent,
|
||||
|
@ -49,7 +49,7 @@ export const TagSelect: React.FC<
|
|||
const { configuration } = React.useContext(ConfigurationContext);
|
||||
const intl = useIntl();
|
||||
const maxOptionsShown =
|
||||
(configuration?.ui as IUIConfig).maxOptionsShown ?? defaultMaxOptionsShown;
|
||||
configuration?.ui.maxOptionsShown ?? defaultMaxOptionsShown;
|
||||
const defaultCreatable =
|
||||
!configuration?.interface.disableDropdownCreate.tag ?? true;
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue