Skip to content

Commit 6be9911

Browse files
committed
project/collaborators: implement ownership management -- #7718
1 parent f5f0ddf commit 6be9911

File tree

6 files changed

+891
-4
lines changed

6 files changed

+891
-4
lines changed

src/packages/frontend/client/project-collaborators.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
* License: MS-RSL – see LICENSE.md for details
44
*/
55

6+
// cSpell:ignore replyto collabs noncloud
7+
68
import type { ConatClient } from "@cocalc/frontend/conat/client";
79
import type { AddCollaborator } from "@cocalc/conat/hub/api/projects";
810

@@ -57,7 +59,7 @@ export class ProjectCollaborators {
5759
public async add_collaborator(
5860
opts: AddCollaborator,
5961
): Promise<{ project_id?: string | string[] }> {
60-
// project_id is a single string or possibly an array of project_id's
62+
// project_id is a single string or possibly an array of project_id's
6163
// in case of a token.
6264
return await this.conat.hub.projects.addCollaborator({
6365
opts,

src/packages/frontend/collaborators/current-collabs.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
* License: MS-RSL – see LICENSE.md for details
44
*/
55

6+
// cSpell:ignore replyto collabs noncloud
7+
68
import { Button, Card, Popconfirm } from "antd";
79
import React from "react";
810
import { FormattedMessage, useIntl } from "react-intl";
@@ -40,7 +42,7 @@ export const CurrentCollaboratorsPanel: React.FC<Props> = (props: Props) => {
4042
const project_id = project.get("project_id");
4143
redux.getActions("projects").remove_collaborator(project_id, account_id);
4244
if (account_id === get_account_id()) {
43-
(redux.getActions("page") as any).close_project_tab(project_id);
45+
(redux.getActions("page") as any).close_project_tab(project_id);
4446
// TODO: better types
4547
}
4648
}

src/packages/frontend/projects/actions.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ import type {
4141
} from "@cocalc/util/db-schema/projects";
4242
export type { Datastore, EnvVars, EnvVarsRecord };
4343

44+
// cSpell:ignore replyto collabs noncloud Payg
45+
4446
// Define projects actions
4547
export class ProjectsActions extends Actions<ProjectsState> {
4648
private getProjectTable = async () => {
@@ -426,7 +428,7 @@ export class ProjectsActions extends Actions<ProjectsState> {
426428
license: undefined,
427429
});
428430
if (!opts2.image) {
429-
// make falseish same as not specified.
431+
// make false-ish same as not specified.
430432
delete opts2.image;
431433
}
432434

@@ -1050,7 +1052,7 @@ export class ProjectsActions extends Actions<ProjectsState> {
10501052
await this.start_project(project_id, options);
10511053
};
10521054

1053-
// Explcitly set whether or not project is hidden for the given account
1055+
// Explicitly set whether or not project is hidden for the given account
10541056
// (hide=true means hidden)
10551057
public async set_project_hide(
10561058
account_id: string,

src/packages/util/db-schema/projects.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,12 @@ Table({
108108
users(obj, db, account_id) {
109109
return db._user_set_query_project_users(obj, account_id);
110110
},
111+
manage_users_owner_only(obj, db, account_id) {
112+
return db._user_set_query_project_manage_users_owner_only(
113+
obj,
114+
account_id,
115+
);
116+
},
111117
action_request: true, // used to request that an action be performed, e.g., "save"; handled by before_change
112118
compute_image: true,
113119
site_license: true,
@@ -191,6 +197,11 @@ Table({
191197
desc: "This is a map from account_id's to {hide:bool, group:'owner'|'collaborator', upgrades:{memory:1000, ...}, ssh:{...}}.",
192198
render: { type: "usersmap", editable: true },
193199
},
200+
manage_users_owner_only: {
201+
type: "boolean",
202+
desc: "If true, only project owners can add or remove collaborators. Collaborators can still remove themselves. Disabled by default (undefined or false means current behavior where collaborators can manage other collaborators).",
203+
render: { type: "boolean", editable: true },
204+
},
194205
invite: {
195206
type: "map",
196207
desc: "Map from email addresses to {time:when invite sent, error:error message if there was one}",

0 commit comments

Comments
 (0)