From 4722bb8fcdac05dfba6a5d7589bb01a4228bb42e Mon Sep 17 00:00:00 2001 From: Hasan Mansoor <68682354+HasanMansoor4@users.noreply.github.com> Date: Thu, 2 Feb 2023 05:27:07 +0300 Subject: [PATCH 1/5] add auto capitalization api controllers and routes with mongo schema updated --- .../src/controllers/v2/workspaceController.ts | 40 ++++++++++++++++++- backend/src/models/workspace.ts | 5 +++ backend/src/routes/v2/workspace.ts | 15 +++++++ 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/backend/src/controllers/v2/workspaceController.ts b/backend/src/controllers/v2/workspaceController.ts index 90781b58c..ce3ecba31 100644 --- a/backend/src/controllers/v2/workspaceController.ts +++ b/backend/src/controllers/v2/workspaceController.ts @@ -467,4 +467,42 @@ export const deleteWorkspaceMembership = async (req: Request, res: Response) => return res.status(200).send({ membership }); -} \ No newline at end of file +} + +/** + * Change autoCapitilzation Rule of workspace + * @param req + * @param res + * @returns + */ +export const toggleAutoCapitilzation = async (req: Request, res: Response) => { + let workspace; + try { + const { workspaceId } = req.params; + const { autoCapitalization } = req.body; + + workspace = await Workspace.findOneAndUpdate( + { + _id: workspaceId + }, + { + autoCapitalization + }, + { + new: true + } + ); + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to change autoCapitalization setting' + }); + } + + return res.status(200).send({ + message: 'Successfully changed autoCapitalization setting', + workspace + }); +}; + diff --git a/backend/src/models/workspace.ts b/backend/src/models/workspace.ts index a70b64340..d68ae9416 100644 --- a/backend/src/models/workspace.ts +++ b/backend/src/models/workspace.ts @@ -8,6 +8,7 @@ export interface IWorkspace { name: string; slug: string; }>; + autoCapitalization: boolean; } const workspaceSchema = new Schema({ @@ -15,6 +16,10 @@ const workspaceSchema = new Schema({ type: String, required: true }, + autoCapitalization: { + type: Boolean, + default: true, + }, organization: { type: Schema.Types.ObjectId, ref: 'Organization', diff --git a/backend/src/routes/v2/workspace.ts b/backend/src/routes/v2/workspace.ts index 55299e575..4e48c9301 100644 --- a/backend/src/routes/v2/workspace.ts +++ b/backend/src/routes/v2/workspace.ts @@ -118,4 +118,19 @@ router.delete( // TODO - rewire dashboard to this route workspaceController.deleteWorkspaceMembership ); + +router.post( + '/:workspaceId/settings', + requireAuth({ + acceptedAuthModes: ['jwt'] + }), + requireWorkspaceAuth({ + acceptedRoles: [ADMIN, MEMBER] + }), + param('workspaceId').exists().trim(), + body('autoCapitalization').exists().trim().notEmpty(), + validateRequest, + workspaceController.toggleAutoCapitilzation +); + export default router; From 75cd7a0f1580a8a09dd00509d991bed72fed1fc8 Mon Sep 17 00:00:00 2001 From: Hasan Mansoor <68682354+HasanMansoor4@users.noreply.github.com> Date: Thu, 2 Feb 2023 05:30:22 +0300 Subject: [PATCH 2/5] integrate frontend with backend for auto capitalization setting --- .../public/locales/en/settings-project.json | 4 +- .../dashboard/DashboardInputField.tsx | 9 +++-- frontend/src/components/dashboard/KeyPair.tsx | 5 ++- .../src/pages/api/workspace/getWorkspaces.ts | 1 + .../api/workspace/toggleAutoCapitalization.ts | 26 +++++++++++++ frontend/src/pages/dashboard/[id].tsx | 4 ++ frontend/src/pages/settings/project/[id].tsx | 38 +++++++++++++++++++ 7 files changed, 82 insertions(+), 5 deletions(-) create mode 100644 frontend/src/pages/api/workspace/toggleAutoCapitalization.ts diff --git a/frontend/public/locales/en/settings-project.json b/frontend/public/locales/en/settings-project.json index 03e4b1459..3f3401f2e 100644 --- a/frontend/public/locales/en/settings-project.json +++ b/frontend/public/locales/en/settings-project.json @@ -9,5 +9,7 @@ "project-id-description": "To integrate Infisical into your code base and get automatic injection of environmental variables, you should use the following Project ID.", "project-id-description2": "For more guidance, including code snipets for various languages and frameworks, see ", "auto-generated": "This is your project's auto-generated unique identifier. It can't be changed.", - "docs": "Infisical Docs" + "docs": "Infisical Docs", + "auto-capitalization": "Auto Capitalization", + "auto-capitalization-description": "According to standards, Infisical will automatically capitalize your keys. If you want to disable this feature, you can do so here." } diff --git a/frontend/src/components/dashboard/DashboardInputField.tsx b/frontend/src/components/dashboard/DashboardInputField.tsx index 0e292d65d..6969b04d8 100644 --- a/frontend/src/components/dashboard/DashboardInputField.tsx +++ b/frontend/src/components/dashboard/DashboardInputField.tsx @@ -14,6 +14,7 @@ interface DashboardInputFieldProps { blurred?: boolean; isDuplicate?: boolean; override?: boolean; + isCapitalized?: boolean; } /** @@ -36,7 +37,8 @@ const DashboardInputField = ({ value, blurred, isDuplicate, - override + override, + isCapitalized }: DashboardInputFieldProps) => { const ref = useRef(null); const syncScroll = (e: SyntheticEvent) => { @@ -58,7 +60,7 @@ const DashboardInputField = ({ } rounded-md`} > onChangeHandler(e.target.value.toUpperCase(), position)} + onChange={(e) => onChangeHandler(isCapitalized ? e.target.value.toUpperCase() : e.target.value, position)} type={type} value={value} className={`z-10 peer font-mono ph-no-capture bg-bunker-800 rounded-md caret-white text-gray-400 text-md px-2 py-1.5 w-full min-w-16 outline-none focus:ring-2 ${ @@ -164,7 +166,8 @@ function inputPropsAreEqual(prev: DashboardInputFieldProps, next: DashboardInput prev.position === next.position && prev.blurred === next.blurred && prev.override === next.override && - prev.isDuplicate === next.isDuplicate + prev.isDuplicate === next.isDuplicate && + prev.isCapitalized === next.isCapitalized ); } diff --git a/frontend/src/components/dashboard/KeyPair.tsx b/frontend/src/components/dashboard/KeyPair.tsx index 7de4edf82..c7aece86f 100644 --- a/frontend/src/components/dashboard/KeyPair.tsx +++ b/frontend/src/components/dashboard/KeyPair.tsx @@ -14,6 +14,7 @@ interface KeyPairProps { toggleSidebar: (id: string) => void; sidebarSecretId: string; isSnapshot: boolean; + isCapitalized: boolean; } /** @@ -39,7 +40,8 @@ const KeyPair = ({ isDuplicate, toggleSidebar, sidebarSecretId, - isSnapshot + isSnapshot, + isCapitalized }: KeyPairProps) => (
; } diff --git a/frontend/src/pages/api/workspace/toggleAutoCapitalization.ts b/frontend/src/pages/api/workspace/toggleAutoCapitalization.ts new file mode 100644 index 000000000..fa459d67a --- /dev/null +++ b/frontend/src/pages/api/workspace/toggleAutoCapitalization.ts @@ -0,0 +1,26 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +/** + * This route lets us change the auto capitalization settings in a project. + * @param {*} req + * @param {*} res + * @returns + */ +const toggleAutoCapitalization = (workspaceId: string, state: boolean) => + SecurityClient.fetchCall(`/api/v2/workspace/${workspaceId}/settings`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + autoCapitalization: state + }) + }).then(async (res) => { + if (res && res.status === 200) { + return res; + } + console.log('Failed to toggle auto capitalization state'); + return undefined; + }); + +export default toggleAutoCapitalization; diff --git a/frontend/src/pages/dashboard/[id].tsx b/frontend/src/pages/dashboard/[id].tsx index c7f15ca70..25fd7fecd 100644 --- a/frontend/src/pages/dashboard/[id].tsx +++ b/frontend/src/pages/dashboard/[id].tsx @@ -123,6 +123,7 @@ export default function Dashboard() { const [snapshotData, setSnapshotData] = useState(); const [numSnapshots, setNumSnapshots] = useState(); const [saveLoading, setSaveLoading] = useState(false); + const [autoCapitalization, setAutoCapitalization] = useState(false); const { t } = useTranslation(); const { createNotification } = useNotificationContext(); @@ -213,6 +214,7 @@ export default function Dashboard() { if (!workspace) { router.push(`/dashboard/${userWorkspaces?.[0]?._id}`); } + setAutoCapitalization(workspace?.autoCapitalization ?? true); setWorkspaceEnvs(workspace?.environments || []); // set env @@ -758,6 +760,7 @@ export default function Dashboard() { .filter((row) => !sharedToHide.includes(row.id)) .map((keyPair) => ( ( ([]); const [environments, setEnvironments] = useState>([]); const [workspaceToBeDeletedName, setWorkspaceToBeDeletedName] = useState(''); @@ -63,6 +67,7 @@ export default function SettingsBasic() { userWorkspaces.forEach((userWorkspace) => { if (userWorkspace._id === workspaceId) { setWorkspaceName(userWorkspace.name); + setAutoCapitalization(userWorkspace.autoCapitalization ?? true); setEnvironments(userWorkspace.environments); } }); @@ -80,11 +85,22 @@ export default function SettingsBasic() { setWorkspaceName(newName); }; + const toggleAutoCapitalizationCheckBox = (state: boolean) => { + setAutoCapitalizationButtonReady(true); + setAutoCapitalization(state); + }; + const submitChanges = (newWorkspaceName: string) => { renameWorkspace(workspaceId, newWorkspaceName); setButtonReady(false); }; + const submitAutoCapitalizationChanges = () => { + toggleAutoCapitalization(workspaceId, autoCapitalization); + setAutoCapitalizationButtonReady(false); + }; + + const closeAddServiceTokenModal = () => { setIsAddServiceTokenDialogOpen(false); }; @@ -196,6 +212,28 @@ export default function SettingsBasic() {
+
+

{t('settings-project:auto-capitalization')}

+ toggleAutoCapitalizationCheckBox(state as boolean)} + > {t('settings-project:auto-capitalization-description')} +
+
+
+
+

{t('common:project-id')}

From 77a44b4490252ebfcbe6f840cc8792cfbe8e4a9b Mon Sep 17 00:00:00 2001 From: Hasan Mansoor <68682354+HasanMansoor4@users.noreply.github.com> Date: Sun, 5 Feb 2023 06:21:58 +0300 Subject: [PATCH 3/5] Refactor into component and use React Query --- frontend/src/hooks/api/workspace/index.tsx | 1 + frontend/src/hooks/api/workspace/queries.tsx | 14 +++++++- frontend/src/hooks/api/workspace/types.ts | 2 ++ .../api/workspace/toggleAutoCapitalization.ts | 26 -------------- .../ProjectSettingsPage.tsx | 29 ++++++++++++++++ .../AutoCapitalizationSection.tsx | 34 +++++++++++++++++++ .../AutoCapitalizationSection/index.tsx | 1 + 7 files changed, 80 insertions(+), 27 deletions(-) delete mode 100644 frontend/src/pages/api/workspace/toggleAutoCapitalization.ts create mode 100644 frontend/src/views/Settings/ProjectSettingsPage/components/AutoCapitalizationSection/AutoCapitalizationSection.tsx create mode 100644 frontend/src/views/Settings/ProjectSettingsPage/components/AutoCapitalizationSection/index.tsx diff --git a/frontend/src/hooks/api/workspace/index.tsx b/frontend/src/hooks/api/workspace/index.tsx index 5de95ab05..23d9e42a3 100644 --- a/frontend/src/hooks/api/workspace/index.tsx +++ b/frontend/src/hooks/api/workspace/index.tsx @@ -4,5 +4,6 @@ export { useDeleteWsEnvironment, useGetUserWorkspaces, useRenameWorkspace, + useToggleAutoCapitalization, useUpdateWsEnvironment } from './queries'; diff --git a/frontend/src/hooks/api/workspace/queries.tsx b/frontend/src/hooks/api/workspace/queries.tsx index b0566a43d..64e4a905c 100644 --- a/frontend/src/hooks/api/workspace/queries.tsx +++ b/frontend/src/hooks/api/workspace/queries.tsx @@ -7,6 +7,7 @@ import { DeleteEnvironmentDTO, DeleteWorkspaceDTO, RenameWorkspaceDTO, + ToggleAutoCapitalizationDTO, UpdateEnvironmentDTO, Workspace } from './types'; @@ -17,7 +18,6 @@ const workspaceKeys = { const fetchUserWorkspaces = async () => { const { data } = await apiRequest.get<{ workspaces: Workspace[] }>('/api/v1/workspace'); - return data.workspaces; }; @@ -37,6 +37,18 @@ export const useRenameWorkspace = () => { }); }; +export const useToggleAutoCapitalization = () => { + const queryClient = useQueryClient(); + + return useMutation<{}, {}, ToggleAutoCapitalizationDTO>({ + mutationFn: ({ workspaceID, state }) => + apiRequest.post(`/api/v2/workspace/${workspaceID}/settings`, { autoCapitalization: state }), + onSuccess: () => { + queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace); + } + }); +}; + export const useDeleteWorkspace = () => { const queryClient = useQueryClient(); diff --git a/frontend/src/hooks/api/workspace/types.ts b/frontend/src/hooks/api/workspace/types.ts index cc4709477..fd408999b 100644 --- a/frontend/src/hooks/api/workspace/types.ts +++ b/frontend/src/hooks/api/workspace/types.ts @@ -3,6 +3,7 @@ export type Workspace = { _id: string; name: string; organization: string; + autoCapitalization: boolean; environments: WorkspaceEnv[]; }; @@ -10,6 +11,7 @@ export type WorkspaceEnv = { name: string; slug: string }; // mutation dto export type RenameWorkspaceDTO = { workspaceID: string; newWorkspaceName: string }; +export type ToggleAutoCapitalizationDTO = { workspaceID: string; state: boolean }; export type DeleteWorkspaceDTO = { workspaceID: string }; diff --git a/frontend/src/pages/api/workspace/toggleAutoCapitalization.ts b/frontend/src/pages/api/workspace/toggleAutoCapitalization.ts deleted file mode 100644 index fa459d67a..000000000 --- a/frontend/src/pages/api/workspace/toggleAutoCapitalization.ts +++ /dev/null @@ -1,26 +0,0 @@ -import SecurityClient from '@app/components/utilities/SecurityClient'; - -/** - * This route lets us change the auto capitalization settings in a project. - * @param {*} req - * @param {*} res - * @returns - */ -const toggleAutoCapitalization = (workspaceId: string, state: boolean) => - SecurityClient.fetchCall(`/api/v2/workspace/${workspaceId}/settings`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - autoCapitalization: state - }) - }).then(async (res) => { - if (res && res.status === 200) { - return res; - } - console.log('Failed to toggle auto capitalization state'); - return undefined; - }); - -export default toggleAutoCapitalization; diff --git a/frontend/src/views/Settings/ProjectSettingsPage/ProjectSettingsPage.tsx b/frontend/src/views/Settings/ProjectSettingsPage/ProjectSettingsPage.tsx index 953a3d140..4fdd3d843 100644 --- a/frontend/src/views/Settings/ProjectSettingsPage/ProjectSettingsPage.tsx +++ b/frontend/src/views/Settings/ProjectSettingsPage/ProjectSettingsPage.tsx @@ -24,9 +24,11 @@ import { useGetUserWsKey, useGetUserWsServiceTokens, useRenameWorkspace, + useToggleAutoCapitalization, useUpdateWsEnvironment } from '@app/hooks/api'; +import { AutoCapitalizationSection } from './components/AutoCapitalizationSection/AutoCapitalizationSection'; import { CopyProjectIDSection, CreateServiceToken, @@ -39,6 +41,7 @@ import { export const ProjectSettingsPage = () => { const { t } = useTranslation(); const { currentWorkspace, workspaces } = useWorkspace(); + console.log(currentWorkspace); const router = useRouter(); const { data: serviceTokens } = useGetUserWsServiceTokens({ workspaceID: currentWorkspace?._id || '' @@ -50,6 +53,8 @@ export const ProjectSettingsPage = () => { const [isDeleting, setIsDeleting] = useToggle(); const renameWorkspace = useRenameWorkspace(); + const toggleAutoCapitalization = useToggleAutoCapitalization(); + const deleteWorkspace = useDeleteWorkspace(); // env crud operation const createWsEnv = useCreateWsEnvironment(); @@ -83,6 +88,26 @@ export const ProjectSettingsPage = () => { } }; + const onAutoCapitalizationToggle = async (state: boolean) => { + try { + await toggleAutoCapitalization.mutateAsync({ + workspaceID, + state + }); + const text = `Successfully ${state ? 'enabled' : 'disabled'} auto capitalization`; + createNotification({ + text, + type: 'success' + }); + } catch (error) { + console.error(error); + createNotification({ + text: 'Failed to update auto capitalization', + type: 'error' + }); + } + }; + const onDeleteWorkspace = async () => { setIsDeleting.on(); try { @@ -241,6 +266,10 @@ export const ProjectSettingsPage = () => { workspaceName={currentWorkspace?.name} onProjectNameChange={onRenameWorkspace} /> + Promise; +}; + +export const AutoCapitalizationSection = ({ + workspaceAutoCapitalization, + onAutoCapitalizationChange +}: Props) => { + const { t } = useTranslation(); + return ( +

+
+

+ {t('settings-project:auto-capitalization')} +

+ { + onAutoCapitalizationChange(state as boolean); + }} + > + {t('settings-project:auto-capitalization-description')} + +
+
+ ); +}; diff --git a/frontend/src/views/Settings/ProjectSettingsPage/components/AutoCapitalizationSection/index.tsx b/frontend/src/views/Settings/ProjectSettingsPage/components/AutoCapitalizationSection/index.tsx new file mode 100644 index 000000000..2b851428e --- /dev/null +++ b/frontend/src/views/Settings/ProjectSettingsPage/components/AutoCapitalizationSection/index.tsx @@ -0,0 +1 @@ +export { AutoCapitalizationSection } from './AutoCapitalizationSection'; \ No newline at end of file From a35e235744fac27e2058136de069baebc51a4d8b Mon Sep 17 00:00:00 2001 From: Hasan Mansoor <68682354+HasanMansoor4@users.noreply.github.com> Date: Sun, 5 Feb 2023 06:25:40 +0300 Subject: [PATCH 4/5] remove console log --- .../views/Settings/ProjectSettingsPage/ProjectSettingsPage.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/views/Settings/ProjectSettingsPage/ProjectSettingsPage.tsx b/frontend/src/views/Settings/ProjectSettingsPage/ProjectSettingsPage.tsx index 4fdd3d843..da89e9882 100644 --- a/frontend/src/views/Settings/ProjectSettingsPage/ProjectSettingsPage.tsx +++ b/frontend/src/views/Settings/ProjectSettingsPage/ProjectSettingsPage.tsx @@ -41,7 +41,6 @@ import { export const ProjectSettingsPage = () => { const { t } = useTranslation(); const { currentWorkspace, workspaces } = useWorkspace(); - console.log(currentWorkspace); const router = useRouter(); const { data: serviceTokens } = useGetUserWsServiceTokens({ workspaceID: currentWorkspace?._id || '' From 86fd8768509d5c4ef5d6b64bf9c9e93c4b804b76 Mon Sep 17 00:00:00 2001 From: Hasan Mansoor <68682354+HasanMansoor4@users.noreply.github.com> Date: Sun, 5 Feb 2023 20:51:53 +0300 Subject: [PATCH 5/5] change api from post to patch, fix spelling mistakes --- backend/src/controllers/v2/workspaceController.ts | 2 +- backend/src/routes/v2/workspace.ts | 6 +++--- frontend/src/hooks/api/workspace/queries.tsx | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/backend/src/controllers/v2/workspaceController.ts b/backend/src/controllers/v2/workspaceController.ts index ce3ecba31..55cd02fff 100644 --- a/backend/src/controllers/v2/workspaceController.ts +++ b/backend/src/controllers/v2/workspaceController.ts @@ -475,7 +475,7 @@ export const deleteWorkspaceMembership = async (req: Request, res: Response) => * @param res * @returns */ -export const toggleAutoCapitilzation = async (req: Request, res: Response) => { +export const toggleAutoCapitalization = async (req: Request, res: Response) => { let workspace; try { const { workspaceId } = req.params; diff --git a/backend/src/routes/v2/workspace.ts b/backend/src/routes/v2/workspace.ts index 4e48c9301..9a753badd 100644 --- a/backend/src/routes/v2/workspace.ts +++ b/backend/src/routes/v2/workspace.ts @@ -119,8 +119,8 @@ router.delete( // TODO - rewire dashboard to this route ); -router.post( - '/:workspaceId/settings', +router.patch( + '/:workspaceId/auto-capitalization', requireAuth({ acceptedAuthModes: ['jwt'] }), @@ -130,7 +130,7 @@ router.post( param('workspaceId').exists().trim(), body('autoCapitalization').exists().trim().notEmpty(), validateRequest, - workspaceController.toggleAutoCapitilzation + workspaceController.toggleAutoCapitalization ); export default router; diff --git a/frontend/src/hooks/api/workspace/queries.tsx b/frontend/src/hooks/api/workspace/queries.tsx index 64e4a905c..650058d5d 100644 --- a/frontend/src/hooks/api/workspace/queries.tsx +++ b/frontend/src/hooks/api/workspace/queries.tsx @@ -42,7 +42,7 @@ export const useToggleAutoCapitalization = () => { return useMutation<{}, {}, ToggleAutoCapitalizationDTO>({ mutationFn: ({ workspaceID, state }) => - apiRequest.post(`/api/v2/workspace/${workspaceID}/settings`, { autoCapitalization: state }), + apiRequest.patch(`/api/v2/workspace/${workspaceID}/auto-capitalization`, { autoCapitalization: state }), onSuccess: () => { queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace); }