Skip to content

Commit

Permalink
Configure default role for new joiners (#19701)
Browse files Browse the repository at this point in the history
  • Loading branch information
svenefftinge authored May 6, 2024
1 parent c94d59e commit 30d5e2f
Show file tree
Hide file tree
Showing 15 changed files with 498 additions and 353 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type UpdateOrganizationSettingsArgs = Partial<
| "allowedWorkspaceClasses"
| "pinnedEditorVersions"
| "restrictedEditorNames"
| "defaultRole"
>
>;

Expand All @@ -36,6 +37,7 @@ export const useUpdateOrgSettingsMutation = () => {
allowedWorkspaceClasses,
pinnedEditorVersions,
restrictedEditorNames,
defaultRole,
}) => {
const settings = await organizationClient.updateOrganizationSettings({
organizationId: teamId,
Expand All @@ -46,6 +48,7 @@ export const useUpdateOrgSettingsMutation = () => {
pinnedEditorVersions,
restrictedEditorNames,
updateRestrictedEditorNames: !!restrictedEditorNames,
defaultRole,
});
return settings.settings!;
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import {
import { getGitpodService } from "./service";
import { converter } from "./public-api";
import { ApplicationError, ErrorCodes } from "@gitpod/gitpod-protocol/lib/messaging/error";
import { OrgMemberRole } from "@gitpod/gitpod-protocol";

export class JsonRpcOrganizationClient implements PromiseClient<typeof OrganizationService> {
async createOrganization(
Expand Down Expand Up @@ -232,6 +233,7 @@ export class JsonRpcOrganizationClient implements PromiseClient<typeof Organizat
defaultWorkspaceImage: request?.defaultWorkspaceImage,
allowedWorkspaceClasses: request?.allowedWorkspaceClasses,
restrictedEditorNames: request?.restrictedEditorNames,
defaultRole: request?.defaultRole,
};
if (request.updatePinnedEditorVersions) {
update.pinnedEditorVersions = request.pinnedEditorVersions;
Expand All @@ -249,7 +251,10 @@ export class JsonRpcOrganizationClient implements PromiseClient<typeof Organizat
"updateRestrictedEditorNames is required to be true to update restrictedEditorNames",
);
}
await getGitpodService().server.updateOrgSettings(request.organizationId, update);
await getGitpodService().server.updateOrgSettings(request.organizationId, {
...update,
defaultRole: request.defaultRole as OrgMemberRole,
});
return new UpdateOrganizationSettingsResponse();
}
}
7 changes: 1 addition & 6 deletions components/dashboard/src/teams/Members.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import { useListOrganizationMembers, useOrganizationMembersInvalidator } from ".
import { useInvitationId, useInviteInvalidator } from "../data/organizations/invite-query";
import { Delayed } from "@podkit/loading/Delayed";
import { Button } from "@podkit/buttons/Button";
import { useIsDataOps } from "../data/featureflag-query";

function getHumanReadable(role: OrganizationRole): string {
return OrganizationRole[role].toLowerCase();
Expand All @@ -46,8 +45,6 @@ export default function MembersPage() {
const [memberToRemove, setMemberToRemove] = useState<OrganizationMember | undefined>(undefined);
const inviteId = useInvitationId().data;

const isDataOps = useIsDataOps();

const inviteUrl = useMemo(() => {
if (!org.data) {
return undefined;
Expand Down Expand Up @@ -265,9 +262,7 @@ export default function MembersPage() {
<ModalBody>
<InputField
label="Invite URL"
hint={`Use this URL to join this organization as a ${
isDataOps ? "collaborator" : "member"
}.`}
hint={`Share this URL to allow others to join this organization.`}
>
<InputWithCopy value={inviteUrl} tip="Copy Invite URL" />
</InputField>
Expand Down
24 changes: 24 additions & 0 deletions components/dashboard/src/teams/TeamSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import { useMutation } from "@tanstack/react-query";
import { useAllowedWorkspaceEditorsMemo } from "../data/ide-options/ide-options-query";
import { IdeOptions, IdeOptionsModifyModal, IdeOptionsModifyModalProps } from "../components/IdeOptions";
import { useFeatureFlag } from "../data/featureflag-query";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@podkit/select/Select";

export default function TeamSettingsPage() {
const user = useCurrentUser();
Expand Down Expand Up @@ -172,6 +173,29 @@ export default function TeamSettingsPage() {
)}
</ConfigurationSettingsField>

<ConfigurationSettingsField>
<Heading3>Default role for joiners</Heading3>
<Subheading className="mb-4">Choose the initial role for new members.</Subheading>
<Select
value={`${settings?.defaultRole || "member"}`}
onValueChange={(value) => handleUpdateTeamSettings({ defaultRole: value })}
disabled={isLoading || !isOwner}
>
<SelectTrigger className="w-60">
<SelectValue placeholder="Select a branch filter" />
</SelectTrigger>
<SelectContent>
<SelectItem value={`owner`}>
Owner - Can fully manage org and repository settings
</SelectItem>
<SelectItem value={`member`}>Member - Can view repository settings</SelectItem>
<SelectItem value={`collaborator`}>
Collaborator - Can only create workspaces
</SelectItem>
</SelectContent>
</Select>
</ConfigurationSettingsField>

<ConfigurationSettingsField>
<Heading3>Collaboration and sharing</Heading3>

Expand Down
5 changes: 4 additions & 1 deletion components/gitpod-db/src/typeorm/entity/db-team-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* See License.AGPL.txt in the project root for license information.
*/

import { OrganizationSettings } from "@gitpod/gitpod-protocol";
import { OrgMemberRole, OrganizationSettings } from "@gitpod/gitpod-protocol";
import { Entity, Column, PrimaryColumn } from "typeorm";
import { TypeORM } from "../typeorm";

Expand All @@ -30,6 +30,9 @@ export class DBOrgSettings implements OrganizationSettings {
@Column("json", { nullable: true })
restrictedEditorNames?: string[] | null;

@Column("varchar", { nullable: true })
defaultRole?: OrgMemberRole | undefined;

@Column()
deleted: boolean;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* Copyright (c) 2024 Gitpod GmbH. All rights reserved.
* Licensed under the GNU Affero General Public License (AGPL).
* See License.AGPL.txt in the project root for license information.
*/

import { MigrationInterface, QueryRunner } from "typeorm";
import { columnExists } from "./helper/helper";

const table = "d_b_org_settings";
const newColumn = "defaultRole";

export class OrgSettingDefaultRole1714741006746 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
if (!(await columnExists(queryRunner, table, newColumn))) {
await queryRunner.query(`ALTER TABLE ${table} ADD COLUMN ${newColumn} varchar(64) NULL`);
}
}

public async down(queryRunner: QueryRunner): Promise<void> {}
}
1 change: 1 addition & 0 deletions components/gitpod-db/src/typeorm/team-db-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ export class TeamDBImpl extends TransactionalDBImpl<TeamDB> implements TeamDB {
"allowedWorkspaceClasses",
"pinnedEditorVersions",
"restrictedEditorNames",
"defaultRole",
],
});
}
Expand Down
3 changes: 3 additions & 0 deletions components/gitpod-protocol/src/teams-projects-protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,9 @@ export interface OrganizationSettings {
pinnedEditorVersions?: { [key: string]: string } | null;

restrictedEditorNames?: string[] | null;

// what role new members will get, default is "member"
defaultRole?: OrgMemberRole;
}

export type TeamMemberRole = OrgMemberRole;
Expand Down
19 changes: 13 additions & 6 deletions components/public-api/gitpod/v1/organization.proto
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ message OrganizationSettings {
repeated string allowed_workspace_classes = 3;
repeated string restricted_editor_names = 4;
map<string, string> pinned_editor_versions = 5;
string default_role = 6;
}

service OrganizationService {
Expand Down Expand Up @@ -121,23 +122,29 @@ message UpdateOrganizationSettingsRequest {
// pass empty string to reset to the installation default workspace image
optional string default_workspace_image = 4;

// allowed_workspace_classes are the IDs of classes, which can be used by workspaces in an organization.
// Pass an empty array to allow all workspace classes
// allowed_workspace_classes are the IDs of classes, which can be used by
// workspaces in an organization. Pass an empty array to allow all workspace
// classes
repeated string allowed_workspace_classes = 5;

// restricted_editor_names updates the list of restricted editor names that are not allowed to be used by workspaces in an organization.
// If empty, all editors are allowed.
// Only updates if update_restricted_editor_names is true.
// restricted_editor_names updates the list of restricted editor names that
// are not allowed to be used by workspaces in an organization. If empty, all
// editors are allowed. Only updates if update_restricted_editor_names is
// true.
repeated string restricted_editor_names = 6;

// Specifies whether restricted_workspace_classes should be updated.
optional bool update_restricted_editor_names = 7;

// pinned_editor_versions updates the pinned version for the corresponding editor.
// pinned_editor_versions updates the pinned version for the corresponding
// editor.
map<string, string> pinned_editor_versions = 8;

// Specifies whether pinned_editor_versions should be updated.
optional bool update_pinned_editor_versions = 9;

// default_role is the default role for new members in the organization.
optional string default_role = 10;
}

message UpdateOrganizationSettingsResponse {
Expand Down
Loading

0 comments on commit 30d5e2f

Please sign in to comment.