Skip to content

Commit 72bfe80

Browse files
committed
Merge remote-tracking branch 'origin/master' into projects-listing-cleanup-20251010
2 parents 0843240 + 792bec5 commit 72bfe80

File tree

7 files changed

+144
-52
lines changed

7 files changed

+144
-52
lines changed

src/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"make": "pnpm run build",
77
"make-dev": "pnpm run build-dev",
88
"build": "./workspaces.py install && ./workspaces.py build && pnpm python-api",
9+
"tsc-all": "./workspaces.py tsc --parallel",
910
"build-dev": "./workspaces.py install && ./workspaces.py build --dev && pnpm python-api",
1011
"clean": "rm -rf packages/node_modules && ./workspaces.py clean && cd compute/compute && pnpm clean ",
1112
"hub": "cd packages/hub && npm run hub-project-dev-nobuild",

src/packages/frontend/cspell.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"respawns",
4747
"revealjs",
4848
"Rmarkdown",
49+
"rtex",
4950
"rtypes",
5051
"Sagemath",
5152
"sagetex",

src/packages/frontend/frame-editors/latex-editor/latex-log-parser.ts

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ import { trimEnd } from "lodash";
2323

2424
import { normalize as path_normalize } from "path";
2525

26+
import { filename_extension } from "@cocalc/util/misc";
27+
2628
// Define some constants
2729
const LOG_WRAP_LIMIT = 79;
2830
const LATEX_WARNING_REGEX = /^LaTeX Warning: (.*)$/;
@@ -33,6 +35,26 @@ const LINES_REGEX = /lines? ([0-9]+)/;
3335
// This is used to parse the package name from the package warnings
3436
const PACKAGE_REGEX = /^(?:Package|Class|Module) (\b.+\b) Warning/;
3537

38+
// Whitelist of text file extensions that can be used with \input{} or \include{}
39+
const ALLOWED_DEP_EXTENSIONS = [
40+
"bbx",
41+
"bib",
42+
"bst",
43+
"cbx",
44+
"cfg",
45+
"cls",
46+
"def",
47+
"lbx",
48+
"md",
49+
"pgf",
50+
"rnw",
51+
"rtex",
52+
"sty",
53+
"tex",
54+
"tikz",
55+
"txt",
56+
] as const;
57+
3658
class LogText {
3759
private lines: string[];
3860
private row: number;
@@ -224,14 +246,25 @@ export class LatexParser {
224246

225247
addDeps(line: string): void {
226248
line = line.trim();
227-
// ignore absolute files
249+
// ignore absolute files (starting with /)
228250
if (line[0] === "/") return;
229251
if (line[line.length - 1] === "\\") {
230252
line = line.slice(0, line.length - 1);
231253
}
232-
// we only want to know about tex and bib files
233-
const pl = line.toLowerCase(); // could be name.TEX
234-
if (!pl.endsWith(".tex") && !pl.endsWith(".bib")) return;
254+
// Skip files that contain a colon (like "master.pdf :")
255+
if (line.includes(":")) return;
256+
257+
// Get the file extension (returns empty string if no extension)
258+
const ext = filename_extension(line).toLowerCase();
259+
260+
// If there's an extension, check if it's in the whitelist
261+
if (ext) {
262+
if (!ALLOWED_DEP_EXTENSIONS.includes(ext as any)) {
263+
return;
264+
}
265+
}
266+
// If no extension, include it (files without extensions are allowed)
267+
235268
this.deps.push(line);
236269
}
237270

@@ -306,7 +339,7 @@ export class LatexParser {
306339
const packageMatch = this.currentLine.match(PACKAGE_REGEX);
307340
if (!packageMatch) return;
308341
const packageName = packageMatch[1];
309-
// Regex to get rid of the unnecesary (packagename) prefix in most multi-line warnings
342+
// Regex to get rid of the unnecessary (packagename) prefix in most multi-line warnings
310343
const prefixRegex = new RegExp(`(?:\\(${packageName}\\))*[\\s]*(.*)`, "i");
311344
// After every warning message there's a blank line, let's use it
312345
while (!!(this.currentLine = this.log.nextLine())) {

src/packages/frontend/misc/latex-log-parser.test.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import fs from "fs";
2+
23
import { LatexParser } from "@cocalc/frontend/frame-editors/latex-editor/latex-log-parser";
34

45
describe("latex-log-parser", () => {
@@ -14,7 +15,7 @@ describe("latex-log-parser", () => {
1415
expect(parsed1.deps[1]).toEqual("subfile.tex");
1516
});
1617

17-
// This is an abbrivated log of https://github.com/sagemathinc/cocalc/issues/8089
18+
// This is an abbreviated log of https://github.com/sagemathinc/cocalc/issues/8089
1819
test("log2", () => {
1920
const log2 = fs.readFileSync("./misc/latex-logs/log2.txt", "utf-8");
2021
const parsed2 = new LatexParser(log2, {
@@ -23,7 +24,27 @@ describe("latex-log-parser", () => {
2324
const err0 = parsed2.all[0];
2425
expect(err0.file).toEqual("ch_Euclidean.tex");
2526
expect(err0.message).toEqual("Marginpar on page 1 moved.");
26-
expect(parsed2.deps).toEqual(["01.tex", "02.5.tex"]);
27+
expect(parsed2.deps).toEqual(["./livre1.bst", "01.tex", "02.5.tex"]);
2728
expect(parsed2.files).toEqual(["livre1.tex", "ch_Euclidean.tex"]);
2829
});
30+
31+
// Test for non-.tex/.bib files in dependencies (e.g., .txt files used via \input{})
32+
test("log3", () => {
33+
const log3 = fs.readFileSync("./misc/latex-logs/log3.txt", "utf-8");
34+
const parsed3 = new LatexParser(log3, {
35+
ignoreDuplicates: true,
36+
}).parse();
37+
expect(parsed3.deps).toEqual([
38+
"../subdir0/file2.md",
39+
"long-running.tex",
40+
"long-running.txt",
41+
"subdir/file_9",
42+
]);
43+
// No .tex or .bib files in parentheses, so files array is empty
44+
expect(parsed3.files).toEqual([]);
45+
expect(parsed3.errors).toEqual([]);
46+
expect(parsed3.warnings).toEqual([]);
47+
expect(parsed3.typesetting).toEqual([]);
48+
expect(parsed3.all).toEqual([]);
49+
});
2950
});
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
(./long-running.txt) (./subdir/file_9)
2+
(../subdir0/file2.md) [1{/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map}]
3+
(./long-running.aux) )</usr/share/texlive/texmf-dist/fonts/type1/public/amsfont
4+
s/cm/cmr10.pfb>
5+
Output written on long-running.pdf (1 page, 15440 bytes).
6+
SyncTeX written on long-running.synctex.gz.
7+
Transcript written on long-running.log.
8+
Latexmk: Examining 'long-running.log'
9+
=== TeX engine is 'pdfTeX'
10+
Latexmk: applying rule 'pdflatex'...
11+
Latexmk: All targets (long-running.pdf) are up-to-date
12+
#===Dependents, and related info, for long-running.tex:
13+
long-running.pdf :\
14+
../subdir0/file2.md\
15+
/etc/texmf/web2c/texmf.cnf\
16+
/usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb\
17+
/usr/share/texlive/texmf-dist/tex/latex/base/article.cls\
18+
/usr/share/texlive/texmf-dist/tex/latex/base/size10.clo\
19+
/usr/share/texlive/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def\
20+
/usr/share/texlive/texmf-dist/web2c/texmf.cnf\
21+
/usr/share/texmf/web2c/texmf.cnf\
22+
/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map\
23+
/var/lib/texmf/web2c/pdftex/pdflatex.fmt\
24+
long-running.tex\
25+
long-running.txt\
26+
subdir/file_9
27+
#===End dependents for long-running.tex:

src/packages/frontend/projects/projects-nav.tsx

Lines changed: 47 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import type { TabsProps } from "antd";
77
import { Avatar, Popover, Tabs, Tooltip } from "antd";
8-
import { cloneElement, CSSProperties, useMemo, useState } from "react";
8+
import { CSSProperties, useMemo, useState } from "react";
99

1010
import {
1111
CSS,
@@ -17,8 +17,8 @@ import {
1717
import { set_window_title } from "@cocalc/frontend/browser";
1818
import { Icon, Loading } from "@cocalc/frontend/components";
1919
import {
20-
SortableTabs,
2120
SortableTab,
21+
SortableTabs,
2222
useItemContext,
2323
useSortable,
2424
} from "@cocalc/frontend/components/sortable-tabs";
@@ -31,7 +31,6 @@ import { COLORS } from "@cocalc/util/theme";
3131
import { useProjectState } from "../project/page/project-state-hook";
3232
import { useProjectHasInternetAccess } from "../project/settings/has-internet-access-hook";
3333
import { BuyLicenseForProject } from "../site-licenses/purchase/buy-license-for-project";
34-
import { blendBackgroundColor } from "./util";
3534

3635
const PROJECT_NAME_STYLE: CSS = {
3736
whiteSpace: "nowrap",
@@ -176,15 +175,36 @@ function ProjectTab({ project_id }: ProjectTabProps) {
176175

177176
function renderAvatar() {
178177
const avatar = project?.get("avatar_image_tiny");
179-
if (!avatar) return;
180-
return (
181-
<Avatar
182-
style={{ marginTop: "-2px" }}
183-
shape="circle"
184-
icon={<img src={project.get("avatar_image_tiny")} />}
185-
size={20}
186-
/>
187-
);
178+
const color = project?.get("color");
179+
180+
if (avatar) {
181+
// Avatar exists: show it with colored border
182+
return (
183+
<Avatar
184+
style={{
185+
marginTop: "-2px",
186+
border: color ? `2px solid ${color}` : undefined,
187+
}}
188+
shape="circle"
189+
icon={<img src={project.get("avatar_image_tiny")} />}
190+
size={20}
191+
/>
192+
);
193+
} else if (color) {
194+
// No avatar but has color: show colored circle
195+
return (
196+
<Avatar
197+
style={{
198+
marginTop: "-2px",
199+
backgroundColor: color,
200+
}}
201+
shape="circle"
202+
size={20}
203+
/>
204+
);
205+
}
206+
207+
return undefined;
188208
}
189209

190210
function onMouseUp(e: React.MouseEvent) {
@@ -242,7 +262,7 @@ export function ProjectsNav(props: ProjectsNavProps) {
242262
const projectActions = useActions("projects");
243263
const activeTopTab = useTypedRedux("page", "active_top_tab");
244264
const openProjects = useTypedRedux("projects", "open_projects");
245-
const project_map = useTypedRedux("projects", "project_map");
265+
//const project_map = useTypedRedux("projects", "project_map");
246266

247267
const items: TabsProps["items"] = useMemo(() => {
248268
if (openProjects == null) return [];
@@ -259,14 +279,14 @@ export function ProjectsNav(props: ProjectsNavProps) {
259279
return openProjects.toJS().map((project_id) => project_id);
260280
}, [openProjects]);
261281

262-
const onEdit = (project_id: string, action: "add" | "remove") => {
263-
if (action == "add") {
282+
function onEdit(project_id: string, action: "add" | "remove") {
283+
if (action === "add") {
264284
actions.set_active_tab("projects");
265285
} else {
266286
// close given project
267287
actions.close_project_tab(project_id);
268288
}
269-
};
289+
}
270290

271291
function onDragEnd(event) {
272292
const { active, over } = event;
@@ -289,39 +309,25 @@ export function ProjectsNav(props: ProjectsNavProps) {
289309
{(node) => {
290310
const project_id = node.key;
291311
const isActive = project_id === activeTopTab;
292-
const projectColor = project_map?.getIn([project_id, "color"]) as
293-
| string
294-
| undefined;
295312

296313
const wrapperStyle: CSS = {
297314
border: isActive
298-
? `2px solid ${projectColor ? projectColor : "#d3d3d3"}`
299-
: `2px solid ${projectColor ? projectColor : "transparent"}`,
315+
? `2px solid ${"#d3d3d3"}`
316+
: `2px solid ${"transparent"}`,
300317
borderRadius: "8px",
301318
};
302319

303-
// Add background color if project has a color
304-
if (projectColor) {
305-
// Active tab: lighter/brighter (less color), inactive: darker (more color)
306-
wrapperStyle.backgroundColor = blendBackgroundColor(
307-
projectColor,
308-
isActive ? "white" : COLORS.GRAY_LL,
309-
!isActive,
310-
);
311-
}
312-
313-
// Clone the node with additional style props to override Ant Design's background
314-
const styledNode = cloneElement(node, {
315-
style: {
316-
...node.props.style,
317-
backgroundColor: wrapperStyle.backgroundColor,
318-
},
319-
});
320-
321-
// this is similar to the renderTabBar in sortable-tabs.tsx, but with the above, also styles the background
320+
// Kept for reference, this allows to tweak the node props directly
321+
// const styledNode = cloneElement(node, {
322+
// style: {
323+
// ...node.props.style,
324+
// backgroundColor: wrapperStyle.backgroundColor,
325+
// },
326+
// });
327+
322328
return (
323329
<SortableTab key={node.key} id={node.key} style={wrapperStyle}>
324-
{styledNode}
330+
{node}
325331
</SortableTab>
326332
);
327333
}}

src/packages/jupyter/util/cell-utils.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { field_cmp, len } from "@cocalc/util/misc";
1313
export function positions_between(
1414
before_pos: number | undefined,
1515
after_pos: number | undefined,
16-
num: number
16+
num: number,
1717
) {
1818
// Return an array of num equally spaced positions starting after
1919
// before_pos and ending before after_pos, so
@@ -96,10 +96,10 @@ export function ensure_positions_are_unique(cells?: Map<string, any>) {
9696
}
9797

9898
export function new_cell_pos(
99-
cells: Map<string, any>,
99+
cells: Map<string, any> | undefined,
100100
cell_list: List<string>,
101101
cur_id: string,
102-
delta: -1 | 1
102+
delta: -1 | 1,
103103
): number {
104104
/*
105105
Returns pos for a new cell whose position
@@ -113,6 +113,9 @@ export function new_cell_pos(
113113
Returned undefined whenever don't really know what to do; then caller
114114
just makes up a pos, and it'll get sorted out.
115115
*/
116+
if (cells == null) {
117+
return 0;
118+
}
116119
let cell_list_0: List<string>;
117120
if (cell_list == null) {
118121
cell_list_0 = sorted_cell_list(cells)!;
@@ -145,7 +148,7 @@ export function new_cell_pos(
145148
export function move_selected_cells(
146149
v?: string[],
147150
selected?: { [id: string]: true },
148-
delta?: number
151+
delta?: number,
149152
) {
150153
/*
151154
- v = ordered js array of all cell id's

0 commit comments

Comments
 (0)