chore: webui profiler write/read filters from url
@@ -6,6 +6,7 @@ import {
AvailableSeriesType, MetricsAggregateInterface, MetricType, useFetchAvailableSeries,
useFetchMetrics,
} from 'pages/TrialDetails/Profiles/utils';
+import { parseUrl } from 'routes/utils';
import { TrialDetails } from 'types';
export interface ProfilesFiltersInterface {
@@ -42,9 +43,12 @@ interface Props {
const ProfilesFiltersProvider: React.FC<Props> = ({ children, trial }: Props) => {
const [ filters, setFilters ] = useState<FiltersInterface>({});
const [ hasProfilingData, setHasProfilingData ] = useState<boolean>(false);
+ const [ isUrlParsed, setIsUrlParsed ] = useState(false);
const systemSeries = useFetchAvailableSeries(trial.id)[MetricType.System];
const timingMetrics = useFetchMetrics(trial.id, MetricType.Timing);
+ const canRender = filters.agentId && filters.name && systemSeries;
+
/*
* Set default filters
*/
@@ -69,6 +73,85 @@ const ProfilesFiltersProvider: React.FC<Props> = ({ children, trial }: Props) =>
setFilters(newFilters);
}, [ systemSeries, filters.agentId, filters.name ]);
+ /*
+ * When filters changes update the page URL.
+ */
+ useEffect(() => {
+ if (!isUrlParsed) return;
+
+ const searchParams = new URLSearchParams;
+ const url = parseUrl(window.location.href);
+
+ // name
+ if (filters.name) {
+ searchParams.append('name', filters.name);
+ }
+
+ // agentId
+ if (filters.agentId) {
+ searchParams.append('agentId', filters.agentId);
+ }
+
+ // gpuUuid
+ if (filters.gpuUuid) {
+ searchParams.append('gpuUuid', filters.gpuUuid);
+ }
+
+ window.history.pushState(
+ {},
+ '',
+ url.origin + url.pathname + '?' + searchParams.toString(),
+ );
+ }, [ filters, isUrlParsed ]);
+
+ /*
+ * On first load: if filters are specified in URL, override default.
+ */
+ useEffect(() => {
+ if (!canRender || isUrlParsed) return;
+
+ // If search params are not set, we default to user preferences
+ const url = parseUrl(window.location.href);
+ if (url.search === '') {
+ setIsUrlParsed(true);
+ return;
+ }
+
+ const newFilters = { ...filters };
+ const urlSearchParams = url.searchParams;
+
+ // name
+ const name = urlSearchParams.get('name');
+ if (name != null && Object.keys(systemSeries).includes(name)) {
+ newFilters.name = name;
+ }
+
+ // agentId
+ const agentId = urlSearchParams.get('agentId');
+ if (
+ agentId != null
+ && newFilters.name
+ && Object.keys(systemSeries[newFilters.name]).includes(agentId)
+ ) {
+ newFilters.agentId = agentId;
+ }
+
+ // gpuUuid
+ const gpuUuid = urlSearchParams.get('gpuUuid');
+ if (
+ agentId != null
+ && gpuUuid != null
+ && newFilters.name
+ && newFilters.agentId
+ && systemSeries[newFilters.name][newFilters.agentId].includes(gpuUuid)
+ ) {
+ newFilters.gpuUuid = gpuUuid;
+ }
+
+ setIsUrlParsed(true);
+ setFilters(newFilters);
+ }, [ canRender, filters, isUrlParsed, systemSeries ]);
+
const context = useMemo<ProfilesFiltersContextInterface>(() => ({
filters,
hasProfilingData,
@@ -78,7 +161,7 @@ const ProfilesFiltersProvider: React.FC<Props> = ({ children, trial }: Props) =>
timingMetrics,
}), [ filters, hasProfilingData, systemSeries, timingMetrics ]);
- if (!filters.agentId || !filters.name) {
+ if (!canRender || !isUrlParsed) {
return <Alert message="No data available." type="warning" />;
}
