Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the ability to set submission profiles in the UI #1170

Open
wants to merge 79 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
d5bdd4d
Add the ability to set submission profiles in the UI
cccs-rs Jul 30, 2024
588c446
Modify UI to allow users to set parameters when using profiles
cccs-rs Jul 31, 2024
3351287
Allow SubmissionProfiles to lockdown certain service parameters
cccs-rs Aug 7, 2024
e2eef53
UI tweaks + allow anyone to use submission profiles
cccs-rs Aug 9, 2024
8006ab8
Add the ability to edit submission profiles
cccs-rs Oct 11, 2024
5b5cd72
Merge branch 'master' into AL-2646
cccs-nr Oct 15, 2024
7731c65
Fixing some issues
cccs-nr Oct 15, 2024
f919da0
remove console.log()
cccs-nr Oct 15, 2024
4d53920
added the createStoreContext and JSONPath types
cccs-nr Oct 17, 2024
7454f44
changed the createStoreContext
cccs-nr Oct 17, 2024
7216185
more changes
cccs-nr Oct 17, 2024
36dee17
implementing the TanStack form in the submit page
cccs-nr Oct 23, 2024
43bc4b8
changes
cccs-nr Oct 24, 2024
c9f7f61
Merge branch 'master' into AL-2646
cccs-nr Oct 24, 2024
57041ba
more changes...
cccs-nr Oct 28, 2024
222068f
more changes
cccs-nr Oct 29, 2024
1c5d543
starting to revert some changes
cccs-nr Oct 29, 2024
0bebe29
first pass at recreating the old style
cccs-nr Oct 30, 2024
0134344
Removed unused components
cccs-nr Oct 30, 2024
09d6551
changes
cccs-nr Oct 31, 2024
7778455
More changes
cccs-nr Nov 1, 2024
4a75ff4
Changed the structure of submitStore
cccs-nr Nov 4, 2024
f62f6b7
more changes
cccs-nr Nov 4, 2024
07c5ddc
working implementation
cccs-nr Nov 4, 2024
7197372
More changes
cccs-nr Nov 6, 2024
170d693
Fixing errors
cccs-nr Nov 6, 2024
b032732
Commenting old components
cccs-nr Nov 6, 2024
8b1f77b
Fixing the types
cccs-nr Nov 6, 2024
22d7cbb
fixing import errors
cccs-nr Nov 6, 2024
4407d76
Fixed some rendering issues
cccs-nr Nov 6, 2024
b08dfcb
Added the submission customize translation and sorted the values
cccs-nr Nov 6, 2024
e4103c5
Implemented the submission profile on the submit page
cccs-nr Nov 8, 2024
ef855b6
Changed the Settings page
cccs-nr Nov 12, 2024
97cb801
Added the Default File Source
cccs-nr Nov 12, 2024
d5ad3c7
Added the loading and disabled. Added the save button
cccs-nr Nov 12, 2024
b83a9f1
Added a submitting state and checking modified using prev value. Adde…
cccs-nr Nov 12, 2024
4563acf
Added the navigation active style
cccs-nr Nov 13, 2024
f1468c6
missing default_external_sources
cccs-nr Nov 13, 2024
3ded7e5
Added the indeterminate
cccs-nr Nov 13, 2024
24080b0
Show a triangle on a nav item to indicate that there's spec associate…
cccs-nr Nov 13, 2024
9243523
minor fix
cccs-nr Nov 13, 2024
fb0e714
Added the profile header and moved the state into the sections
cccs-nr Nov 13, 2024
e6db787
Added the hidden, customize and selfManage to the form state
cccs-nr Nov 14, 2024
7b4f73c
Removed the old submit components
cccs-nr Nov 14, 2024
027bec9
Lots of changes
cccs-nr Dec 2, 2024
4fb2e1b
fix some issues
cccs-nr Dec 2, 2024
f6b19b1
More changes
cccs-nr Dec 10, 2024
41eb209
Splited the Services
cccs-nr Dec 11, 2024
13de3c8
Cleaned the Submission params
cccs-nr Dec 11, 2024
81dc390
Added the hidden parameters to the inputs
cccs-nr Dec 11, 2024
73868bb
More changes
cccs-nr Dec 11, 2024
335932c
Changes
cccs-nr Dec 11, 2024
7671c1d
Minor fix
cccs-nr Dec 11, 2024
c255ac9
Fixed minor bug
cccs-nr Dec 11, 2024
93ac294
Created the List visual components based on the old Input components
cccs-nr Dec 12, 2024
1ca8127
Using the new List components
cccs-nr Dec 12, 2024
eb0a4b8
Moved the handleSubmit to the header components since its faster
cccs-nr Dec 12, 2024
50b99c7
Fixed the case where there are no specs
cccs-nr Dec 16, 2024
ac67f50
Fixed the params
cccs-nr Dec 16, 2024
96ef378
Changed the submission profile loading and parsing functions and did …
cccs-nr Dec 17, 2024
fbeb28a
Fixed the number input
cccs-nr Dec 17, 2024
576bc53
removed console.logs, fixed the pathing, added guard to forbidden pag…
cccs-nr Dec 17, 2024
63c5f71
Fixed the routing to the profiles
cccs-nr Dec 17, 2024
ad8a337
Moved the tab components inside the components folder
cccs-nr Dec 17, 2024
ae0a58f
Changed hidden to render
cccs-nr Dec 18, 2024
1126ce8
Changed the form typing and comments
cccs-nr Dec 18, 2024
aa34e60
Fixed the render change
cccs-nr Dec 18, 2024
5370541
Started adding some inputs: switch and checkbox
cccs-nr Dec 18, 2024
2b2b403
Added the TextInput
cccs-nr Dec 18, 2024
47c408f
Cleaned the TextInput
cccs-nr Dec 18, 2024
1402d14
Fixed TextInput lint
cccs-nr Dec 18, 2024
bde7912
Added the SliderInput
cccs-nr Dec 18, 2024
02150c5
Moved the ListInputs to their own folder
cccs-nr Dec 18, 2024
5cee187
Changed the inputs
cccs-nr Dec 19, 2024
2d45420
Fixed the new imports
cccs-nr Dec 19, 2024
6136614
Changed the inputs
cccs-nr Dec 19, 2024
e9b75b9
Changed the Inputs
cccs-nr Dec 19, 2024
29c3bf9
Modified the submission parameters
cccs-nr Dec 19, 2024
38a7204
Modified the service selection
cccs-nr Dec 19, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"@mui/styles": "^5.11.9",
"@mui/x-date-pickers": "^5.0.18",
"@mui/x-tree-view": "^7.6.2",
"@tanstack/react-form": "^0.34.0",
"@vitejs/plugin-react": "^4.2.1",
"@vitejs/plugin-react-swc": "^3.5.0",
"autosuggest-highlight": "^3.3.4",
Expand Down Expand Up @@ -107,6 +108,7 @@
"@testing-library/user-event": "^14.5.1",
"@types/autosuggest-highlight": "^3.2.3",
"@types/dompurify": "^3.0.5",
"@types/flowjs__flow.js": "^2.13.3",
"@types/lodash": "^4.14.195",
"@types/md5": "^2.3.5",
"@types/node": "^20.3.1",
Expand Down Expand Up @@ -141,7 +143,7 @@
"prettier-plugin-organize-imports": "^3.2.2",
"setimmediate": "^1.0.5",
"ts-node": "^10.9.1",
"typescript": "^5.4.5",
"typescript": "^5.6.3",
"vitest-fetch-mock": "^0.2.2"
},
"jest": {
Expand Down
46 changes: 46 additions & 0 deletions src/components/core/form/createFormContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import type { FormApi, FormOptions, ReactFormApi, Validator } from '@tanstack/react-form';
import { useForm as useTanStackForm } from '@tanstack/react-form';
import React, { createContext, useCallback, useContext } from 'react';

export function createFormContext<
TFormData,
TFormValidator extends Validator<TFormData, string> = Validator<TFormData, string>
>(options: FormOptions<TFormData, TFormValidator>) {
type FormContextProps = (FormApi<TFormData, TFormValidator> & ReactFormApi<TFormData, TFormValidator>) | null;

const FormContext = createContext<FormContextProps>(null);

type FormProviderProps = {
children: React.ReactNode;
onSubmit?: FormOptions<TFormData, TFormValidator>['onSubmit'];
};

const FormProvider = ({ children, onSubmit = () => null }: FormProviderProps) => {
const form = useTanStackForm({
...options,
onSubmit: props => {
'onSubmit' in options ? options.onSubmit(props) : null;
onSubmit(props);
}
});
return <FormContext.Provider value={form}>{children}</FormContext.Provider>;
};

const useForm = () => {
const form = useContext(FormContext);
if (!form) {
throw new Error('Store not found');
}

const setStore = useCallback(
(updater: (data: TFormData) => TFormData) => {
form.store.setState(s => ({ ...s, values: updater(s.values) }));
},
[form.store]
);

return { ...form, setStore };
};

return { FormProvider, useForm };
}
95 changes: 95 additions & 0 deletions src/components/core/form/models.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
export type Length<T> = T extends { length: infer L } ? L : never;
type Join<T extends unknown[], D extends string> = T extends string[]
? PopFront<T> extends string
? Length<T> extends 1
? `${PopFront<T>}`
: `${PopFront<T>}${D}${Join<Shift<T>, D>}`
: never
: never;
type Pop<T extends unknown[]> = T extends [...infer R, infer U] ? U : never;
type PopFront<T extends unknown[]> = T extends [infer U, ...infer R] ? U : never;
type Shift<T extends unknown[]> = T extends [infer U, ...infer R] ? R : never;

type Filter<T extends unknown[], U> = T extends []
? []
: T extends [infer F, ...infer R]
? F extends U
? Filter<R, T>
: [F, ...Filter<R, U>]
: never;
type TupleIncludes<T extends unknown[], U> = Length<Filter<T, U>> extends Length<T> ? false : true;
type StringIncludes<S extends string, D extends string> = S extends `${infer T}${D}${infer U}` ? true : false;
type Includes<T extends unknown[] | string, U> = T extends unknown[]
? TupleIncludes<T, U>
: T extends string
? U extends string
? StringIncludes<T, U>
: never
: never;

export type Split<S extends string, D extends string> = string extends S
? string[]
: S extends ''
? []
: S extends `${infer T}${D}${infer U}`
? [T, ...Split<U, D>]
: [S];

export type ValidPaths<T> = keyof T extends never
? never
: {
[K in keyof T]: T[K] extends never
? never
: T[K] extends Record<string | number | symbol, unknown>
? K extends string
? `${K}.${ValidPaths<T[K]>}` | K
: never
: K;
}[keyof T] &
string;

export type ValidPathTuples<T> = keyof T extends never
? never
: {
[K in keyof T]: T[K] extends never
? never
: T[K] extends Record<string | number | symbol, unknown>
? [K, ...ValidPathTuples<T[K]>] | [K]
: [K];
}[keyof T];

// string version
export type NestedType<T, P extends string> = Includes<P, '.'> extends true
? PopFront<Split<P, '.'>> extends keyof T
? NestedType<T[PopFront<Split<P, '.'>>], Join<Shift<Split<P, '.'>>, '.'>>
: never
: P extends keyof T
? T[P]
: never;

// tuple version
export type NestedTypeByTuple<T, P extends string[]> = Length<P> extends 1
? Pop<P> extends keyof T
? T[Pop<P>]
: never
: PopFront<P> extends keyof T
? Shift<P> extends string[]
? NestedTypeByTuple<T[PopFront<P>], Shift<P>>
: never
: never;

// String version internally using tuples
// Bonus: Also errors now
export type NestedTypeUsingTuplesAgain<T, P extends ValidPaths<T>> = NestedTypeByTuple<T, Split<P, '.'>>;

export type NestedTypeUsingTuplesAgain2<T, P extends ValidPathTuples<T>> = NestedType<T, Join<P, '.'>>;

export type NestedKeyOf<T extends object> = ValidPathTuples<T>;

export type NestedKeyOf2<T extends object, P extends unknown[] = []> = {
[K in keyof T]: T[K] extends object ? [...P, K] | NestedKeyOf2<T[K], [...P, K]> : [...P, K];
}[keyof T];

export type ExtractNestedValue<P extends unknown[] = []> = P extends [infer First, ...infer _Rest] ? [First] : never;

export type DeepPartial<T> = T extends object ? { [P in keyof T]?: DeepPartial<T[P]> } : T;
43 changes: 43 additions & 0 deletions src/components/core/form/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { expect } from 'vitest';
import type { NestedType } from './models';
import { isObject } from './utils';

// Demo
const dictionary = {
someProp: 123,
nested: {
moreProps: 333,
deeper: {
evenDeeper: {
deepest: 'string'
}
},
alsoDeeper: {
randomProp: {
anotherProp: 'another'
}
}
}
} as const;

type MyDict = typeof dictionary;

type Test = NestedType<MyDict, 'nested.alsoDeeper.randomProp.anotherProp'>; // = yay

const Fn = <T, P extends string>(dict: T, path: P): NestedType<T, P> => {
// skip impl.
return undefined as any;
};

const testFromFn = Fn(dictionary, 'nested.moreProps'); // = 333

describe('Test `Form Utilities`', () => {
it('testing the `isObject()`', () => {
expect(isObject(undefined)).toBe(false);
expect(isObject(null)).toBe(false);
expect(isObject({}, true)).toBe(true);
expect(isObject({}, false)).toBe(false);
expect(isObject([])).toBe(false);
expect(isObject({ test: 'test' })).toBe(true);
});
});
56 changes: 56 additions & 0 deletions src/components/core/form/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import type { NestedTypeUsingTuplesAgain2, ValidPathTuples } from './models';

export type FieldPath<Data> = Data extends any[]
? { [K in keyof Data]: FieldPath<Data[K]> }
: Data extends object
? { [K in keyof Data]: FieldPath<Data[K]> } & { toPath: () => string }
: { toPath: () => string };

export function isObject(data: unknown, empty: boolean = true): data is object {
if (typeof data !== 'object') return false;
else if ([null, undefined].includes(data)) return false;
else if (Object.is({}, data)) return empty;
else if (Array.isArray(data)) return false;
else if (Object.keys(data).length === 0) return empty;
else return true;
}

export function buildPath<Data>(data: Data, path: string = '$'): FieldPath<Data> {
if (isObject(data)) {
return {
...Object.fromEntries(Object.keys(data).map(k => [k, buildPath(data[k], `${path}.${k}`)])),
toPath: () => path
} as any;
} else if (Array.isArray(data)) {
return data.map((v, i) => buildPath(v, `${path}.${i}`)) as any;
} else return { toPath: () => path } as any;
}

export function getValueFromPath<Data extends object>(data: Data, path: string): unknown {
let current = data;
if (data === undefined || data === null) return null;

let paths = path.split('.');
if (paths[0] === '$') paths = paths.slice(1);

for (let i = 0; i < paths.length; ++i) {
if (current[paths[i]] === undefined) return undefined;
current = current[paths[i]];
}
return current;
}

export const setValue = <T extends object, P extends string[], V>(obj: T, path: P, value: V) => {
if (!path?.length) return value;
else return { ...obj, [path[0]]: setValue(obj[path[0]], path.slice(1), value) };
};

export const setValueFromPath = <
T extends object,
P extends ValidPathTuples<T>,
V extends NestedTypeUsingTuplesAgain2<T, P>
>(
store: T,
path: P,
value: V
): T => setValue(store, path as string[], value) as T;
Loading