@datagrok/bio 1.11.0 → 1.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "name": "Leonid Stolbov",
6
6
  "email": "lstolbov@datagrok.ai"
7
7
  },
8
- "version": "1.11.0",
8
+ "version": "1.11.1",
9
9
  "description": "Bio is a [package](https://datagrok.ai/help/develop/develop#packages) for the [Datagrok](https://datagrok.ai) platform",
10
10
  "repository": {
11
11
  "type": "git",
@@ -16,7 +16,7 @@
16
16
  "@biowasm/aioli": ">=2.4.0",
17
17
  "@datagrok-libraries/bio": "^4.2.0",
18
18
  "@datagrok-libraries/chem-meta": "1.0.0",
19
- "@datagrok-libraries/ml": "^4.0.0",
19
+ "@datagrok-libraries/ml": "^6.0.0",
20
20
  "@datagrok-libraries/utils": "^1.6.2",
21
21
  "cash-dom": "latest",
22
22
  "datagrok-api": "^1.6.6",
@@ -48,6 +48,7 @@
48
48
  "link-api": "npm link datagrok-api",
49
49
  "link-bio": "npm link @datagrok-libraries/bio",
50
50
  "link-ml": "npm link @datagrok-libraries/ml",
51
+ "link-utils": "npm link @datagrok-libraries/utils",
51
52
  "link-all": "npm link datagrok-api @datagrok-libraries/utils @datagrok-libraries/bio @datagrok-libraries/ml",
52
53
  "debug-sequences1": "grok publish",
53
54
  "release-sequences1": "grok publish --release",
@@ -69,7 +70,11 @@
69
70
  "Developers"
70
71
  ],
71
72
  "sources": [
72
- "css/helm.css"
73
+ "css/helm.css",
74
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.10.4/dojo/dojo.js",
75
+ "helm/JSDraw/Scilligence.JSDraw2.Lite.js",
76
+ "helm/JSDraw/Scilligence.JSDraw2.Resources.js",
77
+ "helm/JSDraw/Pistoia.HELM-uncompressed.js"
73
78
  ],
74
79
  "category": "Bioinformatics"
75
80
  }
package/src/package.ts CHANGED
@@ -15,7 +15,7 @@ import {Aminoacids} from '@datagrok-libraries/bio/src/aminoacids';
15
15
  import {getEmbeddingColsNames, sequenceSpace} from './utils/sequence-space';
16
16
  import {AvailableMetrics} from '@datagrok-libraries/ml/src/typed-metrics';
17
17
  import {getActivityCliffs} from '@datagrok-libraries/ml/src/viewers/activity-cliffs';
18
- import {drawSequences, sequenceGetSimilarities} from './utils/sequence-activity-cliffs';
18
+ import {createPropPanelElement, createTooltipElement, getSimilaritiesMarix} from './utils/sequence-activity-cliffs';
19
19
  import {createJsonMonomerLibFromSdf, encodeMonomers, getMolfilesFromSeq, HELM_CORE_LIB_FILENAME} from './utils/utils';
20
20
  import {getMacroMol} from './utils/atomic-works';
21
21
  import {MacromoleculeSequenceCellRenderer} from './utils/cell-renderer';
@@ -180,8 +180,9 @@ export async function activityCliffs(df: DG.DataFrame, macroMolecule: DG.Column,
180
180
  DG.SEMTYPE.MACROMOLECULE,
181
181
  tags,
182
182
  sequenceSpace,
183
- sequenceGetSimilarities,
184
- drawSequences,
183
+ getSimilaritiesMarix,
184
+ createTooltipElement,
185
+ createPropPanelElement,
185
186
  (options as any)[methodName]);
186
187
  return sp;
187
188
  }
@@ -6,6 +6,7 @@ import {importFasta, multipleSequenceAlignmentAny} from '../package';
6
6
  import {readDataframe} from './utils';
7
7
  import {convertDo} from '../utils/convert';
8
8
  import {ALPHABET, NOTATION, UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
9
+ import { SEM_TYPES, TAGS } from '../utils/constants';
9
10
 
10
11
  category('renderers', () => {
11
12
  let tvList: DG.TableView[];
@@ -30,6 +31,10 @@ category('renderers', () => {
30
31
  await _testAfterConvert();
31
32
  });
32
33
 
34
+ test('setRenderer', async () => {
35
+ await _setRendererManually();
36
+ });
37
+
33
38
  async function _testAfterMsa() {
34
39
  const fastaTxt: string = await grok.dapi.files.readAsText('System:AppData/Bio/samples/sample_FASTA.fasta');
35
40
  const df: DG.DataFrame = importFasta(fastaTxt)[0];
@@ -75,4 +80,16 @@ category('renderers', () => {
75
80
  tvList.push(tv);
76
81
  dfList.push(df);
77
82
  };
83
+
84
+ async function _setRendererManually() {
85
+ const df = DG.DataFrame.fromColumns([DG.Column.fromStrings('SequencesDiff', ['meI/hHis/Aca/N/T/dK/Thr_PO3H2/Aca#D-Tyr_Et/Tyr_ab-dehydroMe/meN/E/N/dV'])]);
86
+ df.col('SequencesDiff')!.tags[DG.TAGS.UNITS] = 'separator';
87
+ df.col('SequencesDiff')!.tags[TAGS.SEPARATOR] = '/';
88
+ df.col('SequencesDiff')!.semType = SEM_TYPES.MACROMOLECULE_DIFFERENCE;
89
+ const tw = grok.shell.addTableView(df);
90
+ await delay(100);
91
+ const renderer = tw.dataFrame.col('SequencesDiff')?.getTag(DG.TAGS.CELL_RENDERER);
92
+ if (renderer !== 'MacromoleculeDifferenceCR')
93
+ throw new Error(`Units 'separator', separator '/' and semType 'MacromoleculeDifference' have been manually set on column but after df aws added as table view renderer has been reset to '${renderer}'`)
94
+ };
78
95
  });
@@ -1,27 +1,22 @@
1
1
  import * as DG from 'datagrok-api/dg';
2
2
  import * as grok from 'datagrok-api/grok';
3
+ import {DataFrame} from 'datagrok-api/dg';
3
4
 
4
- export function generateManySequences(): string {
5
- let csvData = `MSA,Activity
6
- meI/hHis/Aca/N/T/dE/Thr_PO3H2/Aca/D-Tyr_Et/Tyr_ab-dehydroMe/dV/E/N/D-Orn/D-aThr//Phe_4Me,5.30751`;
7
- for (let i = 0; i < 10 ** 6; i++) {
8
- csvData += `\n meI/hHis/Aca/N/T/dE/Thr_PO3H2/Aca/D-Tyr_Et/Tyr_ab-dehydroMe/dV/E/N/D-Orn/D-aThr//Phe_4Me,5.30751`;
9
- }
10
- return csvData;
5
+ export function generateManySequences(): DG.Column[] {
6
+ let columns: DG.Column[] = [];
7
+ columns.push(DG.Column.fromList('string', 'MSA', new Array(10 ** 6).fill('meI/hHis/Aca/N/T/dE/Thr_PO3H2/Aca/D-Tyr_Et/Tyr_ab-dehydroMe/dV/E/N/D-Orn/D-aThr//Phe_4Me')));
8
+ columns.push(DG.Column.fromList('string', 'Activity', new Array(10 ** 6).fill('5.30751')));
9
+ return columns;
11
10
  }
12
11
 
13
- export function generateLongSequence(): string {
14
- let longSequence = `meI/hHis/Aca/N/T/dE/Thr_PO3H2/Aca/D-Tyr_Et/Tyr_ab-dehydroMe/dV/E/N/D-Orn/D-aThr`;
15
- for (let i = 0; i < 10 ** 5; i++) {
16
- longSequence += `/Aca/N/T/dE/Thr_PO3H2/Aca/D-Tyr_Et/Tyr_ab-dehydroMe/dV/dv`;
17
- }
18
- longSequence += `//Phe_4Me,5.30751`;
19
- let csvData = `MSA,Activity `;
20
- for (let i = 0; i <= 10 ** 1 * 4; i++) {
21
- csvData += `\n ${longSequence}`;
22
- }
23
- return csvData;
12
+ export function generateLongSequence(): DG.Column[] {
13
+ let columns: DG.Column[] = [];
14
+ const longSequence = `meI/hHis/Aca/N/T/dE/Thr_PO3H2/Aca/D-Tyr_Et/Tyr_ab-dehydroMe/dV/E/N/D-Orn/D-aThr`.repeat(10 ** 5);
15
+ columns.push(DG.Column.fromList('string', 'MSA', new Array(10 ** 2).fill(longSequence)));
16
+ columns.push(DG.Column.fromList('string', 'Activity', new Array(10 ** 2).fill('7.30751')));
17
+ return columns;
24
18
  }
19
+
25
20
  export function setTagsMacromolecule(col: DG.Column) {
26
21
  col.semType = DG.SEMTYPE.MACROMOLECULE;
27
22
  col.setTag('units', 'separator');
@@ -31,10 +26,10 @@ export function setTagsMacromolecule(col: DG.Column) {
31
26
  return col;
32
27
  }
33
28
 
34
- export function performanceTest(generateFunc: () => string,testName: string) {
29
+ export function performanceTest(generateFunc: () => DG.Column[], testName: string) {
30
+ const columns = generateFunc();
31
+ const df: DG.DataFrame = DG.DataFrame.fromColumns(columns);
35
32
  const startTime: number = Date.now();
36
- const csv = generateFunc();
37
- const df: DG.DataFrame = DG.DataFrame.fromCsv(csv);
38
33
  const col: DG.Column = df.columns.byName('MSA');
39
34
  setTagsMacromolecule(col);
40
35
  grok.shell.addTableView(df);
@@ -2,7 +2,7 @@ import * as C from './constants';
2
2
  import * as DG from 'datagrok-api/dg';
3
3
  import {AminoacidsPalettes} from '@datagrok-libraries/bio/src/aminoacids';
4
4
  import {NucleotidesPalettes} from '@datagrok-libraries/bio/src/nucleotides';
5
- import {UnknownSeqPalette, UnknownSeqPalettes} from '@datagrok-libraries/bio/src/unknown';
5
+ import {UnknownSeqPalettes} from '@datagrok-libraries/bio/src/unknown';
6
6
  import {SplitterFunc, WebLogo} from '@datagrok-libraries/bio/src/viewers/web-logo';
7
7
  import {SeqPalette} from '@datagrok-libraries/bio/src/seq-palettes';
8
8
  import * as ui from 'datagrok-api/ui';
@@ -14,7 +14,7 @@ const monomerToShortFunction: (amino: string, maxLengthOfMonomer: number) => str
14
14
  const gapRenderer = 5;
15
15
 
16
16
 
17
- function getPalleteByType(paletteType: string): SeqPalette {
17
+ function getPaletteByType(paletteType: string): SeqPalette {
18
18
  switch (paletteType) {
19
19
  case 'PT':
20
20
  return AminoacidsPalettes.GrokGroups;
@@ -30,6 +30,10 @@ function getPalleteByType(paletteType: string): SeqPalette {
30
30
  }
31
31
  }
32
32
 
33
+ function getUpdatedWidth(grid: DG.Grid | null, g: CanvasRenderingContext2D, x: number, w: number): number {
34
+ return grid ? Math.min(grid.canvas.width - x, w) : g.canvas.width - x;
35
+ }
36
+
33
37
  export function processSequence(subParts: string[]): [string[], boolean] {
34
38
  const simplified = !subParts.some((amino, index) =>
35
39
  amino.length > 1 &&
@@ -63,8 +67,7 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
63
67
  }
64
68
  const maxLengthWordsSum = gridCell.cell.column.temp['bio-sum-maxLengthWords'];
65
69
  const maxIndex = gridCell.cell.column.temp['bio-maxIndex'];
66
- //@ts-ignore
67
- const argsX = e.layerX - gridCell.gridColumn.left + (gridCell.gridColumn.left - gridCell.bounds.x);
70
+ const argsX = e.offsetX - gridCell.gridColumn.left + (gridCell.gridColumn.left - gridCell.bounds.x);
68
71
  let left = 0;
69
72
  let right = maxIndex;
70
73
  let found = false;
@@ -109,23 +112,22 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
109
112
  g: CanvasRenderingContext2D, x: number, y: number, w: number, h: number, gridCell: DG.GridCell,
110
113
  cellStyle: DG.GridCellStyle
111
114
  ): void {
112
- const grid = gridCell.gridRow !== -1 ? gridCell.grid : undefined;
115
+ const grid = gridCell.gridRow !== -1 ? gridCell.grid : null;
113
116
  const cell = gridCell.cell;
114
- const [type, subtype, paletteType] = gridCell.cell.column.getTag(DG.TAGS.UNITS).split(':');
117
+ const paletteType = gridCell.cell.column.getTag(C.TAGS.ALPHABET);
115
118
  const minDistanceRenderer = 50;
116
- w = grid ? Math.min(grid.canvas.width - x, w) : g.canvas.width - x;
119
+ w = getUpdatedWidth(grid, g, x, w);
117
120
  g.save();
118
121
  g.beginPath();
119
122
  g.rect(x, y, w, h);
120
123
  g.clip();
121
124
  g.font = '12px monospace';
122
125
  g.textBaseline = 'top';
123
- const s: string = cell.value ?? '';
124
126
 
125
127
  //TODO: can this be replaced/merged with splitSequence?
126
128
  const units = gridCell.cell.column.getTag(DG.TAGS.UNITS);
127
129
 
128
- const palette = getPalleteByType(paletteType);
130
+ const palette = getPaletteByType(paletteType);
129
131
 
130
132
  const separator = gridCell.cell.column.getTag('separator') ?? '';
131
133
  const splitLimit = gridCell.bounds.width / 5;
@@ -184,10 +186,8 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
184
186
  g.fillStyle = undefinedColor;
185
187
  let last = index === subParts.length - 1;
186
188
  x1 = printLeftOrCentered(x1, y, w, h, g, monomerToShortFunction(amino, maxLengthOfMonomer), color, 0, true, 1.0, separator, last, drawStyle, maxLengthWords, index, gridCell);
187
- if (x1 - minDistanceRenderer - gridCell.gridColumn.left + (gridCell.gridColumn.left - gridCell.bounds.x) > gridCell.bounds.width) {
188
- return false;
189
- }
190
- return true;
189
+ return x1 - minDistanceRenderer - gridCell.gridColumn.left + (gridCell.gridColumn.left - gridCell.bounds.x) <= gridCell.bounds.width;
190
+
191
191
  });
192
192
 
193
193
  g.restore();
@@ -226,7 +226,7 @@ export class MonomerCellRenderer extends DG.GridCellRenderer {
226
226
  g.font = `12px monospace`;
227
227
  g.textBaseline = 'top';
228
228
 
229
- const palette = getPalleteByType(gridCell.tableColumn!.tags[C.TAGS.ALPHABET]);
229
+ const palette = getPaletteByType(gridCell.tableColumn!.tags[C.TAGS.ALPHABET]);
230
230
  const s: string = gridCell.cell.value ? gridCell.cell.value : '-';
231
231
  const color = palette.get(s);
232
232
 
@@ -262,7 +262,7 @@ export class MacromoleculeDifferenceCellRenderer extends DG.GridCellRenderer {
262
262
  const grid = gridCell.grid;
263
263
  const cell = gridCell.cell;
264
264
 
265
- w = grid ? Math.min(grid.canvas.width - x, w) : g.canvas.width - x;
265
+ w = getUpdatedWidth(grid, g, w, x);
266
266
  g.save();
267
267
  g.beginPath();
268
268
  g.rect(x, y, w, h);
@@ -286,7 +286,7 @@ export class MacromoleculeDifferenceCellRenderer extends DG.GridCellRenderer {
286
286
 
287
287
  let palette: SeqPalette = UnknownSeqPalettes.Color;
288
288
  if (units != 'HELM')
289
- palette = getPalleteByType(units.substring(units.length - 2));
289
+ palette = getPaletteByType(units.substring(units.length - 2));
290
290
 
291
291
  const vShift = 7;
292
292
  for (let i = 0; i < subParts1.length; i++) {
@@ -3,18 +3,130 @@ import * as DG from 'datagrok-api/dg';
3
3
  import * as ui from 'datagrok-api/ui';
4
4
  import {getSimilarityFromDistance} from '@datagrok-libraries/utils/src/similarity-metrics';
5
5
  import {AvailableMetrics} from '@datagrok-libraries/ml/src/typed-metrics';
6
+ import * as grok from 'datagrok-api/grok';
6
7
 
7
- export async function sequenceGetSimilarities(col: DG.Column, seq: string): Promise<DG.Column | null> {
8
+ export async function getDistances(col: DG.Column, seq: string): Promise<Array<number>> {
8
9
  const stringArray = col.toList();
9
- const distances = new Array(stringArray.length).fill(0.0);
10
+ const distances = new Array(stringArray.length).fill(0);
10
11
  for (let i = 0; i < stringArray.length; ++i)
11
- distances[i] = stringArray[i] ? getSimilarityFromDistance(AvailableMetrics['String']['Levenshtein'](stringArray[i], seq)) : 0;
12
- return DG.Column.fromList(DG.COLUMN_TYPE.FLOAT, 'distances', distances);
12
+ distances[i] = stringArray[i] ? AvailableMetrics['String']['Levenshtein'](stringArray[i], seq) : null;
13
+ return distances;
13
14
  }
14
15
 
15
- export function drawSequences(params: ITooltipAndPanelParams) {
16
- params.line.mols.forEach((mol: number, index: number) => {
17
- ui.empty(params.hosts[index]);
18
- params.hosts[index].append(ui.divText(params.seqCol.get(mol)));
16
+ export async function getSimilaritiesMarix(dim: number, seqCol: DG.Column, df: DG.DataFrame, colName: string, simArr: DG.Column[])
17
+ : Promise<DG.Column[]> {
18
+
19
+ function arrayMin(arr: number[]) {
20
+ return arr.reduce(function (p, v) {
21
+ return (p < v ? p : v);
22
+ });
23
+ }
24
+
25
+ function arrayMax(arr: number[]) {
26
+ return arr.reduce(function (p, v) {
27
+ return (p > v ? p : v);
28
+ });
29
+ }
30
+ const distances = new Array(simArr.length).fill(null);
31
+ let min = Infinity;
32
+ let max = -Infinity;
33
+ for (let i = 0; i != dim - 1; ++i) {
34
+ const seq = seqCol.get(i);
35
+ df.rows.removeAt(0, 1, false);
36
+ distances[i] = (await getDistances(df.col(colName)!, seq))!;
37
+ const newMin = arrayMin(distances[i]);
38
+ const newMax = arrayMax(distances[i]);
39
+ if (newMin < min)
40
+ min = newMin;
41
+ if (newMax > max)
42
+ max = newMax;
43
+ }
44
+
45
+ for (let i = 0; i < distances.length; i++) {
46
+ for (let j = 0; j < distances[i].length; j++) {
47
+ distances[i][j] = getSimilarityFromDistance((distances[i][j] - min)/(max - min));
48
+ }
49
+ simArr[i] = DG.Column.fromList(DG.COLUMN_TYPE.FLOAT, 'distances', distances[i]);
50
+ }
51
+ return simArr;
52
+ }
53
+
54
+ export function createTooltipElement(params: ITooltipAndPanelParams): HTMLDivElement {
55
+ const tooltipElement = ui.divH([]);
56
+ const columnNames = ui.divV([
57
+ ui.divText(params.seqCol.name),
58
+ ui.divText(params.activityCol.name),
59
+ ]);
60
+ columnNames.style.fontWeight = 'bold';
61
+ columnNames.style.display = 'flex';
62
+ columnNames.style.justifyContent = 'space-between';
63
+ tooltipElement.append(columnNames);
64
+ params.line.mols.forEach((molIdx: number, idx: number) => {
65
+ const activity = ui.divText(params.activityCol.get(molIdx).toFixed(2));
66
+ activity.style.display = 'flex';
67
+ activity.style.justifyContent = 'left';
68
+ activity.style.paddingLeft = '30px';
69
+ tooltipElement.append(ui.divV([
70
+ ui.divText(params.seqCol.get(molIdx)),
71
+ activity,
72
+ ]));
19
73
  });
74
+ return tooltipElement;
20
75
  }
76
+
77
+ function moleculeInfo(df: DG.DataFrame, idx: number, seqColName: string): HTMLElement {
78
+ let dict: {[key: string]: string} = {};
79
+ for (let col of df.columns) {
80
+ if(col.name !== seqColName) {
81
+ dict[col.name] = df.get(col.name, idx);
82
+ }
83
+ }
84
+ return ui.tableFromMap(dict);
85
+ }
86
+
87
+
88
+ export function createPropPanelElement(params: ITooltipAndPanelParams): HTMLDivElement {
89
+ const propPanel = ui.divV([]);
90
+ const columnNames = ui.divH([
91
+ ui.divText(params.seqCol.name),
92
+ ui.divText(params.activityCol.name),
93
+ ]);
94
+ columnNames.style.fontWeight = 'bold';
95
+ columnNames.style.justifyContent = 'space-between';
96
+ propPanel.append(columnNames);
97
+ const hosts: HTMLDivElement[] = [];
98
+ params.line.mols.forEach((molIdx: number, hostIdx: number) => {
99
+ const activity = ui.divText(params.activityCol.get(molIdx).toFixed(2));
100
+ activity.style.paddingLeft = '15px';
101
+ activity.style.paddingLeft = '10px';
102
+ const molHost = ui.divText(params.seqCol.get(molIdx));
103
+ if (params.df.currentRowIdx === molIdx) {
104
+ molHost.style.border = 'solid 1px lightgrey';
105
+ }
106
+ //@ts-ignore
107
+ ui.tooltip.bind(molHost, () => moleculeInfo(params.df, molIdx, params.seqCol.name));
108
+ molHost.onclick = () => {
109
+ const obj = grok.shell.o;
110
+ molHost.style.border = 'solid 1px lightgrey';
111
+ params.df.currentRowIdx = molIdx;
112
+ hosts.forEach((h, i) => {
113
+ if (i !== hostIdx) {
114
+ h.style.border = '';
115
+ }
116
+ })
117
+ setTimeout(() => {
118
+ grok.shell.o = obj
119
+ }, 1000);
120
+ };
121
+ propPanel.append(ui.divH([
122
+ molHost,
123
+ activity,
124
+ ]));
125
+ hosts.push(molHost);
126
+ });
127
+ propPanel.append(ui.divH([
128
+ ui.divText(`Cliff: `, {style: {fontWeight: 'bold', paddingRight: '5px'}}),
129
+ ui.divText(params.sali!.toFixed(2))
130
+ ]));
131
+ return propPanel;
132
+ }
@@ -0,0 +1,261 @@
1
+ <html><head><meta charset="utf-8"/><title>Bio Test Report. Datagrok version datagrok/datagrok:latest SHA=f1ac5a5eade4. Commit e2085bf5.</title><style type="text/css">html,
2
+ body {
3
+ font-family: Arial, Helvetica, sans-serif;
4
+ font-size: 1rem;
5
+ margin: 0;
6
+ padding: 0;
7
+ color: #333;
8
+ }
9
+ body {
10
+ padding: 2rem 1rem;
11
+ font-size: 0.85rem;
12
+ }
13
+ #jesthtml-content {
14
+ margin: 0 auto;
15
+ max-width: 70rem;
16
+ }
17
+ header {
18
+ display: flex;
19
+ align-items: center;
20
+ }
21
+ #title {
22
+ margin: 0;
23
+ flex-grow: 1;
24
+ }
25
+ #logo {
26
+ height: 4rem;
27
+ }
28
+ #timestamp {
29
+ color: #777;
30
+ margin-top: 0.5rem;
31
+ }
32
+
33
+ /** SUMMARY */
34
+ #summary {
35
+ color: #333;
36
+ margin: 2rem 0;
37
+ display: flex;
38
+ font-family: monospace;
39
+ font-size: 1rem;
40
+ }
41
+ #summary > div {
42
+ margin-right: 2rem;
43
+ background: #eee;
44
+ padding: 1rem;
45
+ min-width: 15rem;
46
+ }
47
+ #summary > div:last-child {
48
+ margin-right: 0;
49
+ }
50
+ @media only screen and (max-width: 720px) {
51
+ #summary {
52
+ flex-direction: column;
53
+ }
54
+ #summary > div {
55
+ margin-right: 0;
56
+ margin-top: 2rem;
57
+ }
58
+ #summary > div:first-child {
59
+ margin-top: 0;
60
+ }
61
+ }
62
+
63
+ .summary-total {
64
+ font-weight: bold;
65
+ margin-bottom: 0.5rem;
66
+ }
67
+ .summary-passed {
68
+ color: #4f8a10;
69
+ border-left: 0.4rem solid #4f8a10;
70
+ padding-left: 0.5rem;
71
+ }
72
+ .summary-failed,
73
+ .summary-obsolete-snapshots {
74
+ color: #d8000c;
75
+ border-left: 0.4rem solid #d8000c;
76
+ padding-left: 0.5rem;
77
+ }
78
+ .summary-pending {
79
+ color: #9f6000;
80
+ border-left: 0.4rem solid #9f6000;
81
+ padding-left: 0.5rem;
82
+ }
83
+ .summary-empty {
84
+ color: #999;
85
+ border-left: 0.4rem solid #999;
86
+ }
87
+
88
+ .test-result {
89
+ padding: 1rem;
90
+ margin-bottom: 0.25rem;
91
+ }
92
+ .test-result:last-child {
93
+ border: 0;
94
+ }
95
+ .test-result.passed {
96
+ background-color: #dff2bf;
97
+ color: #4f8a10;
98
+ }
99
+ .test-result.failed {
100
+ background-color: #ffbaba;
101
+ color: #d8000c;
102
+ }
103
+ .test-result.pending {
104
+ background-color: #ffdf61;
105
+ color: #9f6000;
106
+ }
107
+
108
+ .test-info {
109
+ display: flex;
110
+ justify-content: space-between;
111
+ }
112
+ .test-suitename {
113
+ width: 20%;
114
+ text-align: left;
115
+ font-weight: bold;
116
+ word-break: break-word;
117
+ }
118
+ .test-title {
119
+ width: 40%;
120
+ text-align: left;
121
+ font-style: italic;
122
+ }
123
+ .test-status {
124
+ width: 20%;
125
+ text-align: right;
126
+ }
127
+ .test-duration {
128
+ width: 10%;
129
+ text-align: right;
130
+ font-size: 0.75rem;
131
+ }
132
+
133
+ .failureMessages {
134
+ padding: 0 1rem;
135
+ margin-top: 1rem;
136
+ border-top: 1px dashed #d8000c;
137
+ }
138
+ .failureMessages.suiteFailure {
139
+ border-top: none;
140
+ }
141
+ .failureMsg {
142
+ white-space: pre-wrap;
143
+ white-space: -moz-pre-wrap;
144
+ white-space: -pre-wrap;
145
+ white-space: -o-pre-wrap;
146
+ word-wrap: break-word;
147
+ }
148
+
149
+ .suite-container {
150
+ margin-bottom: 2rem;
151
+ }
152
+ .suite-info {
153
+ padding: 1rem;
154
+ background-color: #eee;
155
+ color: #777;
156
+ display: flex;
157
+ align-items: center;
158
+ margin-bottom: 0.25rem;
159
+ }
160
+ .suite-info .suite-path {
161
+ word-break: break-all;
162
+ flex-grow: 1;
163
+ font-family: monospace;
164
+ font-size: 1rem;
165
+ }
166
+ .suite-info .suite-time {
167
+ margin-left: 0.5rem;
168
+ padding: 0.2rem 0.3rem;
169
+ font-size: 0.75rem;
170
+ }
171
+ .suite-info .suite-time.warn {
172
+ background-color: #d8000c;
173
+ color: #fff;
174
+ }
175
+
176
+ /* CONSOLE LOGS */
177
+ .suite-consolelog {
178
+ margin-bottom: 0.25rem;
179
+ padding: 1rem;
180
+ background-color: #efefef;
181
+ }
182
+ .suite-consolelog-header {
183
+ font-weight: bold;
184
+ }
185
+ .suite-consolelog-item {
186
+ padding: 0.5rem;
187
+ }
188
+ .suite-consolelog-item pre {
189
+ margin: 0.5rem 0;
190
+ white-space: pre-wrap;
191
+ white-space: -moz-pre-wrap;
192
+ white-space: -pre-wrap;
193
+ white-space: -o-pre-wrap;
194
+ word-wrap: break-word;
195
+ }
196
+ .suite-consolelog-item-origin {
197
+ color: #777;
198
+ font-weight: bold;
199
+ }
200
+ .suite-consolelog-item-message {
201
+ color: #000;
202
+ font-size: 1rem;
203
+ padding: 0 0.5rem;
204
+ }
205
+
206
+ /* OBSOLETE SNAPSHOTS */
207
+ .suite-obsolete-snapshots {
208
+ margin-bottom: 0.25rem;
209
+ padding: 1rem;
210
+ background-color: #ffbaba;
211
+ color: #d8000c;
212
+ }
213
+ .suite-obsolete-snapshots-header {
214
+ font-weight: bold;
215
+ }
216
+ .suite-obsolete-snapshots-item {
217
+ padding: 0.5rem;
218
+ }
219
+ .suite-obsolete-snapshots-item pre {
220
+ margin: 0.5rem 0;
221
+ white-space: pre-wrap;
222
+ white-space: -moz-pre-wrap;
223
+ white-space: -pre-wrap;
224
+ white-space: -o-pre-wrap;
225
+ word-wrap: break-word;
226
+ }
227
+ .suite-obsolete-snapshots-item-message {
228
+ color: #000;
229
+ font-size: 1rem;
230
+ padding: 0 0.5rem;
231
+ }
232
+ </style></head><body><div id="jesthtml-content"><header><h1 id="title">Bio Test Report. Datagrok version datagrok/datagrok:latest SHA=f1ac5a5eade4. Commit e2085bf5.</h1></header><div id="metadata-container"><div id="timestamp">Started: 2022-09-08 09:07:23</div><div id="summary"><div id="suite-summary"><div class="summary-total">Suites (1)</div><div class="summary-passed summary-empty">0 passed</div><div class="summary-failed">1 failed</div><div class="summary-pending summary-empty">0 pending</div></div><div id="test-summary"><div class="summary-total">Tests (1)</div><div class="summary-passed summary-empty">0 passed</div><div class="summary-failed">1 failed</div><div class="summary-pending summary-empty">0 pending</div></div></div></div><div id="suite-1" class="suite-container"><div class="suite-info"><div class="suite-path">/home/runner/work/public/public/packages/Bio/src/__jest__/remote.test.ts</div><div class="suite-time warn">10.876s</div></div><div class="suite-tests"><div class="test-result failed"><div class="test-info"><div class="test-suitename"> </div><div class="test-title">TEST</div><div class="test-status">failed</div><div class="test-duration">0s</div></div><div class="failureMessages"> <pre class="failureMsg">Error: Unknown server alias. Please add it to /home/runner/.grok/config.yaml
233
+ at getDevKey (/home/runner/work/public/public/packages/Bio/src/__jest__/test-node.ts:48:13)
234
+ at Object.&lt;anonymous&gt; (/home/runner/work/public/public/packages/Bio/src/__jest__/test-node.ts:57:15)
235
+ at Generator.next (&lt;anonymous&gt;)
236
+ at /home/runner/work/public/public/packages/Bio/src/__jest__/test-node.ts:31:71
237
+ at new Promise (&lt;anonymous&gt;)
238
+ at Object.&lt;anonymous&gt;.__awaiter (/home/runner/work/public/public/packages/Bio/src/__jest__/test-node.ts:27:12)
239
+ at Object.getBrowserPage (/home/runner/work/public/public/packages/Bio/src/__jest__/test-node.ts:94:12)
240
+ at /home/runner/work/public/public/packages/Bio/src/__jest__/remote.test.ts:13:27
241
+ at Generator.next (&lt;anonymous&gt;)
242
+ at /home/runner/work/public/public/packages/Bio/src/__jest__/remote.test.ts:34:71
243
+ at new Promise (&lt;anonymous&gt;)
244
+ at Object.&lt;anonymous&gt;.__awaiter (/home/runner/work/public/public/packages/Bio/src/__jest__/remote.test.ts:30:12)
245
+ at /home/runner/work/public/public/packages/Bio/src/__jest__/remote.test.ts:12:22
246
+ at Promise.then.completed (/home/runner/work/public/public/packages/Bio/node_modules/jest-circus/build/utils.js:391:28)
247
+ at new Promise (&lt;anonymous&gt;)
248
+ at callAsyncCircusFn (/home/runner/work/public/public/packages/Bio/node_modules/jest-circus/build/utils.js:316:10)
249
+ at _callCircusHook (/home/runner/work/public/public/packages/Bio/node_modules/jest-circus/build/run.js:181:40)
250
+ at _runTestsForDescribeBlock (/home/runner/work/public/public/packages/Bio/node_modules/jest-circus/build/run.js:47:7)
251
+ at run (/home/runner/work/public/public/packages/Bio/node_modules/jest-circus/build/run.js:25:3)
252
+ at runAndTransformResultsToJestFormat (/home/runner/work/public/public/packages/Bio/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21)
253
+ at jestAdapter (/home/runner/work/public/public/packages/Bio/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19)
254
+ at runTestInternal (/home/runner/work/public/public/packages/Bio/node_modules/jest-runner/build/runTest.js:389:16)
255
+ at runTest (/home/runner/work/public/public/packages/Bio/node_modules/jest-runner/build/runTest.js:475:34)
256
+ at TestRunner.runTests (/home/runner/work/public/public/packages/Bio/node_modules/jest-runner/build/index.js:101:12)
257
+ at TestScheduler.scheduleTests (/home/runner/work/public/public/packages/Bio/node_modules/@jest/core/build/TestScheduler.js:333:13)
258
+ at runJest (/home/runner/work/public/public/packages/Bio/node_modules/@jest/core/build/runJest.js:404:19)
259
+ at _run10000 (/home/runner/work/public/public/packages/Bio/node_modules/@jest/core/build/cli/index.js:320:7)
260
+ at runCLI (/home/runner/work/public/public/packages/Bio/node_modules/@jest/core/build/cli/index.js:173:3)
261
+ at Object.run (/home/runner/work/public/public/packages/Bio/node_modules/jest-cli/build/cli/index.js:155:37)</pre></div></div></div></div></div></body></html>