Skip to content

Commit cdc9488

Browse files
committed
Merge branch 'master' of github.com:sagemathinc/cocalc
2 parents 20dce0a + e7d6003 commit cdc9488

File tree

52 files changed

+11913
-1385
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+11913
-1385
lines changed

src/packages/frontend/admin/users/impersonate.tsx

Lines changed: 43 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -3,55 +3,54 @@
33
* License: MS-RSL – see LICENSE.md for details
44
*/
55

6-
import { Component, Rendered } from "@cocalc/frontend/app-framework";
7-
import { Loading } from "@cocalc/frontend/components";
8-
import { webapp_client } from "@cocalc/frontend/webapp-client";
6+
import { Alert } from "antd";
97
import { join } from "path";
8+
9+
import { Rendered, useEffect, useState } from "@cocalc/frontend/app-framework";
10+
import { Loading } from "@cocalc/frontend/components";
1011
import { appBasePath } from "@cocalc/frontend/customize/app-base-path";
11-
import { Alert } from "antd";
12+
import { webapp_client } from "@cocalc/frontend/webapp-client";
1213

1314
interface Props {
1415
account_id: string;
1516
first_name: string;
1617
last_name: string;
1718
}
1819

19-
interface State {
20-
auth_token?: string;
21-
err?: string;
22-
}
20+
export function Impersonate(props: Readonly<Props>) {
21+
const { first_name, last_name, account_id } = props;
2322

24-
export class Impersonate extends Component<Props, State> {
25-
constructor(props, state) {
26-
super(props, state);
27-
this.state = {};
28-
}
23+
const [auth_token, set_auth_token] = useState<string | null>(null);
24+
const [err, set_err] = useState<string | null>(null);
2925

30-
async get_token(): Promise<void> {
26+
async function get_token(): Promise<void> {
3127
try {
3228
const auth_token = await webapp_client.admin_client.get_user_auth_token(
33-
this.props.account_id
29+
account_id,
3430
);
35-
this.setState({ auth_token });
31+
set_auth_token(auth_token);
32+
set_err(null);
3633
} catch (err) {
37-
this.setState({ err: err.toString() });
34+
set_err(err.toString());
35+
set_auth_token(null);
3836
}
3937
}
4038

41-
componentDidMount(): void {
42-
this.get_token();
43-
}
39+
useEffect(() => {
40+
get_token();
41+
}, []);
4442

45-
render_link(): Rendered {
46-
if (this.state.auth_token == null) {
43+
function render_link(): Rendered {
44+
if (auth_token == null) {
4745
return <Loading />;
4846
}
49-
const link = join(appBasePath, `app?auth_token=${this.state.auth_token}`);
47+
// lang_temp: https://github.com/sagemathinc/cocalc/issues/7782
48+
const link = join(appBasePath, `app?auth_token=${auth_token}&lang_temp=en`);
5049
return (
5150
<div>
5251
<a href={link} target="_blank" rel="noopener noreferrer">
5352
Right click and open this link in a new incognito window, where you
54-
will be signed in as {this.props.first_name} {this.props.last_name}...
53+
will be signed in as {first_name} {last_name}...
5554
</a>
5655
<br />
5756
The actual link:
@@ -64,35 +63,31 @@ export class Impersonate extends Component<Props, State> {
6463
);
6564
}
6665

67-
render_err(): Rendered {
68-
if (this.state.err != null) {
66+
function render_err(): Rendered {
67+
if (err != null) {
6968
return (
7069
<div>
71-
<b>ERROR</b> {this.state.err}
70+
<b>ERROR</b> {err}
7271
</div>
7372
);
7473
}
7574
}
7675

77-
render(): Rendered {
78-
return (
79-
<Alert
80-
type="warning"
81-
style={{
82-
margin: "15px",
83-
}}
84-
message={
85-
<b>
86-
Impersonate user "{this.props.first_name} {this.props.last_name}"
87-
</b>
88-
}
89-
description={
90-
<>
91-
{this.render_err()}
92-
{this.render_link()}
93-
</>
94-
}
95-
/>
96-
);
97-
}
76+
return (
77+
<Alert
78+
type="warning"
79+
style={{ margin: "15px" }}
80+
message={
81+
<b>
82+
Impersonate user "{first_name} {last_name}"
83+
</b>
84+
}
85+
description={
86+
<>
87+
{render_err()}
88+
{render_link()}
89+
</>
90+
}
91+
/>
92+
);
9893
}

src/packages/frontend/app/localize.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,12 @@ function loadAntdLocale(locale: Locale): Promise<AntdLocale> {
140140
return import("antd/locale/zh_CN");
141141
case "es":
142142
return import("antd/locale/es_ES");
143+
case "ru":
144+
return import("antd/locale/ru_RU");
145+
case "fr":
146+
return import("antd/locale/fr_FR");
147+
case "it":
148+
return import("antd/locale/it_IT");
143149
default:
144150
unreachable(locale);
145151
throw new Error(`Unknown locale '${locale}.`);

src/packages/frontend/app/render.tsx

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,29 +29,43 @@ function App({ children }) {
2929

3030
// setting via ?lang=[locale] takes precedece over account settings
3131
useAsyncEffect(async () => {
32-
const lang = QueryParams.get("lang");
32+
const lang_set = QueryParams.get("lang");
33+
// lang_temp sets the language *temporarily*, i.e. without changing the account settings and it is sticky
34+
// this is useful for impersonation – https://github.com/sagemathinc/cocalc/issues/7782
35+
const lang_temp = QueryParams.get("lang_temp");
36+
const temp = lang_temp != null;
37+
const lang = temp ? lang_temp : lang_set;
3338
if (lang != null) {
3439
if (lang in LOCALIZATIONS) {
3540
console.warn(
36-
`URL query parameter 'lang=${lang}' – overriding user configuration.`,
41+
`URL query parameter 'lang=${lang}' – overriding user configuration ${
42+
temp ? "temporary" : "permanent"
43+
}.`,
3744
);
38-
const store = redux.getStore("account");
39-
// we have to ensure the account store is available, because this code runs very early
40-
await store.async_wait({
41-
until: () => store.get_account_id() != null,
42-
});
43-
redux
44-
.getActions("account")
45-
.set_other_settings(OTHER_SETTINGS_LOCALE_KEY, lang);
45+
if (!temp) {
46+
const store = redux.getStore("account");
47+
// we have to ensure the account store is available, because this code runs very early
48+
await store.async_wait({
49+
until: () => store.get_account_id() != null,
50+
});
51+
redux
52+
.getActions("account")
53+
.set_other_settings(OTHER_SETTINGS_LOCALE_KEY, lang);
54+
}
4655
setLocale(lang);
4756
} else {
4857
console.warn(
49-
`URL query parameter 'lang=${lang}' provided, but not a valid locale.`,
58+
`URL query parameter '${JSON.stringify({
59+
lang_set,
60+
lang_temp,
61+
})}' provided, but not a valid locale.`,
5062
`Known values: ${Object.keys(LOCALIZATIONS)}`,
5163
);
5264
}
53-
// removing the parameter, otherwise this conflicts with further changes of account settings
54-
QueryParams.remove("lang");
65+
if (!temp) {
66+
// removing the parameter, otherwise this conflicts with further changes of account settings
67+
QueryParams.remove("lang");
68+
}
5569
} else {
5670
setLocale(getLocale(other_settings));
5771
}

src/packages/frontend/frame-editors/code-editor/editor.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@ export const SHELLS = {
3131
ml: "ocaml",
3232
pl: "perl",
3333
rb: "ruby",
34-
};
34+
} as const;
3535

36-
export const cm = {
36+
export const cm: EditorDescription = {
37+
type: "cm",
3738
short: "Code",
3839
name: "Source Code",
3940
icon: "code",
@@ -65,13 +66,13 @@ export const cm = {
6566
},
6667
},
6768
},
68-
} as EditorDescription;
69+
} as const;
6970

7071
const EDITOR_SPEC = {
7172
cm,
7273
terminal,
7374
time_travel,
74-
};
75+
} as const;
7576

7677
export const Editor = createEditor({
7778
format_bar: false,

src/packages/frontend/frame-editors/course-editor/editor.ts

Lines changed: 56 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
Students,
1919
Handouts,
2020
} from "./course-panels";
21+
import { EditorDescription } from "../frame-tree/types";
2122

2223
const commands = set([
2324
// commented out for now since broken: See https://github.com/sagemathinc/cocalc/issues/7235
@@ -30,47 +31,62 @@ const commands = set([
3031
//const buttons = set(["decrease_font_size", "increase_font_size"]);
3132
const buttons = undefined;
3233

34+
const course_students: EditorDescription = {
35+
type: "course-students",
36+
short: "Students",
37+
name: "Students",
38+
icon: "users",
39+
component: Students,
40+
commands,
41+
buttons,
42+
} as const;
43+
44+
const course_assignments: EditorDescription = {
45+
type: "course-assignments",
46+
short: "Assignments",
47+
name: "Assignments",
48+
icon: "share-square",
49+
component: Assignments,
50+
commands,
51+
buttons,
52+
} as const;
53+
54+
const course_handouts: EditorDescription = {
55+
type: "course-handouts",
56+
short: "Handouts",
57+
name: "Handouts",
58+
icon: "copy",
59+
component: Handouts,
60+
commands,
61+
buttons,
62+
} as const;
63+
64+
const course_configuration: EditorDescription = {
65+
type: "course-configuration",
66+
short: "Config",
67+
name: "Configuration",
68+
icon: "cogs",
69+
component: Configuration,
70+
commands,
71+
buttons,
72+
} as const;
73+
74+
const course_shared_project: EditorDescription = {
75+
type: "course-shared_project",
76+
short: "Shared",
77+
name: "Shared Project",
78+
icon: "share-square",
79+
component: SharedProject,
80+
commands,
81+
buttons,
82+
} as const;
83+
3384
export const EDITOR_SPEC = {
34-
course_students: {
35-
short: "Students",
36-
name: "Students",
37-
icon: "users",
38-
component: Students,
39-
commands,
40-
buttons,
41-
},
42-
course_assignments: {
43-
short: "Assignments",
44-
name: "Assignments",
45-
icon: "share-square",
46-
component: Assignments,
47-
commands,
48-
buttons,
49-
},
50-
course_handouts: {
51-
short: "Handouts",
52-
name: "Handouts",
53-
icon: "copy",
54-
component: Handouts,
55-
commands,
56-
buttons,
57-
},
58-
course_configuration: {
59-
short: "Config",
60-
name: "Configuration",
61-
icon: "cogs",
62-
component: Configuration,
63-
commands,
64-
buttons,
65-
},
66-
course_shared_project: {
67-
short: "Shared",
68-
name: "Shared Project",
69-
icon: "share-square",
70-
component: SharedProject,
71-
commands,
72-
buttons,
73-
},
85+
course_students,
86+
course_assignments,
87+
course_handouts,
88+
course_configuration,
89+
course_shared_project,
7490
terminal,
7591
time_travel,
7692
} as const;

src/packages/frontend/frame-editors/crm-editor/editor.ts

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,28 @@ import { time_travel } from "@cocalc/frontend/frame-editors/time-travel-editor/e
1111
import TableEditor from "./table-editor";
1212
import Users from "./users";
1313

14+
const tables: EditorDescription = {
15+
type: "crm-tables",
16+
short: "Tables",
17+
name: "Tables",
18+
icon: "database",
19+
component: TableEditor,
20+
commands: set(["save", "undo", "redo"]),
21+
} as const;
22+
23+
const account: EditorDescription = {
24+
type: "crm-account",
25+
short: "Users",
26+
name: "User Search",
27+
icon: "users",
28+
component: Users,
29+
} as const;
30+
1431
const EDITOR_SPEC = {
15-
tables: {
16-
short: "Tables",
17-
name: "Tables",
18-
icon: "database",
19-
component: TableEditor,
20-
commands: set(["save", "undo", "redo"]),
21-
},
22-
account: {
23-
short: "Users",
24-
name: "User Search",
25-
icon: "users",
26-
component: Users,
27-
},
32+
tables,
33+
account,
2834
time_travel,
29-
} as { [name: string]: EditorDescription };
35+
} as const;
3036

3137
export const Editor = createEditor({
3238
format_bar: false,

src/packages/frontend/frame-editors/crm-editor/users/impersonate.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Button } from "antd";
22
import { useState } from "react";
3+
34
import { Impersonate as OldImpersonate } from "@cocalc/frontend/admin/users/impersonate";
45
import { Icon } from "@cocalc/frontend/components";
56

0 commit comments

Comments
 (0)