mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 16:27:40 +00:00
Merge pull request #292 from HasanMansoor4/auto-capitalization-toggle
Auto capitalization toggle for secrets
This commit is contained in:
@@ -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
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
@@ -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 }>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 || []}
|
||||||
|
|||||||
+34
@@ -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>
|
||||||
|
);
|
||||||
|
};
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
export { AutoCapitalizationSection } from './AutoCapitalizationSection';
|
||||||
Reference in New Issue
Block a user