Skip to content

Commit d98f62a

Browse files
authored
Merge pull request #968 from ForomePlatform/trace-variant-ui
Trace variant UI
2 parents 0938524 + 534c17f commit d98f62a

File tree

18 files changed

+599
-34
lines changed

18 files changed

+599
-34
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "anfisa-react-client",
3-
"version": "0.11.4-develop",
3+
"version": "0.11.6-develop",
44
"private": true,
55
"dependencies": {
66
"@monaco-editor/react": "4.3.1",

src/components/popup-card/popup-card.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export interface IPopupCardProps {
1717
onApply?: (event: MouseEvent<HTMLButtonElement>) => void
1818
isApplyDisabled?: boolean
1919
isLoading?: boolean
20-
additionalBottomButton?: Element
20+
additionalBottomButton?: JSX.Element
2121
applyAppend?: ReactNode
2222
}
2323

src/i18n/locales/en.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,15 @@ export const en = {
463463
loadDtree: 'Failed to load dtree "{dtreeName}"',
464464
},
465465
textEditor: 'Text editor',
466+
traceVariant: {
467+
title: 'Trace a variant',
468+
go: 'Trace',
469+
history: 'History',
470+
results: 'Results',
471+
stop: 'Stop',
472+
close: 'Close',
473+
filteredOut: 'filtered out',
474+
},
466475
},
467476
error: {
468477
getBack: 'Back to home',

src/pages/filter/dtree/components/query-builder/query-builder-results.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import stepStore from '@store/dtree/step.store'
88
import { Button } from '@ui/button'
99
import { DecisionTreesResultsDataCy } from '@data-testid'
1010
import { QueryBuilderResultsNumbers } from './query-builder-results-numbers'
11+
import { TraceVariant } from './ui/trace-variant/trace-variant'
1112

1213
interface IQueryBuilderResultsProps {
1314
className?: string
@@ -55,13 +56,14 @@ export const QueryBuilderResults = observer(
5556
<QueryBuilderResultsNumbers className="mt-1" />
5657
</div>
5758
<div className="flex">
59+
{(shouldShowReturnedVariants || hasStartVariants) && <TraceVariant />}
5860
{shouldShowReturnedVariants && (
5961
<Button
6062
dataTestId={DecisionTreesResultsDataCy.viewReturnedVariants}
6163
onClick={() => openTableModal(true)}
6264
text={t('dtree.viewReturnedVariants')}
6365
variant="secondary"
64-
className="ml-auto min-h-32"
66+
className="ml-5 min-h-32"
6567
/>
6668
)}
6769

src/pages/filter/dtree/components/query-builder/query-builder-tree-view.tsx

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ReactElement } from 'react'
1+
import { ReactElement, useEffect, useRef } from 'react'
22
import cn from 'classnames'
33
import { observer } from 'mobx-react-lite'
44

@@ -15,22 +15,41 @@ export const QueryBuilderTreeView = observer(
1515
({ className }: IQueryBuilderTreeViewProps): ReactElement => {
1616
const { filteredSteps } = stepStore
1717

18+
const activeElement = useRef<HTMLDivElement>(null)
19+
useEffect(() => {
20+
activeElement?.current?.scrollIntoView({
21+
behavior: 'smooth',
22+
block: 'start',
23+
})
24+
stepStore.scrollToStep(undefined)
25+
})
26+
1827
return (
1928
<div id="parent" className={cn('flex flex-col', className)}>
2029
{filteredSteps.map((element, index: number) => {
2130
const key = element.groups
2231
? JSON.stringify(element.groups) + index
2332
: index
2433

25-
return element.isFinalStep ? (
26-
<FinalStep key={key} index={index} />
27-
) : (
28-
<NextStep
29-
key={key}
30-
index={index}
31-
changeIndicator={dtreeStore.resultsChangeIndicator}
32-
isContentExpanded={dtreeStore.isResultsContentExpanded}
33-
/>
34+
return (
35+
<div
36+
ref={
37+
index === stepStore.scrollToStepIndex
38+
? activeElement
39+
: undefined
40+
}
41+
>
42+
{element.isFinalStep ? (
43+
<FinalStep key={key} index={index} />
44+
) : (
45+
<NextStep
46+
key={key}
47+
index={index}
48+
changeIndicator={dtreeStore.resultsChangeIndicator}
49+
isContentExpanded={dtreeStore.isResultsContentExpanded}
50+
/>
51+
)}
52+
</div>
3453
)
3554
})}
3655
</div>

src/pages/filter/dtree/components/query-builder/ui/next-step/next-step.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ export const NextStep = observer(
5959
className={cn(
6060
styles.nextStep__treeView,
6161
'pr-3',
62-
currentStep.isReturnedVariantsActive ? ' bg-blue-tertiary' : '',
62+
currentStep.isReturnedVariantsActive ? ' bg-blue-medium' : '',
6363
)}
6464
>
6565
<NextStepRoute
@@ -74,7 +74,7 @@ export const NextStep = observer(
7474
className={cn(
7575
styles.nextStep__resultsView,
7676
'border-b border-l border-grey-light font-medium px-5 relative',
77-
currentStep.isActive && ' bg-blue-tertiary',
77+
currentStep.isActive && ' bg-blue-medium',
7878
)}
7979
onClick={event => setStepActive(event)}
8080
>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import styles from './trace-variant.module.css'
2+
3+
import { FC } from 'react'
4+
import cn from 'classnames'
5+
import { observer } from 'mobx-react-lite'
6+
7+
import { t } from '@i18n'
8+
import { Button } from '@ui/button'
9+
import { Icon } from '@ui/icon'
10+
// import { MainTableDataCy } from '@data-testid'
11+
12+
interface ITraceVariantButtonProps {
13+
onClick: (target: HTMLElement) => void
14+
isOpen: boolean
15+
}
16+
17+
export const TraceVariantButton: FC<ITraceVariantButtonProps> = observer(
18+
({ onClick, isOpen }) => (
19+
<Button
20+
dataTestId="TODO"
21+
text={t('dtree.traceVariant.title')}
22+
append={
23+
<Icon
24+
name="Arrow"
25+
size={14}
26+
className={cn(
27+
styles.traceVariant__buttonIcon_arrow,
28+
isOpen && styles.traceVariant__buttonIcon_arrow_opened,
29+
)}
30+
/>
31+
}
32+
onClick={e => onClick(e.currentTarget)}
33+
variant="secondary"
34+
className="ml-auto min-h-32"
35+
/>
36+
),
37+
)
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
import styles from './trace-variant.module.css'
2+
3+
import { FC, useState } from 'react'
4+
import { observer } from 'mobx-react-lite'
5+
6+
import { t } from '@i18n'
7+
import { DtreeTraceAsyncStore } from '@store/dtree/dtree-trace.async.store'
8+
import stepStore, { ActiveStepOptions } from '@store/dtree/step.store'
9+
import { Button } from '@ui/button'
10+
import { Input } from '@ui/input'
11+
import { Loader } from '@ui/loader'
12+
import { MenuList, MenuListItem } from '@ui/menu-list'
13+
import { Popover } from '@ui/popover'
14+
import { IPopoverBaseProps } from '@ui/popover/popover.interface'
15+
import { PopupCard } from '@components/popup-card/popup-card'
16+
import { TracesResultView } from './trace-variant-results'
17+
18+
export interface ITraceVariantButtonProps extends IPopoverBaseProps {
19+
traceStore: DtreeTraceAsyncStore
20+
}
21+
22+
export type PointToStepIdx = (p: number) => number | undefined
23+
export type PointToStepName = (p: number) => string | undefined
24+
25+
export const TraceVariantPopover: FC<ITraceVariantButtonProps> = observer(
26+
({ isOpen, anchorEl, onClose, traceStore }) => {
27+
const { data, isLoading, activeJobStatus } = traceStore
28+
const [variant, setVariant] = useState<string>('')
29+
const [isStopped, setStopped] = useState<boolean>(true)
30+
const [isHistoryShown, showHistory] = useState<boolean>(false)
31+
//const [transcript] = useState<string>('') // reserved for future use
32+
const transcript = ''
33+
34+
const dataReady: boolean = !!(
35+
data && data[0].variant.trim() === variant.trim()
36+
)
37+
38+
const point2stepIdx: PointToStepIdx = p => {
39+
const idx = stepStore.steps.findIndex(
40+
step => step.returnPointIndex === p || step.conditionPointIndex === p,
41+
)
42+
return idx < 0 ? undefined : idx
43+
}
44+
45+
const point2step: PointToStepName = p => {
46+
const idx = point2stepIdx(p)
47+
if (idx != null) {
48+
return stepStore.steps[idx].isFinalStep
49+
? 'Final Step'
50+
: `Step ${stepStore.steps[idx].step}`
51+
}
52+
}
53+
54+
const keys = traceStore.getCacheKeys()
55+
56+
const selectStep = (pointNo: number) => {
57+
const theStepIdx = point2stepIdx(pointNo)
58+
if (pointNo) {
59+
stepStore.makeStepActive({
60+
index: theStepIdx ?? -1,
61+
option: ActiveStepOptions.ReturnedVariants,
62+
})
63+
stepStore.scrollToStep(theStepIdx)
64+
}
65+
}
66+
67+
const historyButton = () => {
68+
if (isLoading) {
69+
return (
70+
<Button
71+
onClick={() => {
72+
setStopped(true)
73+
traceStore.abortController?.abort()
74+
traceStore.invalidate()
75+
}}
76+
text={t('dtree.traceVariant.stop')}
77+
variant="diestruction"
78+
disabled={isStopped}
79+
/>
80+
)
81+
} else if (keys.length > 0) {
82+
return (
83+
<Button
84+
onClick={() => {
85+
showHistory(!isHistoryShown)
86+
}}
87+
text={t(
88+
`dtree.traceVariant.${isHistoryShown ? 'results' : 'history'}`,
89+
)}
90+
variant="secondary"
91+
/>
92+
)
93+
}
94+
}
95+
96+
const displayHistory = () => {
97+
return (
98+
<div onMouseUp={event => event.stopPropagation()}>
99+
<MenuList className={styles.traceVariant__results__container}>
100+
{keys.map(key => (
101+
<MenuListItem
102+
label={key}
103+
onClick={() => {
104+
setImmediate(() =>
105+
traceStore.setQuery({ variant: key, transcript }),
106+
)
107+
setVariant(key)
108+
showHistory(false)
109+
}}
110+
/>
111+
))}
112+
</MenuList>
113+
</div>
114+
)
115+
}
116+
117+
const displayData = () => {
118+
if (isLoading) {
119+
return activeJobStatus ? (
120+
<div>{activeJobStatus}</div>
121+
) : (
122+
<Loader size="xs" />
123+
)
124+
}
125+
if (data && dataReady) {
126+
return data[1] === 'Finished' ? (
127+
<TracesResultView
128+
data={data[0]}
129+
point2step={point2step.bind(this)}
130+
selectStep={selectStep.bind(this)}
131+
/>
132+
) : (
133+
<div style={{ color: 'red' }}>{`Error: ${data[0].error}`}</div>
134+
)
135+
}
136+
}
137+
138+
return (
139+
<>
140+
<Popover
141+
isOpen={isOpen}
142+
anchorEl={anchorEl}
143+
onClose={onClose}
144+
className={styles.traceVariant__popover}
145+
>
146+
<PopupCard
147+
title={t('dtree.traceVariant.title')}
148+
onClose={onClose}
149+
onApply={() => {
150+
setStopped(false)
151+
const v = variant.trim()
152+
if (v !== variant) setVariant(v)
153+
traceStore.setQuery({ variant: v, transcript })
154+
showHistory(false)
155+
}}
156+
isApplyDisabled={variant.length < 7 || isLoading || dataReady}
157+
isLoading={false}
158+
cancelText={t('dtree.traceVariant.close')}
159+
applyText={t('dtree.traceVariant.go')}
160+
additionalBottomButton={historyButton()}
161+
>
162+
<Input
163+
onChange={e => setVariant(e.target.value)}
164+
value={variant}
165+
shape="brick"
166+
placeholder="enter variant id"
167+
size="m"
168+
/>
169+
<div style={{ height: '0.7em' }} />
170+
{isHistoryShown ? displayHistory() : displayData()}
171+
</PopupCard>
172+
</Popover>
173+
</>
174+
)
175+
},
176+
)

0 commit comments

Comments
 (0)