mirror of
https://github.com/Infisical/infisical.git
synced 2025-07-09 01:45:33 +00:00
Compare commits
3 Commits
infisical/
...
feat/displ
Author | SHA1 | Date | |
---|---|---|---|
4a8dae5bb8 | |||
117617be78 | |||
ae928e225b |
@ -0,0 +1,19 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasColumn(TableName.Organization, "displayAllMembersInvite"))) {
|
||||||
|
await knex.schema.alterTable(TableName.Organization, (t) => {
|
||||||
|
t.boolean("displayAllMembersInvite").defaultTo(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
if (await knex.schema.hasColumn(TableName.Organization, "displayAllMembersInvite")) {
|
||||||
|
await knex.schema.alterTable(TableName.Organization, (t) => {
|
||||||
|
t.dropColumn("displayAllMembersInvite");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -22,7 +22,8 @@ export const OrganizationsSchema = z.object({
|
|||||||
kmsEncryptedDataKey: zodBuffer.nullable().optional(),
|
kmsEncryptedDataKey: zodBuffer.nullable().optional(),
|
||||||
defaultMembershipRole: z.string().default("member"),
|
defaultMembershipRole: z.string().default("member"),
|
||||||
enforceMfa: z.boolean().default(false),
|
enforceMfa: z.boolean().default(false),
|
||||||
selectedMfaMethod: z.string().nullable().optional()
|
selectedMfaMethod: z.string().nullable().optional(),
|
||||||
|
displayAllMembersInvite: z.boolean().default(true)
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TOrganizations = z.infer<typeof OrganizationsSchema>;
|
export type TOrganizations = z.infer<typeof OrganizationsSchema>;
|
||||||
|
@ -257,7 +257,8 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
|
|||||||
scimEnabled: z.boolean().optional(),
|
scimEnabled: z.boolean().optional(),
|
||||||
defaultMembershipRoleSlug: slugSchema({ max: 64, field: "Default Membership Role" }).optional(),
|
defaultMembershipRoleSlug: slugSchema({ max: 64, field: "Default Membership Role" }).optional(),
|
||||||
enforceMfa: z.boolean().optional(),
|
enforceMfa: z.boolean().optional(),
|
||||||
selectedMfaMethod: z.nativeEnum(MfaMethod).optional()
|
selectedMfaMethod: z.nativeEnum(MfaMethod).optional(),
|
||||||
|
displayAllMembersInvite: z.boolean().optional()
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
|
@ -286,7 +286,16 @@ export const orgServiceFactory = ({
|
|||||||
actorOrgId,
|
actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
orgId,
|
orgId,
|
||||||
data: { name, slug, authEnforced, scimEnabled, defaultMembershipRoleSlug, enforceMfa, selectedMfaMethod }
|
data: {
|
||||||
|
name,
|
||||||
|
slug,
|
||||||
|
authEnforced,
|
||||||
|
scimEnabled,
|
||||||
|
defaultMembershipRoleSlug,
|
||||||
|
enforceMfa,
|
||||||
|
selectedMfaMethod,
|
||||||
|
displayAllMembersInvite
|
||||||
|
}
|
||||||
}: TUpdateOrgDTO) => {
|
}: TUpdateOrgDTO) => {
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
||||||
@ -358,7 +367,8 @@ export const orgServiceFactory = ({
|
|||||||
scimEnabled,
|
scimEnabled,
|
||||||
defaultMembershipRole,
|
defaultMembershipRole,
|
||||||
enforceMfa,
|
enforceMfa,
|
||||||
selectedMfaMethod
|
selectedMfaMethod,
|
||||||
|
displayAllMembersInvite
|
||||||
});
|
});
|
||||||
if (!org) throw new NotFoundError({ message: `Organization with ID '${orgId}' not found` });
|
if (!org) throw new NotFoundError({ message: `Organization with ID '${orgId}' not found` });
|
||||||
return org;
|
return org;
|
||||||
|
@ -72,6 +72,7 @@ export type TUpdateOrgDTO = {
|
|||||||
defaultMembershipRoleSlug: string;
|
defaultMembershipRoleSlug: string;
|
||||||
enforceMfa: boolean;
|
enforceMfa: boolean;
|
||||||
selectedMfaMethod: MfaMethod;
|
selectedMfaMethod: MfaMethod;
|
||||||
|
displayAllMembersInvite: boolean;
|
||||||
}>;
|
}>;
|
||||||
} & TOrgPermission;
|
} & TOrgPermission;
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ const formSchema = z.object({
|
|||||||
.trim()
|
.trim()
|
||||||
.max(256, "Description too long, max length is 256 characters")
|
.max(256, "Description too long, max length is 256 characters")
|
||||||
.optional(),
|
.optional(),
|
||||||
addMembers: z.boolean(),
|
addMembers: z.boolean().default(false),
|
||||||
kmsKeyId: z.string(),
|
kmsKeyId: z.string(),
|
||||||
template: z.string()
|
template: z.string()
|
||||||
});
|
});
|
||||||
@ -246,30 +246,32 @@ const NewProjectForm = ({ onOpenChange, projectType }: NewProjectFormProps) => {
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-4 pl-1">
|
{currentOrg?.displayAllMembersInvite && (
|
||||||
<Controller
|
<div className="mt-4 pl-1">
|
||||||
control={control}
|
<Controller
|
||||||
name="addMembers"
|
control={control}
|
||||||
defaultValue={false}
|
name="addMembers"
|
||||||
render={({ field: { onBlur, value, onChange } }) => (
|
defaultValue={false}
|
||||||
<OrgPermissionCan I={OrgPermissionActions.Read} a={OrgPermissionSubjects.Member}>
|
render={({ field: { onBlur, value, onChange } }) => (
|
||||||
{(isAllowed) => (
|
<OrgPermissionCan I={OrgPermissionActions.Read} a={OrgPermissionSubjects.Member}>
|
||||||
<div>
|
{(isAllowed) => (
|
||||||
<Checkbox
|
<div>
|
||||||
id="add-project-layout"
|
<Checkbox
|
||||||
isChecked={value}
|
id="add-project-layout"
|
||||||
onCheckedChange={onChange}
|
isChecked={value}
|
||||||
isDisabled={!isAllowed}
|
onCheckedChange={onChange}
|
||||||
onBlur={onBlur}
|
isDisabled={!isAllowed}
|
||||||
>
|
onBlur={onBlur}
|
||||||
Add all members of my organization to this project
|
>
|
||||||
</Checkbox>
|
Add all members of my organization to this project
|
||||||
</div>
|
</Checkbox>
|
||||||
)}
|
</div>
|
||||||
</OrgPermissionCan>
|
)}
|
||||||
)}
|
</OrgPermissionCan>
|
||||||
/>
|
)}
|
||||||
</div>
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div className="mt-14 flex">
|
<div className="mt-14 flex">
|
||||||
<Accordion type="single" collapsible className="w-full">
|
<Accordion type="single" collapsible className="w-full">
|
||||||
<AccordionItem value="advance-settings" className="data-[state=open]:border-none">
|
<AccordionItem value="advance-settings" className="data-[state=open]:border-none">
|
||||||
|
@ -109,7 +109,8 @@ export const useUpdateOrg = () => {
|
|||||||
orgId,
|
orgId,
|
||||||
defaultMembershipRoleSlug,
|
defaultMembershipRoleSlug,
|
||||||
enforceMfa,
|
enforceMfa,
|
||||||
selectedMfaMethod
|
selectedMfaMethod,
|
||||||
|
displayAllMembersInvite
|
||||||
}) => {
|
}) => {
|
||||||
return apiRequest.patch(`/api/v1/organization/${orgId}`, {
|
return apiRequest.patch(`/api/v1/organization/${orgId}`, {
|
||||||
name,
|
name,
|
||||||
@ -118,7 +119,8 @@ export const useUpdateOrg = () => {
|
|||||||
slug,
|
slug,
|
||||||
defaultMembershipRoleSlug,
|
defaultMembershipRoleSlug,
|
||||||
enforceMfa,
|
enforceMfa,
|
||||||
selectedMfaMethod
|
selectedMfaMethod,
|
||||||
|
displayAllMembersInvite
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
|
@ -15,6 +15,7 @@ export type Organization = {
|
|||||||
defaultMembershipRole: string;
|
defaultMembershipRole: string;
|
||||||
enforceMfa: boolean;
|
enforceMfa: boolean;
|
||||||
selectedMfaMethod?: MfaMethod;
|
selectedMfaMethod?: MfaMethod;
|
||||||
|
displayAllMembersInvite?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type UpdateOrgDTO = {
|
export type UpdateOrgDTO = {
|
||||||
@ -26,6 +27,7 @@ export type UpdateOrgDTO = {
|
|||||||
defaultMembershipRoleSlug?: string;
|
defaultMembershipRoleSlug?: string;
|
||||||
enforceMfa?: boolean;
|
enforceMfa?: boolean;
|
||||||
selectedMfaMethod?: MfaMethod;
|
selectedMfaMethod?: MfaMethod;
|
||||||
|
displayAllMembersInvite?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type BillingDetails = {
|
export type BillingDetails = {
|
||||||
|
@ -11,6 +11,7 @@ import { OrgAuthTab } from "../OrgAuthTab";
|
|||||||
import { OrgEncryptionTab } from "../OrgEncryptionTab";
|
import { OrgEncryptionTab } from "../OrgEncryptionTab";
|
||||||
import { OrgGeneralTab } from "../OrgGeneralTab";
|
import { OrgGeneralTab } from "../OrgGeneralTab";
|
||||||
import { OrgWorkflowIntegrationTab } from "../OrgWorkflowIntegrationTab/OrgWorkflowIntegrationTab";
|
import { OrgWorkflowIntegrationTab } from "../OrgWorkflowIntegrationTab/OrgWorkflowIntegrationTab";
|
||||||
|
import { ProductSettings } from "../ProductSettings/ProductSettings";
|
||||||
import { ProjectTemplatesTab } from "../ProjectTemplatesTab";
|
import { ProjectTemplatesTab } from "../ProjectTemplatesTab";
|
||||||
|
|
||||||
export const OrgTabGroup = () => {
|
export const OrgTabGroup = () => {
|
||||||
@ -20,6 +21,7 @@ export const OrgTabGroup = () => {
|
|||||||
const tabs = [
|
const tabs = [
|
||||||
{ name: "General", key: "tab-org-general", component: OrgGeneralTab },
|
{ name: "General", key: "tab-org-general", component: OrgGeneralTab },
|
||||||
{ name: "Security", key: "tab-org-security", component: OrgAuthTab },
|
{ name: "Security", key: "tab-org-security", component: OrgAuthTab },
|
||||||
|
{ name: "Products", key: "tab-org-products", component: ProductSettings },
|
||||||
{ name: "Encryption", key: "tab-org-encryption", component: OrgEncryptionTab },
|
{ name: "Encryption", key: "tab-org-encryption", component: OrgEncryptionTab },
|
||||||
{
|
{
|
||||||
name: "Workflow Integrations",
|
name: "Workflow Integrations",
|
||||||
|
@ -0,0 +1,69 @@
|
|||||||
|
import { createNotification } from "@app/components/notifications";
|
||||||
|
import { OrgPermissionCan } from "@app/components/permissions";
|
||||||
|
import { ContentLoader, Switch } from "@app/components/v2";
|
||||||
|
import { OrgPermissionActions, OrgPermissionSubjects, useOrganization } from "@app/context";
|
||||||
|
import { useUpdateOrg } from "@app/hooks/api";
|
||||||
|
|
||||||
|
const ProductConfigSection = () => {
|
||||||
|
const { currentOrg } = useOrganization();
|
||||||
|
const { mutateAsync } = useUpdateOrg();
|
||||||
|
|
||||||
|
const handleDisplayAllMembersInviteToggle = async (value: boolean) => {
|
||||||
|
try {
|
||||||
|
if (!currentOrg?.id) return;
|
||||||
|
|
||||||
|
await mutateAsync({
|
||||||
|
orgId: currentOrg?.id,
|
||||||
|
displayAllMembersInvite: value
|
||||||
|
});
|
||||||
|
|
||||||
|
createNotification({
|
||||||
|
text: `Successfully ${value ? "enabled" : "disabled"} display all members invite`,
|
||||||
|
type: "success"
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
createNotification({
|
||||||
|
text: "Failed to update setting",
|
||||||
|
type: "error"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!currentOrg) {
|
||||||
|
return <ContentLoader />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mb-4 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-6">
|
||||||
|
<div className="py-4">
|
||||||
|
<div className="mb-2 flex justify-between">
|
||||||
|
<h3 className="text-md text-mineshaft-100">
|
||||||
|
Display All Members Invite on Project Creation
|
||||||
|
</h3>
|
||||||
|
<OrgPermissionCan I={OrgPermissionActions.Edit} a={OrgPermissionSubjects.Settings}>
|
||||||
|
{(isAllowed) => (
|
||||||
|
<Switch
|
||||||
|
id="display-all-members-invite"
|
||||||
|
onCheckedChange={(value) => handleDisplayAllMembersInviteToggle(value)}
|
||||||
|
isChecked={currentOrg?.displayAllMembersInvite ?? false}
|
||||||
|
isDisabled={!isAllowed}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</OrgPermissionCan>
|
||||||
|
</div>
|
||||||
|
<p className="text-sm text-mineshaft-300">
|
||||||
|
Control whether to display all members in the invite section on project creation
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ProductSettings = () => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<ProductConfigSection />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
Reference in New Issue
Block a user