Files
api/unraid-ui/src/forms/renderers.ts
T
Eli Bosley 5517e7506b feat: add rclone (#1362)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Introduced full RClone remote management with creation, deletion,
listing, and detailed remote info via a multi-step, schema-driven UI.
- Added guided configuration forms supporting advanced and
provider-specific options for RClone remotes.
  - Enabled flash backup initiation through API mutations.
- Added new Vue components for RClone configuration, overview, remote
item cards, and flash backup page.
- Integrated new combobox, stepped layout, control wrapper, label
renderer, and improved form renderers with enhanced validation and error
display.
- Added JSON Forms visibility composable and Unraid settings layout for
consistent UI rendering.

- **Bug Fixes**
- Standardized JSON scalar usage in Docker-related types, replacing
`JSONObject` with `JSON`.

- **Chores**
- Added utility scripts and helpers to manage rclone binary installation
and versioning.
- Updated build scripts and Storybook configuration for CSS handling and
improved developer workflow.
- Refactored ESLint config for modularity and enhanced code quality
enforcement.
- Improved component registration with runtime type checks and error
handling.

- **Documentation**
- Added extensive test coverage for RClone API service, JSON Forms
schema merging, and provider config slice generation.

- **Style**
- Improved UI consistency with new layouts, tooltips on select options,
password visibility toggles, and error handling components.
- Removed deprecated components and consolidated renderer registrations
for JSON Forms.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-05-27 07:52:25 -04:00

112 lines
3.6 KiB
TypeScript

import comboBoxRenderer from '@/forms/ComboBoxField.vue';
import ControlWrapper from '@/forms/ControlWrapper.vue';
import HorizontalLayout from '@/forms/HorizontalLayout.vue';
import inputFieldRenderer from '@/forms/InputField.vue';
import LabelRenderer from '@/forms/LabelRenderer.vue';
import MissingRenderer from '@/forms/MissingRenderer.vue';
import numberFieldRenderer from '@/forms/NumberField.vue';
import PreconditionsLabel from '@/forms/PreconditionsLabel.vue';
import selectRenderer from '@/forms/Select.vue';
import SteppedLayout from '@/forms/SteppedLayout.vue';
import StringArrayField from '@/forms/StringArrayField.vue';
import switchRenderer from '@/forms/Switch.vue';
import UnraidSettingsLayout from '@/forms/UnraidSettingsLayout.vue';
import VerticalLayout from '@/forms/VerticalLayout.vue';
import {
and,
isBooleanControl,
isControl,
isEnumControl,
isIntegerControl,
isLayout,
isNumberControl,
isStringControl,
optionIs,
or,
rankWith,
schemaMatches,
uiTypeIs,
} from '@jsonforms/core';
import type { ControlElement, JsonFormsRendererRegistryEntry, JsonSchema } from '@jsonforms/core';
import type { RendererProps } from '@jsonforms/vue';
import { h, markRaw, type Component } from 'vue';
// Helper function to wrap control renderers with error display
// Returns a functional component
const withErrorWrapper = (RendererComponent: Component) => {
return (props: RendererProps<ControlElement>) => {
return h(ControlWrapper, props, {
default: () => h(RendererComponent, props),
});
};
};
const isStringArray = (schema: JsonSchema): boolean => {
if (!schema || typeof schema !== 'object' || Array.isArray(schema)) return false;
const items = schema.items as JsonSchema;
return schema.type === 'array' && items?.type === 'string';
};
export const jsonFormsRenderers: JsonFormsRendererRegistryEntry[] = [
// Layouts
{
renderer: markRaw(VerticalLayout),
tester: rankWith(2, and(isLayout, uiTypeIs('VerticalLayout'))),
},
{
renderer: markRaw(HorizontalLayout),
tester: rankWith(3, and(isLayout, uiTypeIs('HorizontalLayout'))),
},
{
renderer: markRaw(SteppedLayout),
tester: rankWith(3, and(isLayout, uiTypeIs('SteppedLayout'))),
},
{
renderer: markRaw(UnraidSettingsLayout),
tester: rankWith(3, and(isLayout, uiTypeIs('UnraidSettingsLayout'))),
},
// Controls
{
renderer: markRaw(withErrorWrapper(switchRenderer)),
tester: rankWith(4, and(isBooleanControl, optionIs('toggle', true))),
},
{
renderer: markRaw(withErrorWrapper(switchRenderer)),
tester: rankWith(4, and(isBooleanControl, optionIs('format', 'toggle'))),
},
{
renderer: markRaw(withErrorWrapper(selectRenderer)),
tester: rankWith(4, and(isEnumControl)),
},
{
renderer: markRaw(withErrorWrapper(comboBoxRenderer)),
tester: rankWith(4, and(isControl, optionIs('format', 'combobox'))),
},
{
renderer: markRaw(withErrorWrapper(numberFieldRenderer)),
tester: rankWith(4, or(isNumberControl, isIntegerControl)),
},
{
renderer: markRaw(withErrorWrapper(inputFieldRenderer)),
tester: rankWith(3, isStringControl),
},
{
renderer: markRaw(withErrorWrapper(StringArrayField)),
tester: rankWith(4, and(isControl, schemaMatches(isStringArray))),
},
// Labels
{
renderer: markRaw(PreconditionsLabel),
tester: rankWith(3, and(uiTypeIs('Label'), optionIs('format', 'preconditions'))),
},
{
renderer: markRaw(LabelRenderer),
tester: rankWith(3, and(uiTypeIs('Label'))),
},
// Fallback / Meta
{
renderer: markRaw(withErrorWrapper(MissingRenderer)),
tester: rankWith(0, isControl),
},
];