-
-
-
-
{title}
-
{description}
-
-
-
-
-
+ const dashboard = dashboardStore.selectedDashboard;
+ const selectedWidgetIds = dashboardStore.selectedWidgets.map((widget: any) => widget.metricId);
+ const queryParams = new URLSearchParams(location.search);
-
- {metrics ? metrics.map((metric: any) => (
-
dashboardStore.toggleWidgetSelection(metric)}
- />
- )) : (
- No custom metrics created.
- )}
-
+ const onSave = () => {
+ if (selectedWidgetIds.length === 0) return;
+ dashboardStore
+ .save(dashboard)
+ .then(async (syncedDashboard: Record
) => {
+ if (dashboard.exists()) {
+ await dashboardStore.fetch(dashboard.dashboardId);
+ }
+ dashboardStore.selectDashboardById(syncedDashboard.dashboardId);
+ })
+ .then(hideModal);
+ };
-
-
- {'Selected '}
- {selectedWidgetIds.length}
- {' out of '}
- {metrics ? metrics.length : 0}
-
-
-
-
+ const onCreateNew = () => {
+ const path = withSiteId(dashboardMetricCreate(dashboard.dashboardId), siteId);
+ if (!queryParams.has('modal')) history.push('?modal=addMetric');
+ history.push(path);
+ hideModal();
+ };
+
+ return (
+
+
+
+
+
{title}
+
{description}
+
+
+
- );
+
+
+ {metrics ? (
+ metrics.map((metric: any) => (
+
dashboardStore.toggleWidgetSelection(metric)}
+ />
+ ))
+ ) : (
+ No custom metrics created.
+ )}
+
+
+
+
+
+ {'Selected '}
+ {selectedWidgetIds.length}
+ {' out of '}
+ {metrics ? metrics.length : 0}
+
+
+
+
+
+ );
}
export default withRouter(observer(AddMetric));
diff --git a/frontend/app/components/Dashboard/components/DashboardWidgetGrid/AddMetricContainer.tsx b/frontend/app/components/Dashboard/components/DashboardWidgetGrid/AddMetricContainer.tsx
index fb1105856..b33cccf76 100644
--- a/frontend/app/components/Dashboard/components/DashboardWidgetGrid/AddMetricContainer.tsx
+++ b/frontend/app/components/Dashboard/components/DashboardWidgetGrid/AddMetricContainer.tsx
@@ -49,13 +49,8 @@ function AddMetricButton({ iconName, title, description, onClick, isPremade, isP
function AddMetricContainer({ siteId, isPopup }: any) {
const { showModal } = useModal();
- const [categories, setCategories] = React.useState
[]>([]);
const { dashboardStore } = useStore();
- React.useEffect(() => {
- dashboardStore?.fetchTemplates(true).then((cats) => setCategories(cats));
- }, []);
-
const onAddCustomMetrics = () => {
dashboardStore.initDashboard(dashboardStore.selectedDashboard);
showModal(
@@ -63,7 +58,6 @@ function AddMetricContainer({ siteId, isPopup }: any) {
siteId={siteId}
title="Custom Metrics"
description="Metrics that are manually created by you or your team."
- metrics={categories.find((category) => category.name === 'custom')?.widgets}
/>,
{ right: true }
);
@@ -76,7 +70,6 @@ function AddMetricContainer({ siteId, isPopup }: any) {
siteId={siteId}
title="Ready-Made Metrics"
description="Curated metrics predfined by OpenReplay."
- categories={categories.filter((category) => category.name !== 'custom')}
/>,
{ right: true }
);
diff --git a/frontend/app/components/Dashboard/components/DashboardWidgetGrid/AddPredefinedMetric.tsx b/frontend/app/components/Dashboard/components/DashboardWidgetGrid/AddPredefinedMetric.tsx
index 8ab3cfeb0..4e95a2c6e 100644
--- a/frontend/app/components/Dashboard/components/DashboardWidgetGrid/AddPredefinedMetric.tsx
+++ b/frontend/app/components/Dashboard/components/DashboardWidgetGrid/AddPredefinedMetric.tsx
@@ -1,6 +1,6 @@
import React from 'react';
import { observer } from 'mobx-react-lite';
-import { Button } from 'UI';
+import { Button, Loader } from 'UI';
import WidgetWrapper from 'App/components/Dashboard/components/WidgetWrapper';
import { useStore } from 'App/mstore';
import { useModal } from 'App/components/Modal';
@@ -9,130 +9,145 @@ import { withRouter, RouteComponentProps } from 'react-router-dom';
import { WidgetCategoryItem } from 'App/components/Dashboard/components/DashboardMetricSelection/DashboardMetricSelection';
interface IProps extends RouteComponentProps {
- categories: Record[];
- siteId: string;
- title: string;
- description: string;
+ siteId: string;
+ title: string;
+ description: string;
}
-function AddPredefinedMetric({ categories, history, siteId, title, description }: IProps) {
- const { dashboardStore } = useStore();
- const { hideModal } = useModal();
- const [activeCategory, setActiveCategory] = React.useState>();
+function AddPredefinedMetric({ history, siteId, title, description }: IProps) {
+ const [categories, setCategories] = React.useState([]);
+ const { dashboardStore } = useStore();
+ const { hideModal } = useModal();
+ const [activeCategory, setActiveCategory] = React.useState>();
- const scrollContainer = React.useRef(null);
+ const scrollContainer = React.useRef(null);
- const dashboard = dashboardStore.selectedDashboard;
- const selectedWidgetIds = dashboardStore.selectedWidgets.map((widget: any) => widget.metricId);
- const queryParams = new URLSearchParams(location.search);
- const totalMetricCount = categories.reduce((acc, category) => acc + category.widgets.length, 0);
+ const dashboard = dashboardStore.selectedDashboard;
+ const selectedWidgetIds = dashboardStore.selectedWidgets.map((widget: any) => widget.metricId);
+ const queryParams = new URLSearchParams(location.search);
+ const totalMetricCount = categories.reduce((acc, category) => acc + category.widgets.length, 0);
- React.useEffect(() => {
- dashboardStore?.fetchTemplates(true).then((categories) => {
- const defaultCategory = categories.filter((category: any) => category.name !== 'custom')[0];
- setActiveCategory(defaultCategory);
- });
- }, []);
+ React.useEffect(() => {
+ dashboardStore?.fetchTemplates(true).then((categories: any[]) => {
+ const predefinedCategories = categories.filter((category) => category.name !== 'custom');
+ const defaultCategory = predefinedCategories[0];
+ setActiveCategory(defaultCategory);
+ setCategories(predefinedCategories);
+ });
+ }, []);
- React.useEffect(() => {
- if (scrollContainer.current) {
- scrollContainer.current.scrollTop = 0;
+ React.useEffect(() => {
+ if (scrollContainer.current) {
+ scrollContainer.current.scrollTop = 0;
+ }
+ }, [activeCategory, scrollContainer.current]);
+
+ const handleWidgetCategoryClick = (category: any) => {
+ setActiveCategory(category);
+ };
+
+ const onSave = () => {
+ if (selectedWidgetIds.length === 0) return;
+ dashboardStore
+ .save(dashboard)
+ .then(async (syncedDashboard) => {
+ if (dashboard.exists()) {
+ await dashboardStore.fetch(dashboard.dashboardId);
}
- }, [activeCategory, scrollContainer.current]);
+ dashboardStore.selectDashboardById(syncedDashboard.dashboardId);
+ })
+ .then(hideModal);
+ };
- const handleWidgetCategoryClick = (category: any) => {
- setActiveCategory(category);
- };
+ const onCreateNew = () => {
+ const path = withSiteId(dashboardMetricCreate(dashboard.dashboardId), siteId);
+ if (!queryParams.has('modal')) history.push('?modal=addMetric');
+ history.push(path);
+ hideModal();
+ };
- const onSave = () => {
- if (selectedWidgetIds.length === 0) return;
- dashboardStore
- .save(dashboard)
- .then(async (syncedDashboard) => {
- if (dashboard.exists()) {
- await dashboardStore.fetch(dashboard.dashboardId);
- }
- dashboardStore.selectDashboardById(syncedDashboard.dashboardId);
- })
- .then(hideModal);
- };
+ return (
+
+
+
+
+
{title}
+
{description}
+
- const onCreateNew = () => {
- const path = withSiteId(dashboardMetricCreate(dashboard.dashboardId), siteId);
- if (!queryParams.has('modal')) history.push('?modal=addMetric');
- history.push(path);
- hideModal();
- };
-
- return (
-
-
-
-
-
{title}
-
{description}
-
-
-
-
-
-
-
-
- {activeCategory &&
- categories.map((category) => (
-
-
-
- ))}
-
-
-
-
- {activeCategory &&
- activeCategory.widgets.map((metric: any) => (
-
- dashboardStore.toggleWidgetSelection(metric)}
- />
-
- ))}
-
-
-
-
-
- {'Selected '}
- {selectedWidgetIds.length}
- {' out of '}
- {totalMetricCount}
-
-
-
-
+
- );
+
+
+
+
+ {activeCategory &&
+ categories.map((category) => (
+
+
+
+ ))}
+
+
+
+
+ {activeCategory &&
+ activeCategory.widgets.map((metric: any) => (
+
+ dashboardStore.toggleWidgetSelection(metric)}
+ />
+
+ ))}
+
+
+
+
+
+
+ {'Selected '}
+ {selectedWidgetIds.length}
+ {' out of '}
+ {totalMetricCount}
+
+
+
+
+
+ );
}
export default withRouter(observer(AddPredefinedMetric));
diff --git a/frontend/app/components/Header/SiteDropdown.js b/frontend/app/components/Header/SiteDropdown.js
index 7f89eee82..04deb111b 100644
--- a/frontend/app/components/Header/SiteDropdown.js
+++ b/frontend/app/components/Header/SiteDropdown.js
@@ -54,7 +54,6 @@ export default class SiteDropdown extends React.PureComponent {
this.props.clearSearchLive();
mstore.initClient();
- mstore.dashboardStore.selectDefaultDashboard();
}
render() {
diff --git a/frontend/app/components/ui/Loader/Loader.js b/frontend/app/components/ui/Loader/Loader.tsx
similarity index 73%
rename from frontend/app/components/ui/Loader/Loader.js
rename to frontend/app/components/ui/Loader/Loader.tsx
index e090dcf8d..50a4eeb46 100644
--- a/frontend/app/components/ui/Loader/Loader.js
+++ b/frontend/app/components/ui/Loader/Loader.tsx
@@ -3,7 +3,15 @@ import cn from 'classnames';
import styles from './loader.module.css';
import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
-const Loader = React.memo(
+interface Props {
+ className?: string
+ loading?: boolean
+ children?: React.ReactNode
+ size?: number
+ style?: Record
+}
+
+const Loader = React.memo(
({
className = '',
loading = true,
@@ -12,7 +20,9 @@ const Loader = React.memo(
style = { minHeight: '150px' },
}) =>
!loading ? (
- children
+ <>
+ {children}
+ >
) : (
{/*
*/}
diff --git a/frontend/app/mstore/dashboardStore.ts b/frontend/app/mstore/dashboardStore.ts
index f327b1c60..3f77bace4 100644
--- a/frontend/app/mstore/dashboardStore.ts
+++ b/frontend/app/mstore/dashboardStore.ts
@@ -1,8 +1,6 @@
import {
makeAutoObservable,
runInAction,
- observable,
- action,
} from "mobx";
import Dashboard, { IDashboard } from "./types/dashboard";
import Widget, { IWidget } from "./types/widget";
@@ -39,6 +37,7 @@ export interface IDashboardStore {
metricsSearch: string;
isLoading: boolean;
+ loadingTemplates: boolean;
isSaving: boolean;
isDeleting: boolean;
fetchingDashboard: boolean;
@@ -74,7 +73,6 @@ export interface IDashboardStore {
selectDashboardById(dashboardId: string): void;
getDashboardById(dashboardId: string): boolean;
setSiteId(siteId: any): void;
- selectDefaultDashboard(): Promise
;
saveMetric(metric: IWidget, dashboardId?: string): Promise;
fetchTemplates(hardRefresh: boolean): Promise;
@@ -82,7 +80,6 @@ export interface IDashboardStore {
addWidgetToDashboard(dashboard: IDashboard, metricIds: any): Promise;
setDrillDownPeriod(period: any): void;
- updatePinned(dashboardId: string): Promise;
fetchMetricChartData(
metric: IWidget,
data: any,
@@ -392,22 +389,6 @@ export default class DashboardStore implements IDashboardStore {
this.siteId = siteId;
};
- selectDefaultDashboard = (): Promise => {
- return new Promise((resolve, reject) => {
- if (this.dashboards.length > 0) {
- const pinnedDashboard = this.dashboards.find((d) => d.isPinned);
- if (pinnedDashboard) {
- this.selectedDashboard = pinnedDashboard;
- } else {
- this.selectedDashboard = this.dashboards[0];
- }
-
- resolve(this.selectedDashboard);
- }
- reject(new Error("No dashboards found"));
- });
- };
-
fetchTemplates(hardRefresh): Promise {
this.loadingTemplates = true
return new Promise((resolve, reject) => {
@@ -473,28 +454,6 @@ export default class DashboardStore implements IDashboardStore {
});
}
- updatePinned(dashboardId: string): Promise {
- // this.isSaving = true
- return dashboardService
- .updatePinned(dashboardId)
- .then(() => {
- toast.success("Dashboard pinned successfully");
- this.dashboards.forEach((d) => {
- if (d.dashboardId === dashboardId) {
- d.isPinned = true;
- } else {
- d.isPinned = false;
- }
- });
- })
- .catch(() => {
- toast.error("Dashboard could not be pinned");
- })
- .finally(() => {
- // this.isSaving = false
- });
- }
-
setPeriod(period: any) {
this.period = Period({
start: period.start,
diff --git a/frontend/app/mstore/types/dashboard.ts b/frontend/app/mstore/types/dashboard.ts
index 5b8c40b17..440303d4c 100644
--- a/frontend/app/mstore/types/dashboard.ts
+++ b/frontend/app/mstore/types/dashboard.ts
@@ -12,7 +12,6 @@ export interface IDashboard {
widgets: IWidget[]
metrics: any[]
isValid: boolean
- isPinned: boolean
currentWidget: IWidget
config: any
createdAt: Date
@@ -43,7 +42,6 @@ export default class Dashboard implements IDashboard {
widgets: IWidget[] = []
metrics: any[] = []
isValid: boolean = false
- isPinned: boolean = false
currentWidget: IWidget = new Widget()
config: any = {}
createdAt: Date = new Date()
@@ -78,7 +76,6 @@ export default class Dashboard implements IDashboard {
this.name = json.name
this.description = json.description
this.isPublic = json.isPublic
- this.isPinned = json.isPinned
this.createdAt = DateTime.fromMillis(new Date(json.createdAt).getTime())
this.widgets = json.widgets ? json.widgets.map((w: Widget) => new Widget().fromJson(w)).sort((a: Widget, b: Widget) => a.position - b.position) : []
})
diff --git a/frontend/app/services/DashboardService.ts b/frontend/app/services/DashboardService.ts
index b75a059fa..311830387 100644
--- a/frontend/app/services/DashboardService.ts
+++ b/frontend/app/services/DashboardService.ts
@@ -18,7 +18,6 @@ export interface IDashboardService {
saveWidget(dashboardId: string, widget: IWidget): Promise
deleteWidget(dashboardId: string, widgetId: string): Promise
- updatePinned(dashboardId: string): Promise
}
@@ -151,14 +150,4 @@ export default class DashboardService implements IDashboardService {
.then(response => response.json())
.then(response => response.data || {});
}
-
- /**
- * Update the pinned status of a dashboard.
- * @param dashboardId
- * @returns
- */
- updatePinned(dashboardId: string): Promise {
- return this.client.get(`/dashboards/${dashboardId}/pin`, {})
- .then(response => response.json())
- }
-}
\ No newline at end of file
+}