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

Feature/SubmissionProfiles (master) #1170

Open
wants to merge 222 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
222 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
357514c
Added a choice of label or id to set the link
cccs-nr Dec 20, 2024
99feaf8
Minor change to the DatePicker to fit with the change to the DateInput
cccs-nr Dec 20, 2024
b9997f5
Finished the change to the submit page, fixed some issues with the in…
cccs-nr Jan 2, 2025
19aab20
Fixed error in the moment component
cccs-nr Jan 2, 2025
9c6b7d4
Removed the location state as it doesn't support tabbing
cccs-nr Jan 3, 2025
162b922
Added the max file size to the FileDropper
cccs-nr Jan 3, 2025
3e2960e
Fixed minor issues with the has submit and styling issues
cccs-nr Jan 3, 2025
bcae2dc
Added the Collapse component that does conditional rendering
cccs-nr Jan 3, 2025
5063bda
Added the ShowMore button to standardize the styling of that button
cccs-nr Jan 3, 2025
5a3191b
Implemented the hidden service parameters
cccs-nr Jan 3, 2025
4e975ca
Added resets to the service parameters
cccs-nr Jan 3, 2025
4b9e04a
Fixed minor issue
cccs-nr Jan 3, 2025
a3f418e
Fixed the profile names selection
cccs-nr Jan 3, 2025
ccc8c27
change
cccs-nr Jan 3, 2025
d212def
Fixed minor issues with the settings page
cccs-nr Jan 3, 2025
215d5fe
Removed the unnecessary currentUser
cccs-nr Jan 6, 2025
c659236
Added the customize state
cccs-nr Jan 6, 2025
dd4418d
Fixed the checkbox and switch input when disabled
cccs-nr Jan 6, 2025
438b4a7
Added better uri detection for ip, domain and url.
cccs-nr Jan 6, 2025
802c9af
Fixed the test errors
cccs-nr Jan 6, 2025
c6f9451
Fixed minor bug
cccs-nr Jan 6, 2025
fb4b0d3
Fixed the tooltip on the checkbox, switch nad number inputs.
cccs-nr Jan 6, 2025
6e0138f
Made several changes to the input components
cccs-nr Jan 7, 2025
75f972a
Added the Library page to be able to test and validate visual compone…
cccs-nr Jan 7, 2025
7b17e80
Fixed some issues with the Submit components
cccs-nr Jan 7, 2025
8a727d5
Added the error state to the inputs
cccs-nr Jan 7, 2025
a8573ad
Fixed issues related to the last changes
cccs-nr Jan 7, 2025
93de0f8
Added the readOnly prop for the inputs
cccs-nr Jan 8, 2025
03594e7
Added the interaction section of the inputs to test different behavio…
cccs-nr Jan 8, 2025
b20f5c7
changed the form
cccs-nr Jan 8, 2025
449fbbe
Fixed when input is disabled and readonly
cccs-nr Jan 8, 2025
9f41565
Add tooltip of the submit profile current scan
cccs-nr Jan 8, 2025
cbed00e
Added the developer routes with the library and theme
cccs-nr Jan 8, 2025
037613e
Changed the List Inputs components
cccs-nr Jan 9, 2025
4982387
Changed the Inputs components
cccs-nr Jan 9, 2025
51270e9
Added more sections to the developer's library
cccs-nr Jan 9, 2025
244c631
Fixed a color bug in the text list input
cccs-nr Jan 9, 2025
7a634d9
Fixed the Layout components
cccs-nr Jan 9, 2025
d8d5b33
Fixed the submit and settings comonents to the new changes
cccs-nr Jan 9, 2025
b9389f2
Added the changes to the Library index
cccs-nr Jan 9, 2025
8e00a9f
Minor changes to the ListHeader
cccs-nr Jan 9, 2025
32fb5d9
Fixed the label of the list inputs components
cccs-nr Jan 9, 2025
9f6bf60
Fixed the labels and the button interfactions of the ListHeader.
cccs-nr Jan 9, 2025
f228593
Added back the hover effect on the ListHeader
cccs-nr Jan 9, 2025
1ecdfe0
Added the Table Of Content components
cccs-nr Jan 10, 2025
6b593c2
Changed the Demo components used on the Library page
cccs-nr Jan 10, 2025
bdb6d40
Created the PageLayout and the PageNavigation components
cccs-nr Jan 10, 2025
bcc02e2
Modified the library sections to be compatible with the changes made …
cccs-nr Jan 10, 2025
4cddada
Changed the library form
cccs-nr Jan 10, 2025
fe6e767
Improvements
cccs-nr Jan 10, 2025
b7f21a1
missed a key prop
cccs-nr Jan 10, 2025
85582f3
Moved the colors and added the constants to the helpers dir
cccs-nr Jan 13, 2025
106214b
Added the API call page
cccs-nr Jan 13, 2025
ffbeb73
Changed the dir from developers to development
cccs-nr Jan 13, 2025
0229196
Moved the TableOfContent components
cccs-nr Jan 13, 2025
5e8b409
Fixed color names
cccs-nr Jan 13, 2025
131ff7e
Changed the active label to active index in the TableOfContent
cccs-nr Jan 13, 2025
8cf2a4c
Fix the TableOfContent and the Anchor components and how they are use…
cccs-nr Jan 13, 2025
a66dd18
Fixed the tableofcontent
cccs-nr Jan 13, 2025
f0de603
More changes
cccs-nr Jan 14, 2025
0d85d44
Added endAdornment, helperText and focused to the Inputs
cccs-nr Jan 16, 2025
f8d971b
Fixed the Anchors used in the TableOfContent
cccs-nr Jan 16, 2025
bd86be4
Reverted the changes to the URI_HASH_PATTERN_MAP
cccs-nr Jan 16, 2025
6a6ed73
Changes to the Settings components
cccs-nr Jan 17, 2025
c9e78b3
Fixed bug in the table of content
cccs-nr Jan 17, 2025
a47ff8e
Remove the mock data
cccs-nr Jan 17, 2025
3cc39ba
Fixed errors in the API2 component
cccs-nr Jan 17, 2025
c7f3f2c
Merge branch 'master' into AL-2646
cccs-nr Jan 17, 2025
aaed265
Removed all the API components
cccs-nr Jan 17, 2025
977b54d
Added the applySubmissionProfile function for the File and Hash submit
cccs-nr Jan 17, 2025
cbabace
Remove profiling input
cccs-rs Jan 24, 2025
462e606
Cleanup locales
cccs-rs Jan 24, 2025
ad77857
Only display "Show more" if there is more content to show
cccs-rs Jan 24, 2025
e7a6495
Adjust placement of show more toolip for tiny variant
cccs-rs Jan 24, 2025
30b6557
Correct margins for numerical input fields
cccs-rs Jan 24, 2025
48b0dad
Display "Never" when epoch of last_successful_update is 0
cccs-rs Jan 24, 2025
374d659
Changed the matchURL to isURL which always returns a boolean value. A…
cccs-nr Jan 28, 2025
b77aa1a
Removed the `profile` key from the utils.ts
cccs-nr Jan 28, 2025
a34fa66
isURL works with hXXp
cccs-nr Jan 28, 2025
4442dbf
Added more tests for the `refang` function
cccs-nr Jan 28, 2025
f229df0
Hide service parameters that aren't editable to limited users
cccs-rs Jan 28, 2025
8de9e21
Changed the Settings page so that even if a user doesn't have the `cu…
cccs-nr Jan 29, 2025
ea920e7
Hide changing the default classfication if not enforced by system
cccs-rs Jan 30, 2025
c927d84
Patch interface to allow changes to default zip password
cccs-rs Jan 30, 2025
fb0ce35
Update reference to dynamic recursion prevention
cccs-rs Jan 30, 2025
8100dc2
Changed the implementation of the `default_zip_password` form input.
cccs-nr Jan 31, 2025
a855c17
Use the display name configuration for displaying profile names
cccs-rs Jan 31, 2025
7278fd0
Update configuration model
cccs-rs Jan 31, 2025
3ef51ff
Update UI relative to changes to APIs
cccs-rs Feb 1, 2025
8dada37
Merge pull request #1406 from CybercentreCanada/master
cccs-nr Feb 4, 2025
c019092
Filter services that aren't customizable depending on the user
cccs-rs Feb 6, 2025
5cdaecf
Fix settings
cccs-rs Feb 7, 2025
f5a5557
Load setting from `whoami`, no need to make second API call to load u…
cccs-rs Feb 7, 2025
0dc3842
Fix submit page
cccs-rs Feb 8, 2025
61edfa5
Add options in the UI to resubmit with a profile + pass metadata forw…
cccs-rs Feb 11, 2025
2bc4808
Fix bug when paging back to submission after resubmitting
cccs-rs Feb 11, 2025
7a53d69
Restore configuration for executive summaries
cccs-rs Feb 12, 2025
243bd3b
Relocate the submission profile dropdown outside of the tabbed compon…
cccs-rs Feb 12, 2025
4504fd5
Reconfigure Submit page to replace the Options tab with a button to o…
cccs-rs Feb 12, 2025
ccbb33b
Fix drawer for configuring submission
cccs-rs Feb 13, 2025
fdd58dd
Wrap button in tooltip
cccs-rs Feb 13, 2025
bd20ca9
Run final command as the node user
cccs-rs Feb 14, 2025
bdc5f8e
Fix assignment of file sources
cccs-rs Feb 14, 2025
e4048f2
Allow updating selecting sources to unblock the scan button
cccs-rs Feb 14, 2025
e6c460f
Fix rendering bug where services would disappear when deselected
cccs-rs Feb 14, 2025
04a3d3a
Rename Default Analysis to Custom Analysis
cccs-rs Feb 14, 2025
e51aa16
Update settings to use Custom Analysis
cccs-rs Feb 14, 2025
fbbe2d4
Fix display name in selection
cccs-rs Feb 14, 2025
436c04f
Fix assigning parameter changes in Settings
cccs-rs Feb 14, 2025
769eedb
Correct assignment of default values
cccs-rs Feb 17, 2025
2b90330
Remove content subheading in persistent drawer
cccs-rs Feb 17, 2025
5ebbec2
Fix bug in line
cccs-rs Feb 17, 2025
5abe00f
Cosmetics: Add file sources to TOC, shift service listing inside resp…
cccs-rs Feb 17, 2025
8b0f3cf
Fix bug for altering default classification
cccs-rs Feb 17, 2025
17637de
Changed the file names using the new naming convention for the settin…
cccs-nr Feb 18, 2025
d3977f7
Changed the file names using the new naming convention for the submit…
cccs-nr Feb 18, 2025
d1a6508
Minor changes to the Settings page
cccs-nr Feb 18, 2025
244175a
Added the `inset` prop to the list inputs
cccs-nr Feb 18, 2025
1a94923
Fixed issue with the typing of the TableOfContent and moved away from…
cccs-nr Feb 19, 2025
5d60ae0
Removed the editable property from the ServiceParameter as its only u…
cccs-nr Feb 19, 2025
8abb4bb
- Moved away from form.setStore() as it will be deprecated and will n…
cccs-nr Feb 19, 2025
c53dff0
- Moved the list opacity into the components;
cccs-nr Feb 19, 2025
78bf58d
- Moved the previous value into the settings instead of a copy of the…
cccs-nr Feb 19, 2025
2f2ecdf
Clean the code and added the parsing function to return to the origin…
cccs-nr Feb 21, 2025
35f7aac
Removed the mock data
cccs-nr Feb 21, 2025
e808099
Fixed the expand_min_score input
cccs-nr Feb 24, 2025
e3ec2d0
Fixed some minor issues
cccs-nr Feb 24, 2025
18ac17d
Implementing a different Submit page
cccs-nr Feb 27, 2025
cb8c2cf
Update imports
cccs-nr Feb 27, 2025
bc3cbd1
More changes
cccs-nr Feb 27, 2025
1f6df86
Added the "Adjust" interface
cccs-nr Feb 28, 2025
0136f9a
Removed unused components
cccs-nr Feb 28, 2025
b94c32d
Fixed errors in the Confirmation
cccs-nr Feb 28, 2025
b430f3b
Change the `form.setStore()` to `form.setFieldValue()`
cccs-nr Feb 28, 2025
a233470
Changed the Inputs
cccs-nr Mar 1, 2025
23c2f3e
More changes
cccs-nr Mar 1, 2025
f1cc574
Fixed minor bug
cccs-nr Mar 1, 2025
58f148b
Changed the metadata section and added a default value for the descri…
cccs-nr Mar 3, 2025
16d4714
Added a validator for the submit and added a Metadata editor
cccs-nr Mar 3, 2025
a1e5088
Fixed the submit handlers
cccs-nr Mar 3, 2025
fb4146f
Added a `find` button to search if a hash exists in the system
cccs-nr Mar 4, 2025
390a5ce
Changes
cccs-nr Mar 5, 2025
791ea81
Implemented a side-by-side interface
cccs-nr Mar 8, 2025
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
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ RUN yarn global add serve
WORKDIR /usr/src/app
COPY --from=builder /tmp/frontend/build .
EXPOSE 3000
USER node
CMD ["serve", "-s", "-p", "3000"]
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
31 changes: 31 additions & 0 deletions src/components/core/TableOfContent/Anchor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React, { useEffect, useId } from 'react';
import { useTableOfContent } from './TableOfContent';

export type AnchorProps = React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement> & {
anchor?: string;
label?: React.ReactNode;
subheader?: boolean;
disabled?: boolean;
};

export const Anchor: React.FC<AnchorProps> = React.memo(
({ anchor = null, label = '', subheader = false, children = null, disabled = false, ...props }: AnchorProps) => {
const id = useId();

const loadAnchors = useTableOfContent()?.loadAnchors;

useEffect(() => {
if (disabled) return;
loadAnchors({ id: anchor || id, label: label.toString(), subheader });
return () => loadAnchors({});
}, [anchor, disabled, id, label, loadAnchors, subheader]);

return disabled ? (
children
) : (
<div data-anchor={anchor || id} {...props}>
{children}
</div>
);
}
);
132 changes: 132 additions & 0 deletions src/components/core/TableOfContent/TableOfContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import { createFormContext } from 'components/core/form/createFormContext';
import React, { useCallback, useContext, useEffect, useMemo, useRef } from 'react';

export type TableOfContentStore = {
activeID: string;
anchors: { id: string; label: string; subheader: boolean }[];
};

const TABLE_OF_CONTENT_STORE: TableOfContentStore = Object.freeze({
activeID: null,
anchors: []
});

const { FormProvider, useForm } = createFormContext<TableOfContentStore>({
defaultValues: structuredClone(TABLE_OF_CONTENT_STORE)
});

export type TableOfContentContextProps = {
rootRef: React.MutableRefObject<HTMLDivElement>;
headerRef: React.MutableRefObject<HTMLDivElement>;
loadAnchors: (props?: { id?: string; label?: string; subheader?: boolean }) => void;
scrollTo: (event: React.SyntheticEvent, activeAnchor: string) => void;
Anchors: React.FC<{ children: (anchors: TableOfContentStore['anchors']) => React.ReactNode }>;
ActiveAnchor: React.FC<{
activeID: TableOfContentStore['activeID'];
children: (active: boolean) => React.ReactNode;
}>;
};

export const TableOfContentContext = React.createContext<TableOfContentContextProps>(null);

export function useTableOfContent(): TableOfContentContextProps {
return useContext(TableOfContentContext);
}

export type TableOfContentProps = {
behavior?: ScrollOptions['behavior'];
children?: React.ReactNode;
};

export const TableOfContent: React.FC<TableOfContentProps> = React.memo(
({ behavior = 'smooth', children = null }: TableOfContentProps) => {
const form = useForm();

const rootRef = useRef<HTMLDivElement>();
const headerRef = useRef<HTMLDivElement>();

const Anchors = useMemo<TableOfContentContextProps['Anchors']>(
() =>
({ children: render }) =>
<form.Subscribe selector={state => state.values.anchors} children={anchors => render(anchors)} />,
[form]
);

const ActiveAnchor = useMemo<TableOfContentContextProps['ActiveAnchor']>(
() =>
({ activeID, children: render }) =>
<form.Subscribe selector={state => activeID === state.values.activeID} children={active => render(active)} />,
[form]
);

const findActive = useCallback(() => {
const elements = rootRef.current?.querySelectorAll('[data-anchor]');
for (let i = elements.length - 1; i >= 0; i--) {
if (
elements.item(i).getBoundingClientRect().top - 2 <=
rootRef.current.getBoundingClientRect().top + headerRef.current.getBoundingClientRect().height
) {
form.setFieldValue('activeID', elements.item(i).getAttribute('data-anchor'));
break;
}
}
}, [form]);

const loadAnchors = useCallback<TableOfContentContextProps['loadAnchors']>(
({ id = null, label = null, subheader = false }) => {
const elements = rootRef.current?.querySelectorAll('[data-anchor]');
const prevAnchors = form.getFieldValue('anchors');
const nextAnchors: TableOfContentStore['anchors'] = [];

(elements || []).forEach((element: Element) => {
const anchorID = element.getAttribute('data-anchor');
const index = prevAnchors.findIndex(a => a.id === anchorID);
if (id === anchorID) nextAnchors.push({ id, label, subheader });
else if (index >= 0) nextAnchors.push(prevAnchors[index]);
});

form.setFieldValue('activeID', null);
form.setFieldValue('anchors', nextAnchors);
},
[form]
);

const scrollTo = useCallback<TableOfContentContextProps['scrollTo']>(
(event, activeAnchor) => {
event.preventDefault();
event.stopPropagation();

const element: HTMLDivElement = rootRef.current.querySelector("[data-anchor='" + activeAnchor + "']");
rootRef.current.scrollTo({
top: element.offsetTop - rootRef.current.offsetTop - headerRef.current.getBoundingClientRect().height,
behavior: behavior
});
},
[behavior]
);

useEffect(() => {
const rootElement = rootRef.current;
if (!rootElement) return;

rootElement.addEventListener('scroll', findActive, false);
return () => {
rootElement.removeEventListener('scroll', findActive, false);
};
}, [findActive]);

return (
<TableOfContentContext.Provider value={{ rootRef, headerRef, loadAnchors, scrollTo, Anchors, ActiveAnchor }}>
{children}
</TableOfContentContext.Provider>
);
}
);

export const TableOfContentProvider = React.memo((props: TableOfContentProps) => (
<FormProvider>
<TableOfContent {...props} />
</FormProvider>
));

export default TableOfContentProvider;
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/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;
13 changes: 13 additions & 0 deletions src/components/core/form/form.utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { expect } from 'vitest';
import { isObject } from './form.utils';

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);
});
});
Loading