Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/notebooks-launch-time' into mult…
Browse files Browse the repository at this point in the history
…iplatform-docker-image
  • Loading branch information
Nikita-Smirnov-Exactpro committed Sep 26, 2024
2 parents 8272f2f + 6c18ff6 commit 55e6ee2
Show file tree
Hide file tree
Showing 33 changed files with 1,651 additions and 588 deletions.
4 changes: 3 additions & 1 deletion src/api/ApiSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,9 @@ export interface BooksApiSchema {
export interface JSONViewerApiSchema {
getLinks: (type: string, dir?: string) => Promise<{ directories: string[]; files: string[] }>;
getParameters: (path: string) => Promise<NotebookParameters>;
getResults: (taskId: string) => Promise<{ status: string; result: string; path?: string }>;
getResults: (
taskId: string,
) => Promise<{ status: string; result: string; path?: string; customization?: string }>;
getFile: (path: string) => Promise<{ result: string }>;
launchNotebook: (path: string, parameters?: Object) => Promise<{ task_id: string }>;
stopNotebook: (taskId: string) => Promise<boolean>;
Expand Down
31 changes: 28 additions & 3 deletions src/components/JSONViewer/DisplayTable.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { observer } from 'mobx-react-lite';
import React from 'react';
import { useJSONViewerStore } from '../../hooks/useJSONViewerStore';
import multiTokenSplit from '../../helpers/search/multiTokenSplit';

const shownCapacity = 50;

const DisplayTable = ({ value }: { value: string[][] | undefined }) => {
const JSONViewerStore = useJSONViewerStore();
const [shownSize, setShownSize] = React.useState(shownCapacity);
if (!value) return <div className='display-table-error'>#display-table is undefined</div>;

Expand All @@ -15,7 +19,16 @@ const DisplayTable = ({ value }: { value: string[][] | undefined }) => {
<thead>
<tr>
{header.map((key, index) => (
<th key={index}>{key}</th>
<th key={index}>
{multiTokenSplit(key, JSONViewerStore.tokens).map((contentPart, i) => (
<span
key={i}
className={contentPart.token != null ? 'found-content' : undefined}
style={{ backgroundColor: contentPart.token?.color }}>
{contentPart.content}
</span>
))}
</th>
))}
<th style={{ width: '16px' }}></th>
</tr>
Expand All @@ -24,7 +37,19 @@ const DisplayTable = ({ value }: { value: string[][] | undefined }) => {
{rows.slice(0, shownSize).map((row, index) => (
<tr key={index}>
{row.slice(0, header.length).map((val, ind) => (
<td key={ind}>{typeof val === 'string' ? `"${val}"` : String(val)}</td>
<td key={ind}>
{multiTokenSplit(
typeof val === 'string' ? `"${val}"` : String(val),
JSONViewerStore.tokens,
).map((contentPart, i) => (
<span
key={i}
className={contentPart.token != null ? 'found-content' : undefined}
style={{ backgroundColor: contentPart.token?.color }}>
{contentPart.content}
</span>
))}
</td>
))}
{row.length < header.length &&
Array(header.length - row.length)
Expand Down Expand Up @@ -53,4 +78,4 @@ const DisplayTable = ({ value }: { value: string[][] | undefined }) => {
);
};

export default DisplayTable;
export default observer(DisplayTable);
46 changes: 33 additions & 13 deletions src/components/JSONViewer/FileChoosing.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
import * as React from 'react';
import { nanoid } from 'nanoid';
import { TreeNode } from '../../models/JSONSchema';
import { NotebookNode, NotebookParameters, TreeNode } from '../../models/JSONSchema';
import { ModalPortal } from '../util/Portal';
import { useOutsideClickListener } from '../../hooks';
import api from '../../api';
import { parseText } from '../../helpers/JSONViewer';
import { convertParameterToInput, parseText } from '../../helpers/JSONViewer';

const FileChoosing = ({
type,
multiple,
onSubmit,
singleSubmit,
close,
}: {
type: 'notebooks' | 'results' | 'all';
multiple: boolean;
onSubmit: (t: TreeNode[], n: string[]) => void;
onSubmit?: (t: TreeNode[], n: NotebookNode[]) => void;
singleSubmit?: (f: string) => void;
close: () => void;
}) => {
const [isLoading, setIsLoading] = React.useState(true);
Expand Down Expand Up @@ -73,26 +75,44 @@ const FileChoosing = ({

const getFiles = () => {
const fileData: TreeNode[] = [];
const notebookData: string[] = [];
const notebookData: NotebookNode[] = [];
const promises: Promise<void>[] = [];
if (selectedFiles.length > 0) {
setIsLoading(true);
if (type === 'notebooks' || type === 'all') onSubmit([], selectedFiles);
else {
if (type === 'notebooks') {
selectedFiles.forEach(filePath =>
promises.push(
api.jsonViewer.getParameters(filePath).then((data: NotebookParameters) => {
const parameters = Object.values(data).filter(param => param.name !== 'output_path');
const paramsValue = parameters.map(convertParameterToInput);
const node: NotebookNode = {
name: filePath,
parameters,
paramsValue,
results: [],
resultsCount: '1',
open: true,
};
notebookData.push(node);
}),
),
);
Promise.all(promises).then(() => {
if (onSubmit) onSubmit([], notebookData);
});
} else {
selectedFiles.forEach(filePath =>
promises.push(
api.jsonViewer.getFile(filePath).then(({ result }) => {
if (filePath.endsWith('.ipynb')) {
notebookData.push(filePath);
return;
}
const node: TreeNode = {
id: nanoid(),
parentIds: [],
key: filePath,
failed: false,
viewInstruction: '',
simpleFields: [],
complexFields: [],
childIds: [],
isGeneratedKey: true,
isRoot: true,
};
Expand All @@ -111,7 +131,7 @@ const FileChoosing = ({
),
);
Promise.all(promises).then(() => {
onSubmit(fileData, notebookData);
if (onSubmit) onSubmit(fileData, notebookData);
});
}
}
Expand All @@ -120,8 +140,8 @@ const FileChoosing = ({

const selectFile = (fileName: string) => {
const fileIndex = selectedFiles.indexOf(fileName);
if (!multiple) {
onSubmit([], [fileName]);
if (!multiple && singleSubmit) {
singleSubmit(fileName);
return;
}

Expand Down
28 changes: 28 additions & 0 deletions src/components/JSONViewer/JSONPanel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react';
import { observer } from 'mobx-react-lite';
import '../../styles/JSONviewer.scss';
import SplitView from '../split-view/SplitView';
import SplitViewPane from '../split-view/SplitViewPane';
import TreeList from './TreeList';
import TablePanel from './TablePanel';

interface props {
type: 'left' | 'right';
}

const JSONPanel = ({ type }: props) => {
const [panelArea, setPanelArea] = React.useState(100);

return (
<SplitView panelArea={panelArea} onPanelAreaChange={setPanelArea} maxWidth={window.innerWidth}>
<SplitViewPane>
<TreeList type={type} />
</SplitViewPane>
<SplitViewPane>
<TablePanel type={type} />
</SplitViewPane>
</SplitView>
);
};

export default observer(JSONPanel);
67 changes: 63 additions & 4 deletions src/components/JSONViewer/JSONView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import { observer } from 'mobx-react-lite';
import debounce from 'lodash.debounce';
import { TreeNode } from '../../models/JSONSchema';
import { createBemElement } from '../../helpers/styleCreators';
import SearchToken from '../../models/search/SearchToken';
import { getKeyValueTokens } from '../../helpers/search/getSpecificTokens';
import multiTokenSplit from '../../helpers/search/multiTokenSplit';

const BEAUTIFIED_PAD_VALUE = 15;

Expand All @@ -11,6 +14,7 @@ interface JSONViewProps {
isBeautified: boolean;
isArrayElement?: boolean;
setIsHighlighted?: (isHighlighted: boolean) => void;
tokens: SearchToken[];
}

interface JSONViewFieldsReqProps {
Expand All @@ -19,6 +23,7 @@ interface JSONViewFieldsReqProps {
isArrayElement?: boolean;
setIsHighlighted: (isHighlighted: boolean) => void;
field: any;
tokens: SearchToken[];
}

const JSONViewSimpleField = ({
Expand All @@ -27,8 +32,23 @@ const JSONViewSimpleField = ({
isBeautified,
isArrayElement,
setIsHighlighted,
tokens,
}: JSONViewFieldsReqProps) => {
const highlight = React.useMemo(() => debounce(() => setIsHighlighted(true), 60), []);
const valueString =
typeof field === 'object'
? JSON.stringify(field)
: typeof field === 'string'
? `"${field}"`
: String(field);
const keyValueTokens = getKeyValueTokens(tokens, true).filter(
({ isOne, keyToken, valueToken }) =>
!isOne ||
(`${label}:`.endsWith(keyToken.pattern) && valueString.startsWith(valueToken.pattern)),
);

const keyTokens = keyValueTokens.map(({ keyToken }) => keyToken);
const valueTokens = keyValueTokens.map(({ valueToken }) => valueToken);

const removeHighlight = React.useCallback(() => {
highlight.cancel();
Expand All @@ -45,20 +65,48 @@ const JSONViewSimpleField = ({
onMouseEnter={highlight}
onMouseLeave={removeHighlight}
className='mc-body__field-label'>
{label && !isArrayElement ? `${label}: ` : ''}
{label && !isArrayElement
? multiTokenSplit(`${label}: `, keyTokens).map((contentPart, index) => (
<span
key={index}
className={contentPart.token != null ? 'found-content' : undefined}
style={{ backgroundColor: contentPart.token?.color }}>
{contentPart.content}
</span>
))
: ''}
</span>
<span
onMouseEnter={highlight}
onMouseLeave={removeHighlight}
className='mc-body__field-simple-value'>
{typeof field === 'object' ? JSON.stringify(field) : String(field)}
{multiTokenSplit(valueString, valueTokens).map((contentPart, index) => (
<span
key={index}
className={contentPart.token != null ? 'found-content' : undefined}
style={{ backgroundColor: contentPart.token?.color }}>
{contentPart.content}
</span>
))}
</span>
</span>
);
};

const JSONView = ({ node, isBeautified, setIsHighlighted, isArrayElement }: JSONViewProps) => {
const JSONView = ({
node,
isBeautified,
setIsHighlighted,
isArrayElement,
tokens,
}: JSONViewProps) => {
const [areSameContext, highlightSameContext] = React.useState(false);
const keyValueTokens = getKeyValueTokens(tokens, true).filter(
({ isOne, keyToken, valueToken }) =>
!isOne || (`${node.key}:`.endsWith(keyToken.pattern) && valueToken.pattern === ''),
);

const keyTokens = keyValueTokens.map(({ keyToken }) => keyToken);

const highlight = React.useMemo(
() =>
Expand All @@ -83,7 +131,16 @@ const JSONView = ({ node, isBeautified, setIsHighlighted, isArrayElement }: JSON
onMouseEnter={highlight}
onMouseLeave={removeHighlight}>
<span className='mc-body__field-label'>
{!node.isGeneratedKey && node.key !== '' && !isArrayElement ? `${node.key}:` : ''}
{!node.isGeneratedKey && node.key !== '' && !isArrayElement
? multiTokenSplit(`${node.key}:`, keyTokens).map((contentPart, index) => (
<span
key={index}
className={contentPart.token != null ? 'found-content' : undefined}
style={{ backgroundColor: contentPart.token?.color }}>
{contentPart.content}
</span>
))
: ''}
</span>
<span
className={createBemElement('mc-body', 'field-border', areSameContext ? 'active' : null)}>
Expand All @@ -102,6 +159,7 @@ const JSONView = ({ node, isBeautified, setIsHighlighted, isArrayElement }: JSON
isArrayElement={node.isArray}
isBeautified={isBeautified}
setIsHighlighted={highlightSameContext}
tokens={tokens}
/>
{isBeautified || idx === arr.length - 1 ? null : ', '}
</React.Fragment>
Expand All @@ -116,6 +174,7 @@ const JSONView = ({ node, isBeautified, setIsHighlighted, isArrayElement }: JSON
isArrayElement={node.isArray}
isBeautified={isBeautified}
setIsHighlighted={highlightSameContext}
tokens={tokens}
/>
{isBeautified || idx === arr.length - 1 ? null : ', '}
</React.Fragment>
Expand Down
Loading

0 comments on commit 55e6ee2

Please sign in to comment.