Chore: logs pipelines help in UI (#3971)

* chore: logs pipelines: add help text with link to pipeline docs

* chore: add logs pipelines list empty state with help video and link to docs

* chore: minor cleanup

* chore: update test snapshot

* chore: dont show table & filter in pipeline lists empty state

* chore: add sandbox constraints to logs pipelines empty state video iframe

* chore: update test snapshot
This commit is contained in:
Raj Kamal Singh 2023-11-17 14:01:28 +05:30 committed by GitHub
parent 75526c6de5
commit 31b5635339
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 116 additions and 229 deletions

View File

@ -5,6 +5,7 @@
"create": "Create", "create": "Create",
"reorder": "Reorder", "reorder": "Reorder",
"cancel": "Cancel", "cancel": "Cancel",
"learn_more": "Learn more about pipelines",
"reorder_pipeline": "Do you want to reorder pipeline?", "reorder_pipeline": "Do you want to reorder pipeline?",
"reorder_pipeline_description": "Logs are processed sequentially in processors and pipelines. Reordering it may change how data is processed by them.", "reorder_pipeline_description": "Logs are processed sequentially in processors and pipelines. Reordering it may change how data is processed by them.",
"delete_pipeline": "Do you want to delete pipeline", "delete_pipeline": "Do you want to delete pipeline",

View File

@ -40,7 +40,10 @@ function CreatePipelineButton({
return ( return (
<ButtonContainer> <ButtonContainer>
<TextToolTip text={t('add_new_pipeline')} /> <TextToolTip
text={t('learn_more')}
url="https://signoz.io/docs/logs-pipelines/introduction/"
/>
{isAddNewPipelineVisible && ( {isAddNewPipelineVisible && (
<CustomButton <CustomButton
icon={<EditFilled />} icon={<EditFilled />}

View File

@ -3,7 +3,6 @@ import { Pipeline } from 'types/api/pipeline/def';
import PipelineListsView from '../../PipelineListsView'; import PipelineListsView from '../../PipelineListsView';
import CreatePipelineButton from './CreatePipelineButton'; import CreatePipelineButton from './CreatePipelineButton';
import PipelinesSearchSection from './PipelinesSearchSection';
function PipelinePageLayout({ function PipelinePageLayout({
refetchPipelineLists, refetchPipelineLists,
@ -11,7 +10,6 @@ function PipelinePageLayout({
}: PipelinePageLayoutProps): JSX.Element { }: PipelinePageLayoutProps): JSX.Element {
const [isActionType, setActionType] = useState<string>(); const [isActionType, setActionType] = useState<string>();
const [isActionMode, setActionMode] = useState<string>('viewing-mode'); const [isActionMode, setActionMode] = useState<string>('viewing-mode');
const [pipelineSearchValue, setPipelineSearchValue] = useState<string>('');
return ( return (
<> <>
@ -21,7 +19,6 @@ function PipelinePageLayout({
isActionMode={isActionMode} isActionMode={isActionMode}
pipelineData={pipelineData} pipelineData={pipelineData}
/> />
<PipelinesSearchSection setPipelineSearchValue={setPipelineSearchValue} />
<PipelineListsView <PipelineListsView
isActionType={String(isActionType)} isActionType={String(isActionType)}
setActionType={setActionType} setActionType={setActionType}
@ -29,7 +26,6 @@ function PipelinePageLayout({
isActionMode={isActionMode} isActionMode={isActionMode}
pipelineData={pipelineData} pipelineData={pipelineData}
refetchPipelineLists={refetchPipelineLists} refetchPipelineLists={refetchPipelineLists}
pipelineSearchValue={pipelineSearchValue}
/> />
</> </>
); );

View File

@ -1,5 +1,7 @@
import './styles.scss';
import { ExclamationCircleOutlined, PlusOutlined } from '@ant-design/icons'; import { ExclamationCircleOutlined, PlusOutlined } from '@ant-design/icons';
import { Modal, Table } from 'antd'; import { Card, Modal, Table, Typography } from 'antd';
import { ExpandableConfig } from 'antd/es/table/interface'; import { ExpandableConfig } from 'antd/es/table/interface';
import savePipeline from 'api/pipeline/post'; import savePipeline from 'api/pipeline/post';
import { useNotifications } from 'hooks/useNotifications'; import { useNotifications } from 'hooks/useNotifications';
@ -19,6 +21,7 @@ import { trackEvent } from 'utils/segmentAnalytics';
import { v4 } from 'uuid'; import { v4 } from 'uuid';
import { tableComponents } from '../config'; import { tableComponents } from '../config';
import PipelinesSearchSection from '../Layouts/Pipeline/PipelinesSearchSection';
import AddNewPipeline from './AddNewPipeline'; import AddNewPipeline from './AddNewPipeline';
import AddNewProcessor from './AddNewProcessor'; import AddNewProcessor from './AddNewProcessor';
import { pipelineColumns } from './config'; import { pipelineColumns } from './config';
@ -44,6 +47,39 @@ import {
getUpdatedRow, getUpdatedRow,
} from './utils'; } from './utils';
function PipelinesListEmptyState(): JSX.Element {
const { t } = useTranslation(['pipeline']);
return (
<div className="logs-pipelines-empty-state-centered-container">
<Card size="small">
<div className="logs-pipelines-empty-state-centered-container">
<iframe
className="logs-pipelines-empty-state-video-iframe"
sandbox="allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox"
src="https://www.youtube.com/embed/OneENGNmLd0"
frameBorder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
title={t('learn_more')}
/>
<div>
<Typography>
{t('learn_more')}&nbsp;
<a
href="https://signoz.io/docs/logs-pipelines/introduction/"
target="_blank"
rel="noreferrer"
>
here
</a>
</Typography>
</div>
</div>
</Card>
</div>
);
}
function PipelineListsView({ function PipelineListsView({
isActionType, isActionType,
setActionType, setActionType,
@ -51,11 +87,11 @@ function PipelineListsView({
setActionMode, setActionMode,
pipelineData, pipelineData,
refetchPipelineLists, refetchPipelineLists,
pipelineSearchValue,
}: PipelineListsViewProps): JSX.Element { }: PipelineListsViewProps): JSX.Element {
const { t } = useTranslation(['pipeline', 'common']); const { t } = useTranslation(['pipeline', 'common']);
const [modal, contextHolder] = Modal.useModal(); const [modal, contextHolder] = Modal.useModal();
const { notifications } = useNotifications(); const { notifications } = useNotifications();
const [pipelineSearchValue, setPipelineSearchValue] = useState<string>('');
const [prevPipelineData, setPrevPipelineData] = useState<Array<PipelineData>>( const [prevPipelineData, setPrevPipelineData] = useState<Array<PipelineData>>(
cloneDeep(pipelineData?.pipelines || []), cloneDeep(pipelineData?.pipelines || []),
); );
@ -446,31 +482,40 @@ function PipelineListsView({
expandedPipelineData={expandedPipelineData()} expandedPipelineData={expandedPipelineData()}
setExpandedPipelineData={setExpandedPipelineData} setExpandedPipelineData={setExpandedPipelineData}
/> />
<Container> {prevPipelineData?.length > 0 ? (
<ModeAndConfiguration <>
isActionMode={isActionMode} <PipelinesSearchSection setPipelineSearchValue={setPipelineSearchValue} />
version={pipelineData?.version} <Container>
/> <ModeAndConfiguration
<DndProvider backend={HTML5Backend}> isActionMode={isActionMode}
<Table version={pipelineData?.version}
rowKey="id" />
columns={columns} <DndProvider backend={HTML5Backend}>
expandedRowRender={expandedRowView} <Table
expandable={expandableConfig} rowKey="id"
components={tableComponents} columns={columns}
dataSource={visibleCurrPipelines} expandedRowRender={expandedRowView}
onRow={onRowHandler} expandable={expandableConfig}
footer={footer} components={tableComponents}
pagination={false} dataSource={visibleCurrPipelines}
/> onRow={onRowHandler}
</DndProvider> footer={footer}
{showSaveButton && ( pagination={false}
<SaveConfigButton />
onSaveConfigurationHandler={onSaveConfigurationHandler} </DndProvider>
onCancelConfigurationHandler={onCancelConfigurationHandler} {showSaveButton && (
/> <SaveConfigButton
)} onSaveConfigurationHandler={onSaveConfigurationHandler}
</Container> onCancelConfigurationHandler={onCancelConfigurationHandler}
/>
)}
</Container>
</>
) : (
<Container>
<PipelinesListEmptyState />
</Container>
)}
</> </>
); );
} }
@ -482,7 +527,6 @@ interface PipelineListsViewProps {
setActionMode: (actionMode: ActionMode) => void; setActionMode: (actionMode: ActionMode) => void;
pipelineData: Pipeline; pipelineData: Pipeline;
refetchPipelineLists: VoidFunction; refetchPipelineLists: VoidFunction;
pipelineSearchValue: string;
} }
interface ExpandRowConfig { interface ExpandRowConfig {

View File

@ -0,0 +1,13 @@
.logs-pipelines-empty-state-centered-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.logs-pipelines-empty-state-video-iframe {
width: min(90vw, 640px);
height: min(68vw, 480px);
margin-bottom: 1em;
}

View File

@ -85,218 +85,48 @@ exports[`PipelinePage container test should render PipelinePageLayout section 1`
</span> </span>
</button> </button>
</div> </div>
<span
class="ant-input-affix-wrapper css-dev-only-do-not-override-2i2tap"
>
<input
class="ant-input css-dev-only-do-not-override-2i2tap"
placeholder="search_pipeline_placeholder"
type="text"
value=""
/>
<span
class="ant-input-suffix"
>
<span
class="ant-input-clear-icon ant-input-clear-icon-hidden"
role="button"
tabindex="-1"
>
<span
aria-label="close-circle"
class="anticon anticon-close-circle"
role="img"
>
<svg
aria-hidden="true"
data-icon="close-circle"
fill="currentColor"
fill-rule="evenodd"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M512 64c247.4 0 448 200.6 448 448S759.4 960 512 960 64 759.4 64 512 264.6 64 512 64zm127.98 274.82h-.04l-.08.06L512 466.75 384.14 338.88c-.04-.05-.06-.06-.08-.06a.12.12 0 00-.07 0c-.03 0-.05.01-.09.05l-45.02 45.02a.2.2 0 00-.05.09.12.12 0 000 .07v.02a.27.27 0 00.06.06L466.75 512 338.88 639.86c-.05.04-.06.06-.06.08a.12.12 0 000 .07c0 .03.01.05.05.09l45.02 45.02a.2.2 0 00.09.05.12.12 0 00.07 0c.02 0 .04-.01.08-.05L512 557.25l127.86 127.87c.04.04.06.05.08.05a.12.12 0 00.07 0c.03 0 .05-.01.09-.05l45.02-45.02a.2.2 0 00.05-.09.12.12 0 000-.07v-.02a.27.27 0 00-.05-.06L557.25 512l127.87-127.86c.04-.04.05-.06.05-.08a.12.12 0 000-.07c0-.03-.01-.05-.05-.09l-45.02-45.02a.2.2 0 00-.09-.05.12.12 0 00-.07 0z"
/>
</svg>
</span>
</span>
</span>
</span>
.c0 { .c0 {
margin-top: 3rem; margin-top: 3rem;
} }
.c1 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
gap: 0.5rem;
-webkit-box-pack: end;
-webkit-justify-content: flex-end;
-ms-flex-pack: end;
justify-content: flex-end;
color: #D89614;
margin: 0.125rem;
padding: 0.313rem;
}
<div <div
class="c0" class="c0"
> >
<div <div
class="c1" class="logs-pipelines-empty-state-centered-container"
>
Mode:
<span>
Viewing
</span>
<div>
Configuration Version: 1
</div>
</div>
<div
class="ant-table-wrapper css-dev-only-do-not-override-2i2tap"
> >
<div <div
class="ant-spin-nested-loading css-dev-only-do-not-override-2i2tap" class="ant-card ant-card-bordered ant-card-small css-dev-only-do-not-override-2i2tap"
> >
<div <div
class="ant-spin-container" class="ant-card-body"
> >
<div <div
class="ant-table ant-table-empty" class="logs-pipelines-empty-state-centered-container"
> >
<div <iframe
class="ant-table-container" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
> allowfullscreen=""
<div class="logs-pipelines-empty-state-video-iframe"
class="ant-table-content" frameborder="0"
> sandbox="allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox"
<table src="https://www.youtube.com/embed/OneENGNmLd0"
style="table-layout: auto;" title="learn_more"
>
<colgroup>
<col
class="ant-table-expand-icon-col"
/>
</colgroup>
<thead
class="ant-table-thead"
>
<tr>
<td
class="ant-table-cell ant-table-row-expand-icon-cell"
/>
<td
class="ant-table-cell"
style="text-align: left;"
/>
<th
class="ant-table-cell"
scope="col"
style="text-align: left;"
>
Pipeline Name
</th>
<th
class="ant-table-cell"
scope="col"
style="text-align: left;"
>
Filters
</th>
<th
class="ant-table-cell"
scope="col"
style="text-align: left;"
>
Last Edited
</th>
<th
class="ant-table-cell"
scope="col"
style="text-align: left;"
>
Edited By
</th>
<th
class="ant-table-cell"
scope="col"
style="text-align: center;"
>
Actions
</th>
</tr>
</thead>
<tbody
class="ant-table-tbody"
>
<tr
class="ant-table-placeholder"
draggable="true"
>
<td
class="ant-table-cell"
colspan="7"
>
<div
class="css-dev-only-do-not-override-2i2tap ant-empty ant-empty-normal"
>
<div
class="ant-empty-image"
>
<svg
height="41"
viewBox="0 0 64 41"
width="64"
xmlns="http://www.w3.org/2000/svg"
>
<g
fill="none"
fill-rule="evenodd"
transform="translate(0 1)"
>
<ellipse
cx="32"
cy="33"
fill="#f5f5f5"
rx="32"
ry="7"
/>
<g
fill-rule="nonzero"
stroke="#d9d9d9"
>
<path
d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"
/>
<path
d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z"
fill="#fafafa"
/>
</g>
</g>
</svg>
</div>
<div
class="ant-empty-description"
>
No data
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div
class="ant-table-footer"
/> />
<div>
<article
class="ant-typography css-dev-only-do-not-override-2i2tap"
>
learn_more 
<a
href="https://signoz.io/docs/logs-pipelines/introduction/"
rel="noreferrer"
target="_blank"
>
here
</a>
</article>
</div>
</div> </div>
</div> </div>
</div> </div>