mirror of
https://github.com/nexu-io/open-design.git
synced 2026-07-06 22:31:53 +08:00
* feat(web): simplify Home composer (drop plugin-inputs form & example pill, move Design Agent next to Send) - Remove the inline plugin-inputs form (ARTIFACT KIND / AUDIENCE / TEMPLATE) from the Home composer; required inputs no longer gate Send (defaults still flow to the backend). - Remove the dismissible "selected example" pill above the editor; picking an example still seeds the prompt. - Move the Design Agent toggle from the footer-left group to sit directly left of the Send button. * fix(web): keep client-side required-input gate on Home composer Dropping the inline plugin-inputs form left pluginInputsAreValid() always returning true, so a required field with no default that the user blanks out in an editable Home scenario kept Send enabled and only failed at click-time apply with a generic "Failed to apply …" error (the daemon's validateInputs rejects missing required inputs). Restore a client-side gate that mirrors the daemon's required-input rule and names the missing field in the submit error, so these Home flows fail fast. Extracts the pure check into utils/pluginRequiredInputs with unit coverage. * fix(web): drop example from active-row mount condition With the example pill removed from the Home composer active row, keeping selectedPromptExample in showActiveContextRow mounted an empty .home-hero__active row when an example was picked with no other active context. Remove it from the condition so the row only renders when it has visible content. --------- Co-authored-by: qiongyu1999 <2694684348@qq.com> Co-authored-by: lefarcen <935902669@qq.com>
50 lines
2.0 KiB
TypeScript
50 lines
2.0 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import type { InputFieldSpec } from '@open-design/contracts';
|
|
import {
|
|
missingRequiredInputs,
|
|
pluginInputsAreValid,
|
|
} from '../../src/utils/pluginRequiredInputs';
|
|
|
|
function field(spec: Partial<InputFieldSpec> & { name: string }): InputFieldSpec {
|
|
return spec as InputFieldSpec;
|
|
}
|
|
|
|
describe('pluginRequiredInputs', () => {
|
|
it('flags a required field with no value and no default (the regressed case)', () => {
|
|
// The Home composer dropped its inline inputs form; a required field with
|
|
// no default that the user blanks out must still fail fast client-side, or
|
|
// the run only breaks later at daemon apply time with a generic error.
|
|
const fields = [field({ name: 'subject', label: 'Subject', required: true })];
|
|
expect(missingRequiredInputs(fields, {})).toEqual(['Subject']);
|
|
expect(missingRequiredInputs(fields, { subject: '' })).toEqual(['Subject']);
|
|
expect(pluginInputsAreValid(fields, { subject: '' })).toBe(false);
|
|
});
|
|
|
|
it('treats a provided value or a usable default as satisfied', () => {
|
|
const fields = [
|
|
field({ name: 'subject', label: 'Subject', required: true }),
|
|
field({ name: 'style', required: true, default: 'cinematic' }),
|
|
];
|
|
expect(pluginInputsAreValid(fields, { subject: 'a product shot' })).toBe(true);
|
|
expect(missingRequiredInputs(fields, { subject: 'a product shot' })).toEqual([]);
|
|
});
|
|
|
|
it('ignores optional fields entirely', () => {
|
|
const fields = [
|
|
field({ name: 'note', required: false }),
|
|
field({ name: 'extra' }),
|
|
];
|
|
expect(pluginInputsAreValid(fields, {})).toBe(true);
|
|
});
|
|
|
|
it('falls back to the field name when no label is set', () => {
|
|
const fields = [field({ name: 'subject', required: true })];
|
|
expect(missingRequiredInputs(fields, {})).toEqual(['subject']);
|
|
});
|
|
|
|
it('does not treat an empty-string default as a usable default', () => {
|
|
const fields = [field({ name: 'subject', label: 'Subject', required: true, default: '' })];
|
|
expect(pluginInputsAreValid(fields, {})).toBe(false);
|
|
});
|
|
});
|