Merge pull request #292 from HasanMansoor4/auto-capitalization-toggle

Auto capitalization toggle for secrets
This commit is contained in:
mv-turtle
2023-02-07 21:55:05 -08:00
committed by GitHub
15 changed files with 158 additions and 3 deletions
@@ -468,3 +468,41 @@ export const deleteWorkspaceMembership = async (req: Request, res: Response) =>
membership membership
}); });
} }
/**
* Change autoCapitilzation Rule of workspace
* @param req
* @param res
* @returns
*/
export const toggleAutoCapitalization = 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
});
};
+5
View File
@@ -8,6 +8,7 @@ export interface IWorkspace {
name: string; name: string;
slug: string; slug: string;
}>; }>;
autoCapitalization: boolean;
} }
const workspaceSchema = new Schema<IWorkspace>({ const workspaceSchema = new Schema<IWorkspace>({
@@ -15,6 +16,10 @@ const workspaceSchema = new Schema<IWorkspace>({
type: String, type: String,
required: true required: true
}, },
autoCapitalization: {
type: Boolean,
default: true,
},
organization: { organization: {
type: Schema.Types.ObjectId, type: Schema.Types.ObjectId,
ref: 'Organization', ref: 'Organization',
+15
View File
@@ -118,4 +118,19 @@ router.delete( // TODO - rewire dashboard to this route
workspaceController.deleteWorkspaceMembership workspaceController.deleteWorkspaceMembership
); );
router.patch(
'/:workspaceId/auto-capitalization',
requireAuth({
acceptedAuthModes: ['jwt']
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER]
}),
param('workspaceId').exists().trim(),
body('autoCapitalization').exists().trim().notEmpty(),
validateRequest,
workspaceController.toggleAutoCapitalization
);
export default router; export default router;
@@ -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-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 ", "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.", "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."
} }
@@ -14,6 +14,7 @@ interface DashboardInputFieldProps {
type: 'varName' | 'value' | 'comment'; type: 'varName' | 'value' | 'comment';
blurred?: boolean; blurred?: boolean;
isDuplicate?: boolean; isDuplicate?: boolean;
isCapitalized?: boolean;
overrideEnabled?: boolean; overrideEnabled?: boolean;
modifyValueOverride?: (value: string | undefined, position: number) => void; modifyValueOverride?: (value: string | undefined, position: number) => void;
isSideBarOpen?: boolean; isSideBarOpen?: boolean;
@@ -41,6 +42,7 @@ const DashboardInputField = ({
value, value,
blurred, blurred,
isDuplicate, isDuplicate,
isCapitalized,
overrideEnabled, overrideEnabled,
modifyValueOverride, modifyValueOverride,
isSideBarOpen isSideBarOpen
@@ -69,7 +71,7 @@ const DashboardInputField = ({
}`} }`}
> >
<input <input
onChange={(e) => onChangeHandler(e.target.value.toUpperCase(), position)} onChange={(e) => onChangeHandler(isCapitalized ? e.target.value.toUpperCase() : e.target.value, position)}
type={type} type={type}
value={value} value={value}
className={`z-10 peer font-mono ph-no-capture bg-transparent h-full caret-bunker-200 text-sm px-2 w-full min-w-16 outline-none ${ className={`z-10 peer font-mono ph-no-capture bg-transparent h-full caret-bunker-200 text-sm px-2 w-full min-w-16 outline-none ${
@@ -230,6 +232,7 @@ function inputPropsAreEqual(prev: DashboardInputFieldProps, next: DashboardInput
prev.type === next.type && prev.type === next.type &&
prev.position === next.position && prev.position === next.position &&
prev.blurred === next.blurred && prev.blurred === next.blurred &&
prev.isCapitalized === next.isCapitalized &&
prev.overrideEnabled === next.overrideEnabled && prev.overrideEnabled === next.overrideEnabled &&
prev.isDuplicate === next.isDuplicate && prev.isDuplicate === next.isDuplicate &&
prev.isSideBarOpen === next.isSideBarOpen prev.isSideBarOpen === next.isSideBarOpen
@@ -18,6 +18,7 @@ interface KeyPairProps {
toggleSidebar: (id: string) => void; toggleSidebar: (id: string) => void;
sidebarSecretId: string; sidebarSecretId: string;
isSnapshot: boolean; isSnapshot: boolean;
isCapitalized: boolean;
deleteRow?: (props: DeleteRowFunctionProps) => void; deleteRow?: (props: DeleteRowFunctionProps) => void;
tags: Tag[]; tags: Tag[];
togglePITSidebar?: (value: boolean) => void; togglePITSidebar?: (value: boolean) => void;
@@ -75,6 +76,7 @@ const KeyPair = ({
isDuplicate, isDuplicate,
toggleSidebar, toggleSidebar,
sidebarSecretId, sidebarSecretId,
isCapitalized,
isSnapshot, isSnapshot,
deleteRow, deleteRow,
togglePITSidebar, togglePITSidebar,
@@ -97,6 +99,7 @@ const KeyPair = ({
<div className='text-bunker-400 text-xs flex items-center justify-center w-14 h-10 cursor-default'>{keyPair.pos + 1}</div> <div className='text-bunker-400 text-xs flex items-center justify-center w-14 h-10 cursor-default'>{keyPair.pos + 1}</div>
<div className="flex items-center max-h-16"> <div className="flex items-center max-h-16">
<DashboardInputField <DashboardInputField
isCapitalized = {isCapitalized}
onChangeHandler={modifyKey} onChangeHandler={modifyKey}
type="varName" type="varName"
position={keyPair.pos} position={keyPair.pos}
@@ -5,4 +5,6 @@ export {
useGetUserWorkspaces, useGetUserWorkspaces,
useGetWorkspaceById, useGetWorkspaceById,
useRenameWorkspace, useRenameWorkspace,
useToggleAutoCapitalization,
useUpdateWsEnvironment} from './queries'; useUpdateWsEnvironment} from './queries';
@@ -7,6 +7,7 @@ import {
DeleteEnvironmentDTO, DeleteEnvironmentDTO,
DeleteWorkspaceDTO, DeleteWorkspaceDTO,
RenameWorkspaceDTO, RenameWorkspaceDTO,
ToggleAutoCapitalizationDTO,
UpdateEnvironmentDTO, UpdateEnvironmentDTO,
Workspace Workspace
} from './types'; } from './types';
@@ -51,6 +52,18 @@ export const useRenameWorkspace = () => {
}); });
}; };
export const useToggleAutoCapitalization = () => {
const queryClient = useQueryClient();
return useMutation<{}, {}, ToggleAutoCapitalizationDTO>({
mutationFn: ({ workspaceID, state }) =>
apiRequest.patch(`/api/v2/workspace/${workspaceID}/auto-capitalization`, { autoCapitalization: state }),
onSuccess: () => {
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace);
}
});
};
export const useDeleteWorkspace = () => { export const useDeleteWorkspace = () => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
@@ -3,6 +3,7 @@ export type Workspace = {
_id: string; _id: string;
name: string; name: string;
organization: string; organization: string;
autoCapitalization: boolean;
environments: WorkspaceEnv[]; environments: WorkspaceEnv[];
}; };
@@ -11,6 +12,7 @@ export type WorkspaceTag = { _id: string; name: string; slug: string };
// mutation dto // mutation dto
export type RenameWorkspaceDTO = { workspaceID: string; newWorkspaceName: string }; export type RenameWorkspaceDTO = { workspaceID: string; newWorkspaceName: string };
export type ToggleAutoCapitalizationDTO = { workspaceID: string; state: boolean };
export type DeleteWorkspaceDTO = { workspaceID: string }; export type DeleteWorkspaceDTO = { workspaceID: string };
@@ -4,6 +4,7 @@ interface Workspace {
__v: number; __v: number;
_id: string; _id: string;
name: string; name: string;
autoCapitalization: boolean;
organization: string; organization: string;
environments: Array<{ name: string; slug: string }>; environments: Array<{ name: string; slug: string }>;
} }
+4
View File
@@ -132,6 +132,7 @@ export default function Dashboard() {
const [snapshotData, setSnapshotData] = useState<SnapshotProps>(); const [snapshotData, setSnapshotData] = useState<SnapshotProps>();
const [numSnapshots, setNumSnapshots] = useState<number>(); const [numSnapshots, setNumSnapshots] = useState<number>();
const [saveLoading, setSaveLoading] = useState(false); const [saveLoading, setSaveLoading] = useState(false);
const [autoCapitalization, setAutoCapitalization] = useState(false);
const [dropZoneData, setDropZoneData] = useState<SecretDataProps[]>(); const [dropZoneData, setDropZoneData] = useState<SecretDataProps[]>();
const [projectTags, setProjectTags] = useState<Tag[]>([]); const [projectTags, setProjectTags] = useState<Tag[]>([]);
@@ -224,6 +225,7 @@ export default function Dashboard() {
if (!workspace) { if (!workspace) {
router.push(`/dashboard/${userWorkspaces?.[0]?._id}`); router.push(`/dashboard/${userWorkspaces?.[0]?._id}`);
} }
setAutoCapitalization(workspace?.autoCapitalization ?? true);
const accessibleEnvironments = await getWorkspaceEnvironments({ workspaceId }); const accessibleEnvironments = await getWorkspaceEnvironments({ workspaceId });
setWorkspaceEnvs(accessibleEnvironments || []); setWorkspaceEnvs(accessibleEnvironments || []);
@@ -874,6 +876,7 @@ export default function Dashboard() {
.filter((row) => !sharedToHide.includes(row.id)) .filter((row) => !sharedToHide.includes(row.id))
.map((keyPair) => ( .map((keyPair) => (
<KeyPair <KeyPair
isCapitalized={autoCapitalization}
key={keyPair.id} key={keyPair.id}
keyPair={keyPair} keyPair={keyPair}
modifyValue={listenChangeValue} modifyValue={listenChangeValue}
@@ -916,6 +919,7 @@ export default function Dashboard() {
) )
.map((keyPair) => ( .map((keyPair) => (
<KeyPair <KeyPair
isCapitalized={autoCapitalization}
key={keyPair.id} key={keyPair.id}
keyPair={keyPair} keyPair={keyPair}
modifyValue={listenChangeValue} modifyValue={listenChangeValue}
@@ -13,6 +13,7 @@ const ProjectSettings = () => {
<title>{t('common:head-title', { title: t('settings-project:title') })}</title> <title>{t('common:head-title', { title: t('settings-project:title') })}</title>
<link rel="icon" href="/infisical.ico" /> <link rel="icon" href="/infisical.ico" />
</Head> </Head>
<ProjectSettingsPage /> <ProjectSettingsPage />
</> </>
); );
@@ -27,10 +27,15 @@ import {
useGetUserWsServiceTokens, useGetUserWsServiceTokens,
useGetWsTags, useGetWsTags,
useRenameWorkspace, useRenameWorkspace,
useToggleAutoCapitalization,
useUpdateWsEnvironment useUpdateWsEnvironment
} from '@app/hooks/api'; } from '@app/hooks/api';
import { AutoCapitalizationSection } from './components/AutoCapitalizationSection/AutoCapitalizationSection';
import { SecretTagsSection } from './components/SecretTagsSection'; import { SecretTagsSection } from './components/SecretTagsSection';
import { import {
CopyProjectIDSection, CopyProjectIDSection,
CreateServiceToken, CreateServiceToken,
@@ -55,6 +60,8 @@ export const ProjectSettingsPage = () => {
const [isDeleting, setIsDeleting] = useToggle(); const [isDeleting, setIsDeleting] = useToggle();
const renameWorkspace = useRenameWorkspace(); const renameWorkspace = useRenameWorkspace();
const toggleAutoCapitalization = useToggleAutoCapitalization();
const deleteWorkspace = useDeleteWorkspace(); const deleteWorkspace = useDeleteWorkspace();
// env crud operation // env crud operation
const createWsEnv = useCreateWsEnvironment(); const createWsEnv = useCreateWsEnvironment();
@@ -93,6 +100,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 () => { const onDeleteWorkspace = async () => {
setIsDeleting.on(); setIsDeleting.on();
try { try {
@@ -289,6 +316,10 @@ export const ProjectSettingsPage = () => {
workspaceName={currentWorkspace?.name} workspaceName={currentWorkspace?.name}
onProjectNameChange={onRenameWorkspace} onProjectNameChange={onRenameWorkspace}
/> />
<AutoCapitalizationSection
workspaceAutoCapitalization={currentWorkspace?.autoCapitalization}
onAutoCapitalizationChange={onAutoCapitalizationToggle}
/>
<CopyProjectIDSection workspaceID={currentWorkspace?._id || ''} /> <CopyProjectIDSection workspaceID={currentWorkspace?._id || ''} />
<EnvironmentSection <EnvironmentSection
environments={currentWorkspace?.environments || []} environments={currentWorkspace?.environments || []}
@@ -0,0 +1,34 @@
import { useTranslation } from 'react-i18next';
import { Checkbox } from '@app/components/v2';
type Props = {
workspaceAutoCapitalization?: boolean;
onAutoCapitalizationChange: (state: boolean) => Promise<void>;
};
export const AutoCapitalizationSection = ({
workspaceAutoCapitalization,
onAutoCapitalizationChange
}: Props) => {
const { t } = useTranslation();
return (
<form>
<div className="mb-2 flex w-full flex-col items-start rounded-md bg-white/5 px-6 pb-6 pt-2">
<p className="mb-4 mt-2 text-xl font-semibold">
{t('settings-project:auto-capitalization')}
</p>
<Checkbox
className="data-[state=checked]:bg-primary"
id="autoCapitalization"
isChecked={workspaceAutoCapitalization}
onCheckedChange={(state) => {
onAutoCapitalizationChange(state as boolean);
}}
>
{t('settings-project:auto-capitalization-description')}
</Checkbox>
</div>
</form>
);
};
@@ -0,0 +1 @@
export { AutoCapitalizationSection } from './AutoCapitalizationSection';