Skip to content

Commit

Permalink
feat: enhance tag explorer view (grafana#1329)
Browse files Browse the repository at this point in the history
* add buttons which allow you to hop to single/comparison/diff page
* add flamegraph.com export and add groupBy/groupByValues to /export request
* add "where" dropdown
* add ability to choose tagValue using legend
  • Loading branch information
dogfrogfog authored Aug 5, 2022
1 parent 283592b commit 7d66d75
Show file tree
Hide file tree
Showing 24 changed files with 699 additions and 75 deletions.
15 changes: 15 additions & 0 deletions cypress/integration/webapp/e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,21 @@ describe('E2E Tests', () => {
findFlamegraph(2).waitForFlamegraphToRender();
});

// TODO(dogfrogfog): fix when app selector modal and explore tag modal will be combined
it.skip('tests /explore view', () => {
const params = new URLSearchParams();
params.set('query', appName);
params.set('from', t0);
params.set('until', t4);

cy.visit(`/explore?${params.toString()}`);

cy.findByTestId('explore-header');
cy.findByTestId('timeline-explore-page');
cy.findByTestId('explore-table');
cy.findByTestId('tag-explorer-view').waitForFlamegraphToRender();
});

it('works with standalone view', () => {
const params = new URLSearchParams();
params.set('query', appName);
Expand Down
14 changes: 14 additions & 0 deletions packages/pyroscope-flamegraph/src/NoProfiingData.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import NoProfilingData from './NoProfilingData';

describe('NoProfilingData', () => {
it('should render correctly', () => {
render(<NoProfilingData />);

expect(screen.getByTestId('no-profiling-data')).toBeInTheDocument();
expect(screen.getByTestId('no-profiling-data')).toHaveTextContent(
'No profiling data available for this application / time range.'
);
});
});
2 changes: 1 addition & 1 deletion packages/pyroscope-flamegraph/src/NoProfilingData.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import styles from './NoProfilingData.module.scss';

export default function NoProfilingData() {
return (
<div className={styles.noProfilingData}>
<div data-testid="no-profiling-data" className={styles.noProfilingData}>
<span>
No profiling data available for this application / time range.
</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

.sectionTitle {
margin-left: 10px;
color: #888;
color: var(--ps-select-modal-title);
font-weight: 700;
font-size: 0.8em;
}
Expand Down
2 changes: 1 addition & 1 deletion webapp/javascript/components/TagsBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import TextareaAutosize from 'react-textarea-autosize';
import { Prism } from '@webapp/util/prism';
import { Query, brandQuery } from '@webapp/models/query';
import Input from '@webapp/ui/Input';
import { appendLabelToQuery } from '@webapp/util/appendLabelToQuery';
import { appendLabelToQuery } from '@webapp/util/query';
import styles from './TagsBar.module.css';

interface TagsBarProps {
Expand Down
23 changes: 19 additions & 4 deletions webapp/javascript/components/TimelineChartWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,12 @@ type TimelineDataProps =
| {
/** timelineGroups refers to group of timelines, useful for explore view */
timelineGroups: TimelineGroupData[];
/** if there is active group, the other groups should "dim" themselves */
activeGroup: string;
/** show or hide tags legend, useful forr disabling single timeline legend */
showTagsLegend: boolean;
/** to set active tagValue using <Legend /> */
handleGroupByTagValueChange: (groupByTagValue: string) => void;
/** to manage strict data type */
mode: 'multiple';
};
Expand Down Expand Up @@ -199,7 +203,8 @@ class TimelineChartWrapper extends React.Component<
const { flotOptions } = this.state;

if (this.props.mode === 'multiple') {
const { timelineGroups, showTagsLegend, id, timezone } = this.props;
const { timelineGroups, activeGroup, showTagsLegend, id, timezone } =
this.props;

const customFlotOptions = {
...flotOptions,
Expand All @@ -212,10 +217,13 @@ class TimelineChartWrapper extends React.Component<

const centeredTimelineGroups =
timelineGroups &&
timelineGroups.map(({ data, color }) => {
timelineGroups.map(({ data, color, tagName }) => {
return {
data: centerTimelineData({ data }),
color,
color:
activeGroup && activeGroup !== tagName
? color?.fade(0.75)
: color,
};
});

Expand All @@ -232,7 +240,14 @@ class TimelineChartWrapper extends React.Component<
width="100%"
height={this.props.height || '100px'}
/>
{showTagsLegend && <Legend groups={timelineGroups} />}
{showTagsLegend && (
<Legend
groups={timelineGroups}
handleGroupByTagValueChange={
this.props.handleGroupByTagValueChange
}
/>
)}
</>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import { shareWithFlamegraphDotcom } from '@webapp/services/share';
import { useAppDispatch } from '@webapp/redux/hooks';
import handleError from '@webapp/util/handleError';

export default function useExportToFlamegraphDotCom(flamebearer?: Profile) {
export default function useExportToFlamegraphDotCom(
flamebearer?: Profile,
groupByTag?: string,
groupByTagValue?: string
) {
const dispatch = useAppDispatch();

return async (name?: string) => {
Expand All @@ -14,6 +18,9 @@ export default function useExportToFlamegraphDotCom(flamebearer?: Profile) {
const res = await shareWithFlamegraphDotcom({
flamebearer,
name,
// or we should add this to name ?
groupByTag,
groupByTagValue,
});

if (res.isErr) {
Expand Down
15 changes: 12 additions & 3 deletions webapp/javascript/hooks/populateLeftRightQuery.hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,26 @@ import { useEffect } from 'react';
import { actions, selectQueries } from '@webapp/redux/reducers/continuous';
import { useAppDispatch, useAppSelector } from '@webapp/redux/hooks';

function isQueriesHasSameApp(queries: string[]): boolean {
const appName = queries[0].split('{')[0];

return queries.every((query) => query.match(appName));
}

// usePopulateLeftRightQuery populates the left and right queries using the main query
export default function usePopulateLeftRightQuery() {
const dispatch = useAppDispatch();
const { query } = useAppSelector(selectQueries);
const { query, leftQuery, rightQuery } = useAppSelector(selectQueries);
// should not populate queries when was redirected
const shouldResetQuery =
query && !isQueriesHasSameApp([query, leftQuery, rightQuery]);

// When the query changes (ie the app has changed)
// We populate left and right tags to reflect that application
useEffect(() => {
if (query) {
if (shouldResetQuery) {
dispatch(actions.setRightQuery(query));
dispatch(actions.setLeftQuery(query));
}
}, [query]);
}, [shouldResetQuery]);
}
35 changes: 35 additions & 0 deletions webapp/javascript/pages/TagExplorerView.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
}

.tableDescription {
display: flex;
justify-content: space-between;
margin: 0 10px 10px;
}

Expand All @@ -21,6 +23,38 @@
margin-right: 5px;
}

.buttons {
position: relative;

a,
.buttonName {
cursor: pointer;
padding: 8px 6px;
margin-left: 5px;
text-decoration: none;
border: 1px solid var(--ps-ui-border);
color: var(--ps-neutral-2);
background-color: var(--ps-ui-element-bg-primary);
border-radius: 4px;

&:hover {
background-color: var(--ps-ui-element-bg-highlight);
}
}

.buttonName {
position: relative;
line-height: initial;
padding: 8px 20px 8px 6px;

&:after {
content: '';
position: absolute;
right: 5px;
}
}
}

.query {
display: flex;
align-items: center;
Expand Down Expand Up @@ -58,6 +92,7 @@
align-items: center;

.tagColor {
flex-shrink: 0;
display: inline-block;
height: 10px;
width: 10px;
Expand Down
Loading

0 comments on commit 7d66d75

Please sign in to comment.