Skip to content

Commit 6f85977

Browse files
authored
Merge pull request #8514 from sagemathinc/frontend-processes-vertical-size
Frontend: processes vertical size
2 parents a4afe64 + c9929a7 commit 6f85977

File tree

5 files changed

+161
-50
lines changed

5 files changed

+161
-50
lines changed

src/packages/frontend/cspell.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,11 @@
7070
"flyouts",
7171
"buttonbar",
7272
"noconf",
73-
"flyoutdragbar"
73+
"flyoutdragbar",
74+
"ptree",
75+
"pchildren",
76+
"nprocs",
77+
"pids"
7478
],
7579
"flagWords": [],
7680
"ignorePaths": ["node_modules/**", "dist/**", "dist-ts/**", "build/**"],

src/packages/frontend/project/context.tsx

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export interface ProjectContextState {
3232
actions?: ProjectActions;
3333
active_project_tab?: string;
3434
compute_image: string | undefined;
35+
contentSize: { width: number; height: number };
3536
enabledLLMs: LLMServicesAvailable;
3637
flipTabs: [number, React.Dispatch<React.SetStateAction<number>>];
3738
group?: UserGroup;
@@ -47,22 +48,15 @@ export interface ProjectContextState {
4748
onCoCalcDocker: boolean;
4849
project_id: string;
4950
project?: Project;
51+
setContentSize: (size: { width: number; height: number }) => void;
5052
status: ProjectStatus;
5153
}
5254

5355
export const emptyProjectContext = {
5456
actions: undefined,
5557
active_project_tab: undefined,
56-
group: undefined,
57-
project: undefined,
58-
is_active: false,
59-
project_id: "",
60-
isRunning: undefined,
61-
status: INIT_PROJECT_STATE,
62-
hasInternet: undefined,
63-
flipTabs: [0, () => {}],
64-
onCoCalcCom: true,
65-
onCoCalcDocker: false,
58+
compute_image: undefined,
59+
contentSize: { width: 0, height: 0 },
6660
enabledLLMs: {
6761
openai: false,
6862
google: false,
@@ -72,12 +66,22 @@ export const emptyProjectContext = {
7266
custom_openai: false,
7367
user: false,
7468
},
69+
flipTabs: [0, () => {}],
70+
group: undefined,
71+
hasInternet: undefined,
72+
is_active: false,
73+
isRunning: undefined,
7574
mainWidthPx: 0,
7675
manageStarredFiles: {
7776
starred: [],
7877
setStarredPath: () => {},
7978
},
80-
compute_image: undefined,
79+
onCoCalcCom: true,
80+
onCoCalcDocker: false,
81+
project: undefined,
82+
project_id: "",
83+
setContentSize: () => {},
84+
status: INIT_PROJECT_STATE,
8185
} as ProjectContextState;
8286

8387
export const ProjectContext: Context<ProjectContextState> =
@@ -141,10 +145,13 @@ export function useProjectContextProvider({
141145
userDefinedLLM,
142146
]);
143147

148+
const [contentSize, setContentSize] = useState({ width: 0, height: 0 });
149+
144150
return {
145151
actions,
146152
active_project_tab,
147153
compute_image,
154+
contentSize,
148155
enabledLLMs,
149156
flipTabs,
150157
group,
@@ -157,6 +164,7 @@ export function useProjectContextProvider({
157164
onCoCalcDocker,
158165
project_id,
159166
project,
167+
setContentSize,
160168
status,
161169
};
162170
}

src/packages/frontend/project/info/full.tsx

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

6+
// cspell:ignore Questionmark
7+
68
declare let DEBUG;
79

8-
import { InfoCircleOutlined, ScheduleOutlined } from "@ant-design/icons";
910
import { Alert, Button, Form, Modal, Popconfirm, Switch, Table } from "antd";
11+
import { useEffect, useRef, useState } from "react";
12+
13+
import { InfoCircleOutlined, ScheduleOutlined } from "@ant-design/icons";
1014
import { Col, Row } from "@cocalc/frontend/antd-bootstrap";
1115
import { CSS, ProjectActions, redux } from "@cocalc/frontend/app-framework";
1216
import { A, Loading, Tip } from "@cocalc/frontend/components";
1317
import { SiteName } from "@cocalc/frontend/customize";
18+
import { field_cmp, seconds2hms } from "@cocalc/util/misc";
19+
import { COLORS } from "@cocalc/util/theme";
1420
import {
1521
Process,
1622
ProjectInfo as ProjectInfoType,
1723
} from "@cocalc/util/types/project-info/types";
18-
import { field_cmp, seconds2hms } from "@cocalc/util/misc";
19-
import { COLORS } from "@cocalc/util/theme";
24+
import { useProjectContext } from "../context";
25+
import { ROOT_STYLE } from "../servers/consts";
2026
import { RestartProject } from "../settings/restart-project";
2127
import {
2228
AboutContent,
@@ -28,7 +34,6 @@ import {
2834
} from "./components";
2935
import { CGroupInfo, DUState, PTStats, ProcessRow } from "./types";
3036
import { DETAILS_BTN_TEXT, SSH_KEYS_DOC } from "./utils";
31-
import { ROOT_STYLE } from "../servers/consts";
3237

3338
interface Props {
3439
any_alerts: () => boolean;
@@ -89,6 +94,53 @@ export function Full(props: Readonly<Props>): React.JSX.Element {
8994
onCellProps,
9095
} = props;
9196

97+
const { contentSize } = useProjectContext();
98+
99+
const problemsRef = useRef<HTMLDivElement>(null);
100+
const cgroupRef = useRef<HTMLDivElement>(null);
101+
const headerRef = useRef<HTMLDivElement>(null);
102+
const explanationRef = useRef<HTMLDivElement>(null);
103+
const generalStatusRef = useRef<HTMLDivElement>(null);
104+
const [tableHeight, setTableHeight] = useState<number>(400);
105+
106+
useEffect(() => {
107+
const calculateTableHeight = () => {
108+
const parentHeight = contentSize.height;
109+
if (parentHeight === 0) return; // Wait until contentSize is measured
110+
111+
let usedHeight = 0;
112+
113+
// Add height of ProjectProblems component
114+
usedHeight += problemsRef.current?.offsetHeight ?? 0;
115+
116+
// Add height of CGroup component
117+
usedHeight += cgroupRef.current?.offsetHeight ?? 0;
118+
119+
// Add height of header row
120+
usedHeight += headerRef.current?.offsetHeight ?? 0;
121+
122+
// Add height of explanation row if visible
123+
usedHeight += explanationRef.current?.offsetHeight ?? 0;
124+
125+
// Add height of general status row if DEBUG is enabled
126+
if (DEBUG) {
127+
usedHeight += generalStatusRef.current?.offsetHeight ?? 0;
128+
}
129+
130+
// Add more buffer for table header, margins, and other spacing
131+
usedHeight += 100;
132+
133+
const availableHeight = Math.max(300, parentHeight - usedHeight);
134+
setTableHeight(availableHeight);
135+
};
136+
137+
calculateTableHeight();
138+
139+
// Recalculate on window resize
140+
window.addEventListener("resize", calculateTableHeight);
141+
return () => window.removeEventListener("resize", calculateTableHeight);
142+
}, [show_explanation, ptree, contentSize.height, contentSize.width]);
143+
92144
function render_help() {
93145
return (
94146
<Form.Item label="Help:">
@@ -295,11 +347,16 @@ export function Full(props: Readonly<Props>): React.JSX.Element {
295347
</Tip>
296348
);
297349

298-
const table_style: CSS = { marginBottom: "2rem" };
350+
const table_style: CSS = {
351+
marginBottom: "2rem",
352+
};
299353

300354
return (
301355
<>
302-
<Row style={{ marginBottom: "10px", marginTop: "20px" }}>
356+
<Row
357+
ref={headerRef}
358+
style={{ marginBottom: "10px", marginTop: "20px" }}
359+
>
303360
<Col md={9}>
304361
<Form layout="inline">
305362
<Form.Item label="Table of Processes" />
@@ -314,13 +371,14 @@ export function Full(props: Readonly<Props>): React.JSX.Element {
314371
</Form>
315372
</Col>
316373
</Row>
317-
<Row>{render_explanation()}</Row>
374+
<Row ref={explanationRef}>{render_explanation()}</Row>
318375
<Row>
319376
<Table<ProcessRow>
377+
key={`table-${contentSize.width}-${contentSize.height}`}
320378
dataSource={ptree}
321379
size={"small"}
322380
pagination={false}
323-
scroll={{ y: "65vh" }}
381+
scroll={{ y: tableHeight }}
324382
style={table_style}
325383
expandable={expandable}
326384
rowSelection={rowSelection}
@@ -439,7 +497,7 @@ export function Full(props: Readonly<Props>): React.JSX.Element {
439497
</div>
440498
);
441499
return (
442-
<Col lg={8} lgOffset={2} md={12} mdOffset={0}>
500+
<Col md={12} mdOffset={0}>
443501
<Alert
444502
message={msg}
445503
style={{ margin: "10px 0" }}
@@ -457,30 +515,36 @@ export function Full(props: Readonly<Props>): React.JSX.Element {
457515

458516
function render_general_status() {
459517
return (
460-
<Col md={12} style={{ color: COLORS.GRAY }}>
461-
Timestamp:{" "}
462-
{info?.timestamp != null ? (
463-
<code>{new Date(info.timestamp).toISOString()}</code>
464-
) : (
465-
"no timestamp"
466-
)}{" "}
467-
| Status: <code>{status}</code>
518+
<Col md={12}>
519+
<div ref={generalStatusRef} style={{ color: COLORS.GRAY }}>
520+
Timestamp:{" "}
521+
{info?.timestamp != null ? (
522+
<code>{new Date(info.timestamp).toISOString()}</code>
523+
) : (
524+
"no timestamp"
525+
)}{" "}
526+
| Status: <code>{status}</code>
527+
</div>
468528
</Col>
469529
);
470530
}
471531

472532
function render_body() {
473533
return (
474534
<>
475-
<ProjectProblems project_status={project_status} />
476-
<CGroup
477-
have_cgroup={info?.cgroup != null}
478-
cg_info={cg_info}
479-
disk_usage={disk_usage}
480-
pt_stats={pt_stats}
481-
start_ts={start_ts}
482-
project_status={project_status}
483-
/>
535+
<div ref={problemsRef}>
536+
<ProjectProblems project_status={project_status} />
537+
</div>
538+
<div ref={cgroupRef}>
539+
<CGroup
540+
have_cgroup={info?.cgroup != null}
541+
cg_info={cg_info}
542+
disk_usage={disk_usage}
543+
pt_stats={pt_stats}
544+
start_ts={start_ts}
545+
project_status={project_status}
546+
/>
547+
</div>
484548
{render_top()}
485549
{render_modals()}
486550
{DEBUG && render_general_status()}

src/packages/frontend/project/info/project-info.tsx

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

6+
// cSpell:ignore chldsum
7+
68
import { Alert } from "antd";
9+
10+
import { cgroup_stats } from "@cocalc/comm/project-status/utils";
711
import {
812
React,
913
Rendered,
@@ -13,20 +17,19 @@ import {
1317
useState,
1418
useTypedRedux,
1519
} from "@cocalc/frontend/app-framework";
20+
import ShowError from "@cocalc/frontend/components/error";
1621
import { useProjectContext } from "@cocalc/frontend/project/context";
22+
import { unreachable } from "@cocalc/util/misc";
1723
import {
1824
Process,
1925
ProjectInfo as ProjectInfoType,
2026
} from "@cocalc/util/types/project-info/types";
21-
import { cgroup_stats } from "@cocalc/comm/project-status/utils";
22-
import { unreachable } from "@cocalc/util/misc";
2327
import { CoCalcFile, render_cocalc_btn } from "./components";
2428
import { Flyout } from "./flyout";
2529
import { Full } from "./full";
2630
import { CGroupInfo, DUState, PTStats, ProcessRow } from "./types";
27-
import { grid_warning, linearList, process_tree, sum_children } from "./utils";
2831
import useProjectInfo from "./use-project-info";
29-
import ShowError from "@cocalc/frontend/components/error";
32+
import { grid_warning, linearList, process_tree, sum_children } from "./utils";
3033

3134
interface Props {
3235
project_id: string;
@@ -82,7 +85,7 @@ export const ProjectInfo: React.FC<Props> = React.memo(
8285
const [ptree, set_ptree] = useState<ProcessRow[] | undefined>(undefined);
8386
const [pt_stats, set_pt_stats] = useState<PTStats>(pt_stats_init);
8487
const [selected, set_selected] = useState<number[]>([]);
85-
const [expanded, set_expanded] = useState<(string|number)[]>([]);
88+
const [expanded, set_expanded] = useState<(string | number)[]>([]);
8689
const [have_children, set_have_children] = useState<string[]>([]);
8790
const [cg_info, set_cg_info] = useState<CGroupInfo>(gc_info_init);
8891
const [disk_usage, set_disk_usage] = useState<DUState>(du_init);
@@ -116,7 +119,7 @@ export const ProjectInfo: React.FC<Props> = React.memo(
116119

117120
function update_top(info: ProjectInfoType) {
118121
// this shouldn't be the case, but somehow I saw this happening once
119-
// the ProjectInfoType type is updated to refrect this edge case and here we bail out
122+
// the ProjectInfoType type is updated to reflect this edge case and here we bail out
120123
// and wait for the next update of "info" to get all processes…
121124
if (info.processes == null) return;
122125
switch (mode) {
@@ -131,7 +134,7 @@ export const ProjectInfo: React.FC<Props> = React.memo(
131134
set_have_children(pchildren);
132135
break;
133136
case "flyout":
134-
// flyout does not nest children, not enogh space
137+
// flyout does not nest children, not enough space
135138
set_ptree(linearList(info.processes));
136139
break;
137140
default:
@@ -216,7 +219,7 @@ export const ProjectInfo: React.FC<Props> = React.memo(
216219
to_str?: (val) => Rendered,
217220
) {
218221
const cell_val = (val, proc): number => {
219-
// we have to check for length==0, because initally rows are all expanded but
222+
// we have to check for length==0, because initially rows are all expanded but
220223
// onExpandedRowsChange isn't triggered
221224
if (
222225
expanded.length == 0 ||
@@ -296,7 +299,11 @@ export const ProjectInfo: React.FC<Props> = React.memo(
296299
}
297300

298301
const showError = (
299-
<ShowError style={{ margin: "15px 0" }} error={error} setError={setError} />
302+
<ShowError
303+
style={{ margin: "15px 0" }}
304+
error={error}
305+
setError={setError}
306+
/>
300307
);
301308

302309
switch (mode) {

0 commit comments

Comments
 (0)