feat(settings): add beforeSave check (#161)

This commit is contained in:
megumin 2022-10-25 18:49:50 +01:00 committed by GitHub
parent e06ba68c40
commit 5e7c155f6e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 43 additions and 23 deletions

View file

@ -67,6 +67,7 @@ export default function PluginModal({ plugin, onRestartNeeded, onClose, transiti
const [tempSettings, setTempSettings] = React.useState<Record<string, any>>({}); const [tempSettings, setTempSettings] = React.useState<Record<string, any>>({});
const [errors, setErrors] = React.useState<Record<string, boolean>>({}); const [errors, setErrors] = React.useState<Record<string, boolean>>({});
const [saveError, setSaveError] = React.useState<string | null>(null);
const canSubmit = () => Object.values(errors).every(e => !e); const canSubmit = () => Object.values(errors).every(e => !e);
@ -79,11 +80,20 @@ export default function PluginModal({ plugin, onRestartNeeded, onClose, transiti
})(); })();
}, []); }, []);
function saveAndClose() { async function saveAndClose() {
if (!plugin.options) { if (!plugin.options) {
onClose(); onClose();
return; return;
} }
if (plugin.beforeSave) {
const result = await Promise.resolve(plugin.beforeSave(tempSettings));
if (result !== true) {
setSaveError(result);
return;
}
}
let restartNeeded = false; let restartNeeded = false;
for (const [key, value] of Object.entries(tempSettings)) { for (const [key, value] of Object.entries(tempSettings)) {
const option = plugin.options[key]; const option = plugin.options[key];
@ -195,28 +205,31 @@ export default function PluginModal({ plugin, onRestartNeeded, onClose, transiti
</Forms.FormSection> </Forms.FormSection>
</ModalContent> </ModalContent>
<ModalFooter> <ModalFooter>
<Flex> <Flex flexDirection="column" style={{ width: "100%" }}>
<Button <Flex style={{ marginLeft: "auto" }}>
onClick={onClose} <Button
size={Button.Sizes.SMALL} onClick={onClose}
color={Button.Colors.RED} size={Button.Sizes.SMALL}
> color={Button.Colors.RED}
Exit Without Saving >
</Button> Exit Without Saving
<Tooltip text="You must fix all errors before saving" shouldShow={!canSubmit()}> </Button>
{({ onMouseEnter, onMouseLeave }) => ( <Tooltip text="You must fix all errors before saving" shouldShow={!canSubmit()}>
<Button {({ onMouseEnter, onMouseLeave }) => (
size={Button.Sizes.SMALL} <Button
color={Button.Colors.BRAND} size={Button.Sizes.SMALL}
onClick={saveAndClose} color={Button.Colors.BRAND}
onMouseEnter={onMouseEnter} onClick={saveAndClose}
onMouseLeave={onMouseLeave} onMouseEnter={onMouseEnter}
disabled={!canSubmit()} onMouseLeave={onMouseLeave}
> disabled={!canSubmit()}
Save & Exit >
</Button> Save & Exit
)} </Button>
</Tooltip> )}
</Tooltip>
</Flex>
{saveError && <Text variant="text-md/semibold" style={{ color: "var(--text-danger)" }}>Error while saving: {saveError}</Text>}
</Flex> </Flex>
</ModalFooter> </ModalFooter>
</ModalRoot> </ModalRoot>

View file

@ -16,6 +16,8 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import { Promisable } from "type-fest";
import { Command } from "../api/Commands"; import { Command } from "../api/Commands";
// exists to export default definePlugin({...}) // exists to export default definePlugin({...})
@ -75,6 +77,11 @@ interface PluginDef {
* Optionally provide settings that the user can configure in the Plugins tab of settings. * Optionally provide settings that the user can configure in the Plugins tab of settings.
*/ */
options?: Record<string, PluginOptionsItem>; options?: Record<string, PluginOptionsItem>;
/**
* Check that this returns true before allowing a save to complete.
* If a string is returned, show the error to the user.
*/
beforeSave?(options: Record<string, any>): Promisable<true | string>;
/** /**
* Allows you to specify a custom Component that will be rendered in your * Allows you to specify a custom Component that will be rendered in your
* plugin's settings page * plugin's settings page