Skip to content

Commit

Permalink
feat: upload any arbitrary data (collapsed/pprof/json) via adhoc ui (g…
Browse files Browse the repository at this point in the history
…rafana#1327)

Allow "uploading"[0] pprof/collapsed (aka folded) via adhoc UI.

* migrate to redux toolkit
* migrate to typescript
* fixes grafana#1333 (Flamegraph is squeezed in adhoc comparison UI grafana#1333)
* have that same logic continuous have of being able to easily change from single/comparison/diff and keeping the same profile in memory
  • Loading branch information
eh-am authored Aug 3, 2022
1 parent b130a3e commit 6620888
Show file tree
Hide file tree
Showing 24 changed files with 1,036 additions and 1,352 deletions.
2 changes: 1 addition & 1 deletion pkg/adhoc/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func (s *server) AddRoutes(r *mux.Router) http.HandlerFunc {
r.HandleFunc("/v1/profiles", s.Profiles)
r.HandleFunc("/v1/profile/{id:[0-9a-f]+}", s.Profile)
r.HandleFunc("/v1/diff/{left:[0-9a-f]+}/{right:[0-9a-f]+}", s.Diff)
r.HandleFunc("/v1/upload/", s.Upload)
r.HandleFunc("/v1/upload", s.Upload)
r.HandleFunc("/v1/upload-diff/", s.UploadDiff)
}
return r.ServeHTTP
Expand Down
132 changes: 0 additions & 132 deletions webapp/javascript/components/FileList.jsx

This file was deleted.

1 change: 0 additions & 1 deletion webapp/javascript/components/FileList.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ $tdHeight: 25px;
text-align: right;
padding: 0px 10px;

border-left: 1px solid var(--ps-ui-border);
border-bottom: 1px solid var(--ps-ui-border);
width: 400px;
min-width: 400px;
Expand Down
141 changes: 141 additions & 0 deletions webapp/javascript/components/FileList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import React, { useState, useMemo } from 'react';
import { Maybe } from '@webapp/util/fp';
import { AllProfiles } from '@webapp/models/adhoc';
import clsx from 'clsx';
// eslint-disable-next-line css-modules/no-unused-class
import styles from './FileList.module.scss';
import CheckIcon from './CheckIcon';

const dateModifiedColName = 'updatedAt';
const fileNameColName = 'name';
const tableFormat = [
{ name: fileNameColName, label: 'Filename' },
{ name: dateModifiedColName, label: 'Date Modified' },
];

interface FileListProps {
className?: string;
profilesList: AllProfiles;
onProfileSelected: (id: string) => void;
selectedProfileId: Maybe<string>;
}

function FileList(props: FileListProps) {
const {
profilesList: profiles,
onProfileSelected,
className,
selectedProfileId,
} = props;

const [sortBy, updateSortBy] = useState(dateModifiedColName);
const [sortByDirection, setSortByDirection] = useState<'desc' | 'asc'>(
'desc'
);

const isRowSelected = (id: string) => {
return selectedProfileId.mapOr(false, (profId) => profId === id);
};

const updateSortParams = (newSortBy: typeof tableFormat[number]['name']) => {
let dir = sortByDirection;

if (sortBy === newSortBy) {
dir = dir === 'asc' ? 'desc' : 'asc';
} else {
dir = 'asc';
}

updateSortBy(newSortBy);
setSortByDirection(dir);
};

const sortedProfilesIds = useMemo(() => {
const m = sortByDirection === 'asc' ? 1 : -1;

let sorted: AllProfiles[number][] = [];

if (profiles) {
const filesInfo = Object.values(profiles);

switch (sortBy) {
case fileNameColName:
sorted = filesInfo.sort(
(a, b) => m * a[sortBy].localeCompare(b[sortBy])
);
break;
case dateModifiedColName:
sorted = filesInfo.sort(
(a, b) =>
m *
(new Date(a[sortBy]).getTime() - new Date(b[sortBy]).getTime())
);
break;
default:
sorted = filesInfo;
}
}

return sorted;
}, [profiles, sortBy, sortByDirection]);

return (
<>
<div className={`${styles.tableContainer} ${className}`}>
<table className={styles.profilesTable} data-testid="table-view">
<thead>
<tr>
{tableFormat.map(({ name, label }) => (
<th
key={name}
className={styles.sortable}
onClick={() => updateSortParams(name)}
>
{label}
<span
className={clsx(
styles.sortArrow,
sortBy === name && styles[sortByDirection]
)}
/>
</th>
))}
</tr>
</thead>
<tbody>
{profiles &&
sortedProfilesIds.map((profile) => (
<tr
key={profile.id}
onClick={() => {
// Optimize to not reload the same one
if (
selectedProfileId.isJust &&
selectedProfileId.value === profile.id
) {
return;
}
onProfileSelected(profile.id);
}}
className={`${
isRowSelected(profile.id) && styles.rowSelected
}`}
>
<td>
{profile.name}

{isRowSelected(profile.id) && (
<CheckIcon className={styles.checkIcon} />
)}
</td>
<td>{profile.updatedAt}</td>
</tr>
))}
</tbody>
</table>
</div>
</>
);
}

export default FileList;
Loading

0 comments on commit 6620888

Please sign in to comment.