mirror of
https://github.com/stashapp/stash.git
synced 2026-05-01 19:30:55 +02:00
FR: Save & New Button on Objects (#6438)
This commit is contained in:
parent
b4969add27
commit
77d0008c6d
16 changed files with 209 additions and 66 deletions
|
|
@ -19,12 +19,14 @@ const GalleryCreate: React.FC = () => {
|
|||
|
||||
const [createGallery] = useGalleryCreate();
|
||||
|
||||
async function onSave(input: GQL.GalleryCreateInput) {
|
||||
async function onSave(input: GQL.GalleryCreateInput, andNew?: boolean) {
|
||||
const result = await createGallery({
|
||||
variables: { input },
|
||||
});
|
||||
if (result.data?.galleryCreate) {
|
||||
history.push(`/galleries/${result.data.galleryCreate.id}`);
|
||||
if (!andNew) {
|
||||
history.push(`/galleries/${result.data.galleryCreate.id}`);
|
||||
}
|
||||
Toast.success(
|
||||
intl.formatMessage(
|
||||
{ id: "toast.created_entity" },
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
import { Prompt } from "react-router-dom";
|
||||
import { Button, Form, Col, Row } from "react-bootstrap";
|
||||
import { Button, Dropdown, Form, Col, Row, SplitButton } from "react-bootstrap";
|
||||
import Mousetrap from "mousetrap";
|
||||
import * as GQL from "src/core/generated-graphql";
|
||||
import * as yup from "yup";
|
||||
|
|
@ -35,7 +35,7 @@ import { ScraperMenu } from "src/components/Shared/ScraperMenu";
|
|||
interface IProps {
|
||||
gallery: Partial<GQL.GalleryDataFragment>;
|
||||
isVisible: boolean;
|
||||
onSubmit: (input: GQL.GalleryCreateInput) => Promise<void>;
|
||||
onSubmit: (input: GQL.GalleryCreateInput, andNew?: boolean) => Promise<void>;
|
||||
onDelete: () => void;
|
||||
}
|
||||
|
||||
|
|
@ -177,10 +177,10 @@ export const GalleryEditPanel: React.FC<IProps> = ({
|
|||
return <div></div>;
|
||||
}, [gallery?.paths?.cover, intl]);
|
||||
|
||||
async function onSave(input: InputValues) {
|
||||
async function onSave(input: InputValues, andNew?: boolean) {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
await onSubmit(input);
|
||||
await onSubmit(input, andNew);
|
||||
formik.resetForm();
|
||||
} catch (e) {
|
||||
Toast.error(e);
|
||||
|
|
@ -188,6 +188,11 @@ export const GalleryEditPanel: React.FC<IProps> = ({
|
|||
setIsLoading(false);
|
||||
}
|
||||
|
||||
async function onSaveAndNewClick() {
|
||||
const input = schema.cast(formik.values);
|
||||
onSave(input, true);
|
||||
}
|
||||
|
||||
async function onScrapeClicked(s: GQL.ScraperSourceInput) {
|
||||
if (!gallery || !gallery.id) return;
|
||||
|
||||
|
|
@ -445,16 +450,31 @@ export const GalleryEditPanel: React.FC<IProps> = ({
|
|||
<Form noValidate onSubmit={formik.handleSubmit}>
|
||||
<Row className="form-container edit-buttons-container px-3 pt-3">
|
||||
<div className="edit-buttons mb-3 pl-0">
|
||||
<Button
|
||||
className="edit-button"
|
||||
variant="primary"
|
||||
disabled={
|
||||
(!isNew && !formik.dirty) || !isEqual(formik.errors, {})
|
||||
}
|
||||
onClick={() => formik.submitForm()}
|
||||
>
|
||||
<FormattedMessage id="actions.save" />
|
||||
</Button>
|
||||
{isNew ? (
|
||||
<SplitButton
|
||||
id="gallery-save-split-button"
|
||||
className="edit-button"
|
||||
variant="primary"
|
||||
disabled={!isEqual(formik.errors, {})}
|
||||
title={intl.formatMessage({ id: "actions.save" })}
|
||||
onClick={() => formik.submitForm()}
|
||||
>
|
||||
<Dropdown.Item onClick={() => onSaveAndNewClick()}>
|
||||
<FormattedMessage id="actions.save_and_new" />
|
||||
</Dropdown.Item>
|
||||
</SplitButton>
|
||||
) : (
|
||||
<Button
|
||||
className="edit-button"
|
||||
variant="primary"
|
||||
disabled={
|
||||
(!isNew && !formik.dirty) || !isEqual(formik.errors, {})
|
||||
}
|
||||
onClick={() => formik.submitForm()}
|
||||
>
|
||||
<FormattedMessage id="actions.save" />
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
className="edit-button"
|
||||
variant="danger"
|
||||
|
|
|
|||
|
|
@ -25,12 +25,14 @@ const GroupCreate: React.FC = () => {
|
|||
|
||||
const [createGroup] = useGroupCreate();
|
||||
|
||||
async function onSave(input: GQL.GroupCreateInput) {
|
||||
async function onSave(input: GQL.GroupCreateInput, andNew?: boolean) {
|
||||
const result = await createGroup({
|
||||
variables: { input },
|
||||
});
|
||||
if (result.data?.groupCreate?.id) {
|
||||
history.push(`/groups/${result.data.groupCreate.id}`);
|
||||
if (!andNew) {
|
||||
history.push(`/groups/${result.data.groupCreate.id}`);
|
||||
}
|
||||
Toast.success(
|
||||
intl.formatMessage(
|
||||
{ id: "toast.created_entity" },
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ import { RelatedGroupTable, IRelatedGroupEntry } from "./RelatedGroupTable";
|
|||
|
||||
interface IGroupEditPanel {
|
||||
group: Partial<GQL.GroupDataFragment>;
|
||||
onSubmit: (group: GQL.GroupCreateInput) => Promise<void>;
|
||||
onSubmit: (group: GQL.GroupCreateInput, andNew?: boolean) => Promise<void>;
|
||||
onCancel: () => void;
|
||||
onDelete: () => void;
|
||||
setFrontImage: (image?: string | null) => void;
|
||||
|
|
@ -208,10 +208,10 @@ export const GroupEditPanel: React.FC<IGroupEditPanel> = ({
|
|||
}
|
||||
}
|
||||
|
||||
async function onSave(input: InputValues) {
|
||||
async function onSave(input: InputValues, andNew?: boolean) {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
await onSubmit(input);
|
||||
await onSubmit(input, andNew);
|
||||
formik.resetForm();
|
||||
} catch (e) {
|
||||
Toast.error(e);
|
||||
|
|
@ -219,6 +219,11 @@ export const GroupEditPanel: React.FC<IGroupEditPanel> = ({
|
|||
setIsLoading(false);
|
||||
}
|
||||
|
||||
async function onSaveAndNewClick() {
|
||||
const input = schema.cast(formik.values);
|
||||
onSave(input, true);
|
||||
}
|
||||
|
||||
async function onScrapeGroupURL(url: string) {
|
||||
if (!url) return;
|
||||
setIsLoading(true);
|
||||
|
|
@ -462,6 +467,7 @@ export const GroupEditPanel: React.FC<IGroupEditPanel> = ({
|
|||
isEditing
|
||||
onToggleEdit={onCancel}
|
||||
onSave={formik.handleSubmit}
|
||||
onSaveAndNew={isNew ? onSaveAndNewClick : undefined}
|
||||
saveDisabled={(!isNew && !formik.dirty) || !isEqual(formik.errors, {})}
|
||||
onImageChange={onFrontImageChange}
|
||||
onImageChangeURL={onFrontImageLoad}
|
||||
|
|
|
|||
|
|
@ -23,12 +23,14 @@ const PerformerCreate: React.FC = () => {
|
|||
|
||||
const [createPerformer] = usePerformerCreate();
|
||||
|
||||
async function onSave(input: GQL.PerformerCreateInput) {
|
||||
async function onSave(input: GQL.PerformerCreateInput, andNew?: boolean) {
|
||||
const result = await createPerformer({
|
||||
variables: { input },
|
||||
});
|
||||
if (result.data?.performerCreate) {
|
||||
history.push(`/performers/${result.data.performerCreate.id}`);
|
||||
if (!andNew) {
|
||||
history.push(`/performers/${result.data.performerCreate.id}`);
|
||||
}
|
||||
Toast.success(
|
||||
intl.formatMessage(
|
||||
{ id: "toast.created_entity" },
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import { Button, Form, Dropdown } from "react-bootstrap";
|
||||
import { Button, Form, Dropdown, SplitButton } from "react-bootstrap";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
import Mousetrap from "mousetrap";
|
||||
import * as GQL from "src/core/generated-graphql";
|
||||
|
|
@ -58,7 +58,10 @@ const isScraper = (
|
|||
interface IPerformerDetails {
|
||||
performer: Partial<GQL.PerformerDataFragment>;
|
||||
isVisible: boolean;
|
||||
onSubmit: (performer: GQL.PerformerCreateInput) => Promise<void>;
|
||||
onSubmit: (
|
||||
performer: GQL.PerformerCreateInput,
|
||||
andNew?: boolean
|
||||
) => Promise<void>;
|
||||
onCancel?: () => void;
|
||||
setImage: (image?: string | null) => void;
|
||||
setEncodingImage: (loading: boolean) => void;
|
||||
|
|
@ -345,10 +348,10 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||
ImageUtils.onImageChange(event, onImageLoad);
|
||||
}
|
||||
|
||||
async function onSave(input: InputValues) {
|
||||
async function onSave(input: InputValues, andNew?: boolean) {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
await onSubmit(input);
|
||||
await onSubmit(input, andNew);
|
||||
formik.resetForm();
|
||||
} catch (e) {
|
||||
Toast.error(e);
|
||||
|
|
@ -356,6 +359,15 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||
setIsLoading(false);
|
||||
}
|
||||
|
||||
async function onSaveAndNewClick() {
|
||||
const { values } = formik;
|
||||
const input = {
|
||||
...schema.cast(values),
|
||||
custom_fields: customFieldInput(isNew, values.custom_fields),
|
||||
};
|
||||
onSave(input, true);
|
||||
}
|
||||
|
||||
// set up hotkeys
|
||||
useEffect(() => {
|
||||
if (isVisible) {
|
||||
|
|
@ -603,17 +615,33 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||
<FormattedMessage id="actions.clear_image" />
|
||||
</Button>
|
||||
</div>
|
||||
<Button
|
||||
variant="success"
|
||||
disabled={
|
||||
(!isNew && !formik.dirty) ||
|
||||
!isEqual(formik.errors, {}) ||
|
||||
customFieldsError !== undefined
|
||||
}
|
||||
onClick={() => formik.submitForm()}
|
||||
>
|
||||
<FormattedMessage id="actions.save" />
|
||||
</Button>
|
||||
{isNew ? (
|
||||
<SplitButton
|
||||
id="save-split-button"
|
||||
variant="success"
|
||||
disabled={
|
||||
!isEqual(formik.errors, {}) || customFieldsError !== undefined
|
||||
}
|
||||
title={intl.formatMessage({ id: "actions.save" })}
|
||||
onClick={() => formik.submitForm()}
|
||||
>
|
||||
<Dropdown.Item onClick={() => onSaveAndNewClick()}>
|
||||
<FormattedMessage id="actions.save_and_new" />
|
||||
</Dropdown.Item>
|
||||
</SplitButton>
|
||||
) : (
|
||||
<Button
|
||||
variant="success"
|
||||
disabled={
|
||||
(!isNew && !formik.dirty) ||
|
||||
!isEqual(formik.errors, {}) ||
|
||||
customFieldsError !== undefined
|
||||
}
|
||||
onClick={() => formik.submitForm()}
|
||||
>
|
||||
<FormattedMessage id="actions.save" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,14 +57,16 @@ const SceneCreate: React.FC = () => {
|
|||
return <LoadingIndicator />;
|
||||
}
|
||||
|
||||
async function onSave(input: GQL.SceneCreateInput) {
|
||||
async function onSave(input: GQL.SceneCreateInput, andNew?: boolean) {
|
||||
const fileID = query.get("file_id") ?? undefined;
|
||||
const result = await mutateCreateScene({
|
||||
...input,
|
||||
file_ids: fileID ? [fileID] : undefined,
|
||||
});
|
||||
if (result.data?.sceneCreate?.id) {
|
||||
history.push(`/scenes/${result.data.sceneCreate.id}`);
|
||||
if (!andNew) {
|
||||
history.push(`/scenes/${result.data.sceneCreate.id}`);
|
||||
}
|
||||
Toast.success(
|
||||
intl.formatMessage(
|
||||
{ id: "toast.created_entity" },
|
||||
|
|
|
|||
|
|
@ -1,6 +1,14 @@
|
|||
import React, { useEffect, useState, useMemo } from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
import { Button, Form, Col, Row, ButtonGroup } from "react-bootstrap";
|
||||
import {
|
||||
Button,
|
||||
Dropdown,
|
||||
Form,
|
||||
Col,
|
||||
Row,
|
||||
ButtonGroup,
|
||||
SplitButton,
|
||||
} from "react-bootstrap";
|
||||
import Mousetrap from "mousetrap";
|
||||
import * as GQL from "src/core/generated-graphql";
|
||||
import * as yup from "yup";
|
||||
|
|
@ -51,7 +59,7 @@ interface IProps {
|
|||
initialCoverImage?: string;
|
||||
isNew?: boolean;
|
||||
isVisible: boolean;
|
||||
onSubmit: (input: GQL.SceneCreateInput) => Promise<void>;
|
||||
onSubmit: (input: GQL.SceneCreateInput, andNew?: boolean) => Promise<void>;
|
||||
onDelete?: () => void;
|
||||
}
|
||||
|
||||
|
|
@ -268,10 +276,10 @@ export const SceneEditPanel: React.FC<IProps> = ({
|
|||
formik.setFieldValue("groups", newGroups);
|
||||
}
|
||||
|
||||
async function onSave(input: InputValues) {
|
||||
async function onSave(input: InputValues, andNew?: boolean) {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
await onSubmit(input);
|
||||
await onSubmit(input, andNew);
|
||||
formik.resetForm();
|
||||
} catch (e) {
|
||||
Toast.error(e);
|
||||
|
|
@ -279,6 +287,11 @@ export const SceneEditPanel: React.FC<IProps> = ({
|
|||
setIsLoading(false);
|
||||
}
|
||||
|
||||
async function onSaveAndNewClick() {
|
||||
const input = schema.cast(formik.values);
|
||||
onSave(input, true);
|
||||
}
|
||||
|
||||
const encodingImage = ImageUtils.usePasteImage(onImageLoad);
|
||||
|
||||
function onImageLoad(imageData: string) {
|
||||
|
|
@ -737,16 +750,31 @@ export const SceneEditPanel: React.FC<IProps> = ({
|
|||
<Form noValidate onSubmit={formik.handleSubmit}>
|
||||
<Row className="form-container edit-buttons-container px-3 pt-3">
|
||||
<div className="edit-buttons mb-3 pl-0">
|
||||
<Button
|
||||
className="edit-button"
|
||||
variant="primary"
|
||||
disabled={
|
||||
(!isNew && !formik.dirty) || !isEqual(formik.errors, {})
|
||||
}
|
||||
onClick={() => formik.submitForm()}
|
||||
>
|
||||
<FormattedMessage id="actions.save" />
|
||||
</Button>
|
||||
{isNew ? (
|
||||
<SplitButton
|
||||
id="scene-save-split-button"
|
||||
className="edit-button"
|
||||
variant="primary"
|
||||
disabled={!isEqual(formik.errors, {})}
|
||||
title={intl.formatMessage({ id: "actions.save" })}
|
||||
onClick={() => formik.submitForm()}
|
||||
>
|
||||
<Dropdown.Item onClick={() => onSaveAndNewClick()}>
|
||||
<FormattedMessage id="actions.save_and_new" />
|
||||
</Dropdown.Item>
|
||||
</SplitButton>
|
||||
) : (
|
||||
<Button
|
||||
className="edit-button"
|
||||
variant="primary"
|
||||
disabled={
|
||||
(!isNew && !formik.dirty) || !isEqual(formik.errors, {})
|
||||
}
|
||||
onClick={() => formik.submitForm()}
|
||||
>
|
||||
<FormattedMessage id="actions.save" />
|
||||
</Button>
|
||||
)}
|
||||
{onDelete && (
|
||||
<Button
|
||||
className="edit-button"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Button, Modal } from "react-bootstrap";
|
||||
import { Button, Dropdown, Modal, SplitButton } from "react-bootstrap";
|
||||
import React, { useState } from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
import { ImageInput } from "./ImageInput";
|
||||
|
|
@ -10,6 +10,7 @@ interface IProps {
|
|||
isEditing: boolean;
|
||||
onToggleEdit: () => void;
|
||||
onSave: () => void;
|
||||
onSaveAndNew?: () => void;
|
||||
saveDisabled?: boolean;
|
||||
onDelete: () => void;
|
||||
onAutoTag?: () => void;
|
||||
|
|
@ -48,6 +49,23 @@ export const DetailsEditNavbar: React.FC<IProps> = (props: IProps) => {
|
|||
function renderSaveButton() {
|
||||
if (!props.isEditing) return;
|
||||
|
||||
if (props.isNew && props.onSaveAndNew) {
|
||||
return (
|
||||
<SplitButton
|
||||
id="save-split-button"
|
||||
variant="success"
|
||||
className="save"
|
||||
disabled={props.saveDisabled}
|
||||
title={intl.formatMessage({ id: "actions.save" })}
|
||||
onClick={() => props.onSave()}
|
||||
>
|
||||
<Dropdown.Item onClick={() => props.onSaveAndNew!()}>
|
||||
<FormattedMessage id="actions.save_and_new" />
|
||||
</Dropdown.Item>
|
||||
</SplitButton>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Button
|
||||
variant="success"
|
||||
|
|
|
|||
|
|
@ -62,10 +62,23 @@
|
|||
padding: 0;
|
||||
row-gap: 0.5rem;
|
||||
|
||||
.btn {
|
||||
> .btn {
|
||||
margin-right: 0.5rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
> .btn-group {
|
||||
margin-right: 0.5rem;
|
||||
|
||||
.btn {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
// Show caret on split button dropdown toggle
|
||||
.dropdown-toggle-split::after {
|
||||
content: "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.col-md-8 .details-edit div:nth-last-child(2),
|
||||
|
|
|
|||
|
|
@ -26,12 +26,14 @@ const StudioCreate: React.FC = () => {
|
|||
|
||||
const [createStudio] = useStudioCreate();
|
||||
|
||||
async function onSave(input: GQL.StudioCreateInput) {
|
||||
async function onSave(input: GQL.StudioCreateInput, andNew?: boolean) {
|
||||
const result = await createStudio({
|
||||
variables: { input },
|
||||
});
|
||||
if (result.data?.studioCreate?.id) {
|
||||
history.push(`/studios/${result.data.studioCreate.id}`);
|
||||
if (!andNew) {
|
||||
history.push(`/studios/${result.data.studioCreate.id}`);
|
||||
}
|
||||
Toast.success(
|
||||
intl.formatMessage(
|
||||
{ id: "toast.created_entity" },
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import StashBoxIDSearchModal from "src/components/Shared/StashBoxIDSearchModal";
|
|||
|
||||
interface IStudioEditPanel {
|
||||
studio: Partial<GQL.StudioDataFragment>;
|
||||
onSubmit: (studio: GQL.StudioCreateInput) => Promise<void>;
|
||||
onSubmit: (studio: GQL.StudioCreateInput, andNew?: boolean) => Promise<void>;
|
||||
onCancel: () => void;
|
||||
onDelete: () => void;
|
||||
setImage: (image?: string | null) => void;
|
||||
|
|
@ -132,10 +132,10 @@ export const StudioEditPanel: React.FC<IStudioEditPanel> = ({
|
|||
};
|
||||
});
|
||||
|
||||
async function onSave(input: InputValues) {
|
||||
async function onSave(input: InputValues, andNew?: boolean) {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
await onSubmit(input);
|
||||
await onSubmit(input, andNew);
|
||||
formik.resetForm();
|
||||
} catch (e) {
|
||||
Toast.error(e);
|
||||
|
|
@ -143,6 +143,11 @@ export const StudioEditPanel: React.FC<IStudioEditPanel> = ({
|
|||
setIsLoading(false);
|
||||
}
|
||||
|
||||
async function onSaveAndNewClick() {
|
||||
const input = schema.cast(formik.values);
|
||||
onSave(input, true);
|
||||
}
|
||||
|
||||
function onImageLoad(imageData: string | null) {
|
||||
formik.setFieldValue("image", imageData);
|
||||
}
|
||||
|
|
@ -248,6 +253,7 @@ export const StudioEditPanel: React.FC<IStudioEditPanel> = ({
|
|||
isEditing
|
||||
onToggleEdit={onCancel}
|
||||
onSave={formik.handleSubmit}
|
||||
onSaveAndNew={isNew ? onSaveAndNewClick : undefined}
|
||||
saveDisabled={(!isNew && !formik.dirty) || !isEqual(formik.errors, {})}
|
||||
onImageChange={onImageChange}
|
||||
onImageChangeURL={onImageLoad}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ const TagCreate: React.FC = () => {
|
|||
|
||||
const [createTag] = useTagCreate();
|
||||
|
||||
async function onSave(input: GQL.TagCreateInput) {
|
||||
async function onSave(input: GQL.TagCreateInput, andNew?: boolean) {
|
||||
const oldRelations = {
|
||||
parents: [],
|
||||
children: [],
|
||||
|
|
@ -39,7 +39,9 @@ const TagCreate: React.FC = () => {
|
|||
parents: created.parents,
|
||||
children: created.children,
|
||||
});
|
||||
history.push(`/tags/${created.id}`);
|
||||
if (!andNew) {
|
||||
history.push(`/tags/${created.id}`);
|
||||
}
|
||||
Toast.success(
|
||||
intl.formatMessage(
|
||||
{ id: "toast.created_entity" },
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import StashBoxIDSearchModal from "src/components/Shared/StashBoxIDSearchModal";
|
|||
|
||||
interface ITagEditPanel {
|
||||
tag: Partial<GQL.TagDataFragment>;
|
||||
onSubmit: (tag: GQL.TagCreateInput) => Promise<void>;
|
||||
onSubmit: (tag: GQL.TagCreateInput, andNew?: boolean) => Promise<void>;
|
||||
onCancel: () => void;
|
||||
onDelete: () => void;
|
||||
setImage: (image?: string | null) => void;
|
||||
|
|
@ -122,10 +122,10 @@ export const TagEditPanel: React.FC<ITagEditPanel> = ({
|
|||
};
|
||||
});
|
||||
|
||||
async function onSave(input: InputValues) {
|
||||
async function onSave(input: InputValues, andNew?: boolean) {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
await onSubmit(input);
|
||||
await onSubmit(input, andNew);
|
||||
formik.resetForm();
|
||||
} catch (e) {
|
||||
Toast.error(e);
|
||||
|
|
@ -133,6 +133,11 @@ export const TagEditPanel: React.FC<ITagEditPanel> = ({
|
|||
setIsLoading(false);
|
||||
}
|
||||
|
||||
async function onSaveAndNewClick() {
|
||||
const input = schema.cast(formik.values);
|
||||
onSave(input, true);
|
||||
}
|
||||
|
||||
const encodingImage = ImageUtils.usePasteImage(onImageLoad);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -272,6 +277,7 @@ export const TagEditPanel: React.FC<ITagEditPanel> = ({
|
|||
isEditing
|
||||
onToggleEdit={onCancel}
|
||||
onSave={formik.handleSubmit}
|
||||
onSaveAndNew={isNew ? onSaveAndNewClick : undefined}
|
||||
saveDisabled={
|
||||
(!isNew && !formik.dirty) || !isEqual(formik.errors, {})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -687,6 +687,11 @@ div.dropdown-menu {
|
|||
|
||||
.edit-button {
|
||||
margin-right: 10px;
|
||||
|
||||
// Show caret on split button dropdown toggle
|
||||
&.btn-group .dropdown-toggle-split::after {
|
||||
content: "";
|
||||
}
|
||||
}
|
||||
|
||||
.wrap-tags {
|
||||
|
|
|
|||
|
|
@ -105,6 +105,7 @@
|
|||
"reshuffle": "Reshuffle",
|
||||
"running": "running",
|
||||
"save": "Save",
|
||||
"save_and_new": "Save & New",
|
||||
"save_delete_settings": "Use these options by default when deleting",
|
||||
"save_filter": "Save filter",
|
||||
"scan": "Scan",
|
||||
|
|
|
|||
Loading…
Reference in a new issue