Skip to content

Commit

Permalink
feat: Navbar Drag and Drop (#313)
Browse files Browse the repository at this point in the history
  • Loading branch information
svc-shorpo authored Feb 17, 2024
1 parent 95f5041 commit dba8a43
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 22 deletions.
5 changes: 5 additions & 0 deletions .changeset/fifty-pumpkins-film.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hyperdx/app': patch
---

Allow to drag and drop saved searches and dashhoards between groups
8 changes: 4 additions & 4 deletions packages/api/src/controllers/dashboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ export async function updateDashboardAndAlerts(
query,
tags,
}: {
name: string;
charts: z.infer<typeof chartSchema>[];
query: string;
tags: z.infer<typeof tagsSchema>;
name?: string;
charts?: z.infer<typeof chartSchema>[];
query?: string;
tags?: z.infer<typeof tagsSchema>;
},
) {
const oldDashboard = await Dashboard.findOne({
Expand Down
6 changes: 3 additions & 3 deletions packages/api/src/routers/api/dashboards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,9 @@ router.put(
id: objectIdSchema,
}),
body: z.object({
name: z.string().max(1024),
charts: z.array(chartSchema),
query: z.string().max(2048),
name: z.string().max(1024).optional(),
charts: z.array(chartSchema).optional(),
query: z.string().max(2048).optional(),
tags: tagsSchema,
}),
}),
Expand Down
4 changes: 2 additions & 2 deletions packages/api/src/routers/api/logViews.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ router.patch(
}),
body: z.object({
name: z.string().max(1024).min(1).optional(),
query: z.string().max(2048),
query: z.string().max(2048).optional(),
tags: tagsSchema,
}),
}),
Expand All @@ -103,7 +103,7 @@ router.patch(
},
{
...(name && { name }),
query,
...(query && { query }),
tags: tags && uniq(tags),
},
{ new: true },
Expand Down
114 changes: 105 additions & 9 deletions packages/app/src/AppNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ import { useLocalStorage, useWindowSize } from './utils';

import styles from '../styles/AppNav.module.scss';

const UNTAGGED_SEARCHES_GROUP_NAME = 'Saved Searches';
const UNTAGGED_DASHBOARDS_GROUP_NAME = 'Saved Dashboards';

const APP_PERFORMANCE_DASHBOARD_CONFIG = {
id: '',
name: 'App Performance',
Expand Down Expand Up @@ -539,11 +542,13 @@ const AppNavLinkGroups = <T extends AppNavLinkItem>({
name,
groups,
renderLink,
onDragEnd,
forceExpandGroups = false,
}: {
name: string;
groups: AppNavLinkGroup<T>[];
renderLink: (item: T) => React.ReactNode;
onDragEnd?: (target: HTMLElement | null, newGroup: string | null) => void;
forceExpandGroups?: boolean;
}) => {
const [collapsedGroups, setCollapsedGroups] = useLocalStorage<
Expand All @@ -560,10 +565,27 @@ const AppNavLinkGroups = <T extends AppNavLinkItem>({
[collapsedGroups, setCollapsedGroups],
);

const [draggingOver, setDraggingOver] = useState<string | null>(null);

return (
<>
{groups.map(group => (
<div key={group.name}>
<div
key={group.name}
className={cx(
draggingOver === group.name && styles.listGroupDragEnter,
)}
onDragOver={e => {
e.preventDefault();
e.dataTransfer.dropEffect = 'move';
setDraggingOver(group.name);
}}
onDragEnd={e => {
e.preventDefault();
onDragEnd?.(e.target as HTMLElement, draggingOver);
setDraggingOver(null);
}}
>
<AppNavGroupLabel
onClick={() => handleToggleGroup(group.name)}
name={group.name}
Expand Down Expand Up @@ -621,10 +643,20 @@ function useSearchableList<T extends AppNavLinkItem>({
if (untaggedItems.length) {
groupedItems[untaggedGroupName] = untaggedItems;
}
return Object.entries(groupedItems).map(([name, items]) => ({
name,
items,
}));
return Object.entries(groupedItems)
.map(([name, items]) => ({
name,
items,
}))
.sort((a, b) => {
if (a.name === untaggedGroupName) {
return 1;
}
if (b.name === untaggedGroupName) {
return -1;
}
return a.name.localeCompare(b.name);
});
}, [filteredList, untaggedGroupName]);

return {
Expand Down Expand Up @@ -660,8 +692,14 @@ export default function AppNav({ fixed = false }: { fixed?: boolean }) {
} = api.useLogViews();
const logViews = logViewsData?.data ?? [];

const { data: dashboardsData, isLoading: isDashboardsLoading } =
api.useDashboards();
const updateDashboard = api.useUpdateDashboard();
const updateLogView = api.useUpdateLogView();

const {
data: dashboardsData,
isLoading: isDashboardsLoading,
refetch: refetchDashboards,
} = api.useDashboards();
const dashboards = dashboardsData?.data ?? [];

const { data: alertsData, isLoading: isAlertsLoading } = api.useAlerts();
Expand Down Expand Up @@ -734,7 +772,7 @@ export default function AppNav({ fixed = false }: { fixed?: boolean }) {
groupedFilteredList: groupedFilteredSearchesList,
} = useSearchableList({
items: logViews,
untaggedGroupName: 'Saved Searches',
untaggedGroupName: UNTAGGED_SEARCHES_GROUP_NAME,
});

const [isSearchPresetsCollapsed, setSearchPresetsCollapsed] = useLocalStorage(
Expand All @@ -749,7 +787,7 @@ export default function AppNav({ fixed = false }: { fixed?: boolean }) {
groupedFilteredList: groupedFilteredDashboardsList,
} = useSearchableList({
items: dashboards,
untaggedGroupName: 'Saved Dashboards',
untaggedGroupName: UNTAGGED_DASHBOARDS_GROUP_NAME,
});

const [isDashboardsPresetsCollapsed, setDashboardsPresetsCollapsed] =
Expand Down Expand Up @@ -777,6 +815,8 @@ export default function AppNav({ fixed = false }: { fixed?: boolean }) {
lv._id === query.savedSearchId && styles.listLinkActive,
)}
title={lv.name}
draggable
data-savedsearchid={lv._id}
>
<div className="d-inline-block text-truncate">{lv.name}</div>
{Array.isArray(lv.alerts) && lv.alerts.length > 0 ? (
Expand All @@ -802,6 +842,32 @@ export default function AppNav({ fixed = false }: { fixed?: boolean }) {
],
);

const handleLogViewDragEnd = useCallback(
(target: HTMLElement | null, name: string | null) => {
if (!target?.dataset.savedsearchid || name == null) {
return;
}
const logView = logViews.find(
lv => lv._id === target.dataset.savedsearchid,
);
if (logView?.tags?.includes(name)) {
return;
}
updateLogView.mutate(
{
id: target.dataset.savedsearchid,
tags: name === UNTAGGED_SEARCHES_GROUP_NAME ? [] : [name],
},
{
onSuccess: () => {
refetchLogViews();
},
},
);
},
[logViews, refetchLogViews, updateLogView],
);

const renderDashboardLink = useCallback(
(dashboard: Dashboard) => (
<Link
Expand All @@ -811,13 +877,41 @@ export default function AppNav({ fixed = false }: { fixed?: boolean }) {
className={cx(styles.listLink, {
[styles.listLinkActive]: dashboard._id === query.dashboardId,
})}
draggable
data-dashboardid={dashboard._id}
>
{dashboard.name}
</Link>
),
[query.dashboardId],
);

const handleDashboardDragEnd = useCallback(
(target: HTMLElement | null, name: string | null) => {
if (!target?.dataset.dashboardid || name == null) {
return;
}
const dashboard = dashboards.find(
d => d._id === target.dataset.dashboardid,
);
if (dashboard?.tags?.includes(name)) {
return;
}
updateDashboard.mutate(
{
id: target.dataset.dashboardid,
tags: name === UNTAGGED_DASHBOARDS_GROUP_NAME ? [] : [name],
},
{
onSuccess: () => {
refetchDashboards();
},
},
);
},
[dashboards, refetchDashboards, updateDashboard],
);

return (
<>
<AuthLoadingBlocker />
Expand Down Expand Up @@ -934,6 +1028,7 @@ export default function AppNav({ fixed = false }: { fixed?: boolean }) {
groups={groupedFilteredSearchesList}
renderLink={renderLogViewLink}
forceExpandGroups={!!searchesListQ}
onDragEnd={handleLogViewDragEnd}
/>
</div>

Expand Down Expand Up @@ -1170,6 +1265,7 @@ export default function AppNav({ fixed = false }: { fixed?: boolean }) {
groups={groupedFilteredDashboardsList}
renderLink={renderDashboardLink}
forceExpandGroups={!!dashboardsListQ}
onDragEnd={handleDashboardDragEnd}
/>

{dashboards.length === 0 && (
Expand Down
8 changes: 4 additions & 4 deletions packages/app/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,7 @@ const api = {
Error,
{
id: string;
query: string;
query?: string;
tags?: string[];
}
>(`log-views`, async ({ id, query, tags }) =>
Expand Down Expand Up @@ -624,9 +624,9 @@ const api = {
HTTPError,
{
id: string;
name: string;
query: string;
charts: any[];
name?: string;
query?: string;
charts?: any[];
tags?: string[];
}
>(async ({ id, name, charts, query, tags }) =>
Expand Down
7 changes: 7 additions & 0 deletions packages/app/styles/AppNav.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@
padding-bottom: 10px;
}

.listGroupDragEnter {
opacity: 0.7;
background: #ffffff1a;
border-radius: 10px;
}

.listGroupName {
color: $slate-400;
text-transform: uppercase;
Expand Down Expand Up @@ -41,6 +47,7 @@
text-overflow: ellipsis;
white-space: nowrap;
padding-left: 16px;
user-select: none;
gap: 10px;
&:hover {
color: $slate-100;
Expand Down

0 comments on commit dba8a43

Please sign in to comment.