Skip to content

Commit

Permalink
feat: add UI support for flag metadata (#3717)
Browse files Browse the repository at this point in the history
* feat: add MetadataForm component and flag metadata types

- Add IFlagMetadata interface to Flag.ts
- Create MetadataForm component with CRUD operations
- Add validation using Yup schema
- Use Radix UI components for accessibility
- Style with TailwindCSS
- Install required type declarations

Co-Authored-By: Mark Phelps <[email protected]>

* feat: integrate MetadataForm into FlagForm

- Add metadata field to flag form
- Update validation schema for metadata
- Follow existing styling patterns
- Add proper TypeScript types

Co-Authored-By: Mark Phelps <[email protected]>

* feat: update RTK Query endpoints for flag metadata

- Ensure metadata is preserved in updateFlag mutation
- Preserve metadata when copying flags
- Add proper TypeScript types for metadata handling

Co-Authored-By: Mark Phelps <[email protected]>

* chore: add testing dependencies for MetadataForm tests

Co-Authored-By: Mark Phelps <[email protected]>

* test: add MetadataForm component tests

Co-Authored-By: Mark Phelps <[email protected]>

* chore: update jest config for React and TypeScript testing

Co-Authored-By: Mark Phelps <[email protected]>

* chore: update testing dependencies and babel config

Co-Authored-By: Mark Phelps <[email protected]>

* chore: update jest configuration and dependencies

Co-Authored-By: Mark Phelps <[email protected]>

* chore: add babel-jest for React component testing

Co-Authored-By: Mark Phelps <[email protected]>

* test: enhance React testing configuration

Co-Authored-By: Mark Phelps <[email protected]>

* test: relocate MetadataForm test file

Co-Authored-By: Mark Phelps <[email protected]>

* test: improve MetadataForm test selectors and type handling

Co-Authored-By: Mark Phelps <[email protected]>

* chore: ignore coverage directory

Co-Authored-By: Mark Phelps <[email protected]>

* chore: remove coverage directory

Co-Authored-By: Mark Phelps <[email protected]>

* test: update MetadataForm test formatting

Co-Authored-By: Mark Phelps <[email protected]>

* chore: update ui/.gitignore

Co-Authored-By: Mark Phelps <[email protected]>
Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix: resolve linting issues and move test dependencies

Co-Authored-By: Mark Phelps <[email protected]>

* fix: move testing libraries to devDependencies

Co-Authored-By: Mark Phelps <[email protected]>

* test: add test setup and mock files

Co-Authored-By: Mark Phelps <[email protected]>

* chore: prepare for test file cleanup

Co-Authored-By: Mark Phelps <[email protected]>

* chore: remove unit test files in favor of e2e tests

Co-Authored-By: Mark Phelps <[email protected]>

* test: add playwright tests for flag metadata

Co-Authored-By: Mark Phelps <[email protected]>

* chore: origin add back ui/data tests

Signed-off-by: Mark Phelps <[email protected]>

* chore: revert ui test config

Signed-off-by: Mark Phelps <[email protected]>

* chore: delete unneeded tests configs, add back helpers tests

Signed-off-by: Mark Phelps <[email protected]>

* chore: redo package.json

Signed-off-by: Mark Phelps <[email protected]>

* chore: support objects and primitives in metadata

Signed-off-by: Mark Phelps <[email protected]>

* chore: handle arrays

Signed-off-by: Mark Phelps <[email protected]>

* chore: simplify

Signed-off-by: Mark Phelps <[email protected]>

* chore: only show types/subtypes for new fields

Signed-off-by: Mark Phelps <[email protected]>

* chore: fix lint issues

Signed-off-by: Mark Phelps <[email protected]>

* chore: fix tests

Signed-off-by: Mark Phelps <[email protected]>

* chore: try to fix readonly flag test

Signed-off-by: Mark Phelps <[email protected]>

* chore: rename metadata flag for tests

Signed-off-by: Mark Phelps <[email protected]>

* chore: revert back to original icons in flag form

Signed-off-by: Mark Phelps <[email protected]>

* chore: add error boundary for metadata form

Signed-off-by: Mark Phelps <[email protected]>

* chore: revert string as key helper

Signed-off-by: Mark Phelps <[email protected]>

* chore: handle duplicate key errors

Signed-off-by: Mark Phelps <[email protected]>

* chore: update specs

Signed-off-by: Mark Phelps <[email protected]>

* chore: ui IT test fix

Signed-off-by: Mark Phelps <[email protected]>

---------

Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Signed-off-by: Mark Phelps <[email protected]>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Mark Phelps <[email protected]>
Co-authored-by: Mark Phelps <[email protected]>
  • Loading branch information
3 people authored Jan 1, 2025
1 parent 1c01075 commit e62f4b4
Show file tree
Hide file tree
Showing 13 changed files with 776 additions and 84 deletions.
1 change: 0 additions & 1 deletion go.work.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1665,7 +1665,6 @@ github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+
github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
github.com/prometheus/common v0.60.1/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw=
github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
Expand Down
3 changes: 2 additions & 1 deletion ui/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@ dist-ssr
/playwright/.cache/
.packagehash
/screenshots/
.env
.env
coverage
5 changes: 3 additions & 2 deletions ui/src/app/console/Console.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { useListAuthProvidersQuery } from '~/app/auth/authApi';
import { useListFlagsQuery } from '~/app/flags/flagsApi';
import { selectCurrentNamespace } from '~/app/namespaces/namespacesSlice';
import { selectCurrentRef } from '~/app/refs/refsSlice';
import { ContextEditor } from '~/components/console/ContextEditor';
import { JsonEditor } from '~/components/json/JsonEditor';
import EmptyState from '~/components/EmptyState';
import { Button } from '~/components/Button';
import Combobox from '~/components/Combobox';
Expand Down Expand Up @@ -285,8 +285,9 @@ export default function Console() {
Request Context
</label>
<div className="mt-1 text-sm">
<ContextEditor
<JsonEditor
id="context"
value={formik.values.context}
setValue={(v) => {
formik.setFieldValue('context', v);
}}
Expand Down
2 changes: 1 addition & 1 deletion ui/src/app/flags/flagsApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,9 @@ export const flagsApi = createApi({
{ namespaceKey: string; flagKey: string; values: IFlagBase }
>({
query({ namespaceKey, flagKey, values }) {
// create new object 'values' to remap defaultVariant to defaultVariantId
const update = {
defaultVariantId: values.defaultVariant?.id || null,
metadata: values.metadata || [],
...values
};
delete update.defaultVariant;
Expand Down
64 changes: 0 additions & 64 deletions ui/src/components/console/lint.ts

This file was deleted.

50 changes: 45 additions & 5 deletions ui/src/components/flags/forms/FlagForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ import { Button } from '~/components/Button';
import Input from '~/components/forms/Input';
import Toggle from '~/components/forms/Toggle';
import Loading from '~/components/Loading';
import { MetadataForm } from '~/components/flags/forms/MetadataForm';
import { useError } from '~/data/hooks/error';
import { useSuccess } from '~/data/hooks/success';
import { keyValidation, requiredValidation } from '~/data/validations';
import { FlagType, IFlag, IFlagBase } from '~/types/Flag';
import { cls, copyTextToClipboard, stringAsKey } from '~/utils/helpers';
import MetadataFormErrorBoundary from './MetadataFormErrorBoundary';

const flagTypes = [
{
Expand All @@ -37,7 +39,8 @@ const flagTypes = [

const flagValidationSchema = Yup.object({
key: keyValidation,
name: requiredValidation
name: requiredValidation,
metadata: Yup.object()
});

export default function FlagForm(props: { flag?: IFlag }) {
Expand All @@ -61,14 +64,14 @@ export default function FlagForm(props: { flag?: IFlag }) {
if (isNew) {
return createFlag({
namespaceKey: namespace.key,
values: values
values
}).unwrap();
}

return updateFlag({
namespaceKey: namespace.key,
flagKey: flag?.key,
values: values
values
}).unwrap();
};

Expand All @@ -78,10 +81,12 @@ export default function FlagForm(props: { flag?: IFlag }) {
description: flag?.description || '',
type: flag?.type || FlagType.VARIANT,
enabled: flag?.enabled || false,
defaultVariant: flag?.defaultVariant
defaultVariant: flag?.defaultVariant,
metadata: flag?.metadata || {}
};

const [keyCopied, setKeyCopied] = useState(false);
const [hasMetadataErrors, setHasMetadataErrors] = useState(false);

return (
<Formik
Expand Down Expand Up @@ -285,6 +290,40 @@ export default function FlagForm(props: { flag?: IFlag }) {
disabled={readOnly}
/>
</div>
<div className="col-span-3">
<div className="flex justify-between">
<label
htmlFor="metadata"
className="block text-sm font-medium text-gray-700"
>
Metadata
</label>
<span
className="text-xs text-gray-500"
id="metadata-optional"
>
Optional
</span>
</div>
<div className="mt-1">
<MetadataFormErrorBoundary
metadata={formik.values.metadata}
onChange={(metadata) =>
formik.setFieldValue('metadata', metadata)
}
disabled={readOnly}
>
<MetadataForm
metadata={formik.values.metadata}
onChange={(metadata) =>
formik.setFieldValue('metadata', metadata)
}
disabled={readOnly}
onErrorChange={setHasMetadataErrors}
/>
</MetadataFormErrorBoundary>
</div>
</div>
</div>
<div className="flex justify-end">
<Button type="button" onClick={() => navigate(-1)}>
Expand All @@ -297,7 +336,8 @@ export default function FlagForm(props: { flag?: IFlag }) {
title={readOnly ? 'Not allowed in Read-Only mode' : undefined}
disabled={
!(formik.dirty && formik.isValid && !formik.isSubmitting) ||
readOnly
readOnly ||
hasMetadataErrors
}
>
{formik.isSubmitting ? <Loading isPrimary /> : submitPhrase}
Expand Down
Loading

0 comments on commit e62f4b4

Please sign in to comment.