diff --git a/src/frontend/src/components/forms/AuthenticationForm.tsx b/src/frontend/src/components/forms/AuthenticationForm.tsx
index 5f61a60eb0..37f7e8b5ae 100644
--- a/src/frontend/src/components/forms/AuthenticationForm.tsx
+++ b/src/frontend/src/components/forms/AuthenticationForm.tsx
@@ -17,7 +17,11 @@ import { useLocation, useNavigate } from 'react-router-dom';
import { api } from '../../App';
import { ApiEndpoints } from '../../enums/ApiEndpoints';
-import { doBasicLogin, doSimpleLogin } from '../../functions/auth';
+import {
+ doBasicLogin,
+ doSimpleLogin,
+ followRedirect
+} from '../../functions/auth';
import { showLoginNotification } from '../../functions/notifications';
import { apiUrl, useServerApiState } from '../../states/ApiState';
import { useUserState } from '../../states/UserState';
@@ -51,8 +55,7 @@ export function AuthenticationForm() {
title: t`Login successful`,
message: t`Logged in successfully`
});
-
- navigate(location?.state?.redirectFrom ?? '/home');
+ followRedirect(navigate, location?.state);
} else {
showLoginNotification({
title: t`Login failed`,
diff --git a/src/frontend/src/components/nav/Layout.tsx b/src/frontend/src/components/nav/Layout.tsx
index b201c7d669..236e3dd63b 100644
--- a/src/frontend/src/components/nav/Layout.tsx
+++ b/src/frontend/src/components/nav/Layout.tsx
@@ -18,7 +18,14 @@ export const ProtectedRoute = ({ children }: { children: JSX.Element }) => {
if (!isLoggedIn()) {
return (
-
+
);
}
diff --git a/src/frontend/src/functions/auth.tsx b/src/frontend/src/functions/auth.tsx
index 8325bfc8b2..a05b043755 100644
--- a/src/frontend/src/functions/auth.tsx
+++ b/src/frontend/src/functions/auth.tsx
@@ -1,7 +1,7 @@
import { t } from '@lingui/macro';
import { notifications } from '@mantine/notifications';
import axios from 'axios';
-import { NavigateFunction } from 'react-router-dom';
+import { Navigate, NavigateFunction } from 'react-router-dom';
import { api, setApiDefaults } from '../App';
import { ApiEndpoints } from '../enums/ApiEndpoints';
@@ -11,6 +11,17 @@ import { useUserState } from '../states/UserState';
import { fetchGlobalStates } from '../states/states';
import { showLoginNotification } from './notifications';
+export function followRedirect(navigate: NavigateFunction, redirect: any) {
+ let url = redirect?.redirectUrl ?? '/home';
+
+ if (redirect?.queryParams) {
+ // Construct and appand query parameters
+ url = url + '?' + new URLSearchParams(redirect.queryParams).toString();
+ }
+
+ navigate(url);
+}
+
/**
* sends a request to the specified url from a form. this will change the window location.
* @param {string} path the path to send the post request to
@@ -177,7 +188,7 @@ export function handleReset(navigate: any, values: { email: string }) {
*/
export const checkLoginState = async (
navigate: any,
- redirect?: string,
+ redirect?: any,
no_redirect?: boolean
) => {
setApiDefaults();
@@ -197,13 +208,13 @@ export const checkLoginState = async (
fetchGlobalStates();
- navigate(redirect ?? '/home');
+ followRedirect(navigate, redirect);
};
// Callback function when login fails
const loginFailure = () => {
if (!no_redirect) {
- navigate('/login', { state: { redirectFrom: redirect } });
+ navigate('/login', { state: redirect });
}
};
diff --git a/src/frontend/src/pages/Auth/Logged-In.tsx b/src/frontend/src/pages/Auth/Logged-In.tsx
index c4939dd30d..6aec174400 100644
--- a/src/frontend/src/pages/Auth/Logged-In.tsx
+++ b/src/frontend/src/pages/Auth/Logged-In.tsx
@@ -10,7 +10,7 @@ export default function Logged_In() {
const location = useLocation();
useEffect(() => {
- checkLoginState(navigate, location?.state?.redirectFrom);
+ checkLoginState(navigate, location?.state);
}, [navigate]);
return (
diff --git a/src/frontend/src/pages/Auth/Login.tsx b/src/frontend/src/pages/Auth/Login.tsx
index a27687dfe8..213963a34c 100644
--- a/src/frontend/src/pages/Auth/Login.tsx
+++ b/src/frontend/src/pages/Auth/Login.tsx
@@ -13,7 +13,11 @@ import {
} from '../../components/forms/AuthenticationForm';
import { InstanceOptions } from '../../components/forms/InstanceOptions';
import { defaultHostKey } from '../../defaults/defaultHostList';
-import { checkLoginState, doBasicLogin } from '../../functions/auth';
+import {
+ checkLoginState,
+ doBasicLogin,
+ followRedirect
+} from '../../functions/auth';
import { useServerApiState } from '../../states/ApiState';
import { useLocalState } from '../../states/LocalState';
@@ -49,7 +53,7 @@ export default function Login() {
ChangeHost(defaultHostKey);
}
- checkLoginState(navigate, location?.state?.redirectFrom, true);
+ checkLoginState(navigate, location?.state, true);
// check if we got login params (login and password)
if (searchParams.has('login') && searchParams.has('password')) {
@@ -57,7 +61,7 @@ export default function Login() {
searchParams.get('login') ?? '',
searchParams.get('password') ?? ''
).then(() => {
- navigate(location?.state?.redirectFrom ?? '/home');
+ followRedirect(navigate, location?.state);
});
}
}, []);
diff --git a/src/frontend/src/tables/InvenTreeTable.tsx b/src/frontend/src/tables/InvenTreeTable.tsx
index 4ba9fb718c..5ffbc5fd33 100644
--- a/src/frontend/src/tables/InvenTreeTable.tsx
+++ b/src/frontend/src/tables/InvenTreeTable.tsx
@@ -12,6 +12,7 @@ import {
import {
IconBarcode,
IconFilter,
+ IconFilterCancel,
IconRefresh,
IconTrash
} from '@tabler/icons-react';
@@ -28,7 +29,7 @@ import React, {
useMemo,
useState
} from 'react';
-import { useNavigate } from 'react-router-dom';
+import { useNavigate, useSearchParams } from 'react-router-dom';
import { api } from '../App';
import { Boundary } from '../components/Boundary';
@@ -155,10 +156,14 @@ export function InvenTreeTable>({
setTableSorting,
loader
} = useLocalState();
+
const [fieldNames, setFieldNames] = useState>({});
const navigate = useNavigate();
+ // Extract URL query parameters (e.g. ?active=true&overdue=false)
+ const [urlQueryParams, setUrlQueryParams] = useSearchParams();
+
// Construct table filters - note that we can introspect filter labels from column names
const filters: TableFilter[] = useMemo(() => {
return (
@@ -361,6 +366,13 @@ export function InvenTreeTable>({
);
}
+ // Allow override of filters based on URL query parameters
+ if (urlQueryParams) {
+ for (let [key, value] of urlQueryParams) {
+ queryParams[key] = value;
+ }
+ }
+
// Add custom search term
if (tableState.searchTerm) {
queryParams.search = tableState.searchTerm;
@@ -522,6 +534,11 @@ export function InvenTreeTable>({
refetchOnMount: true
});
+ // Refetch data when the query parameters change
+ useEffect(() => {
+ refetch();
+ }, [urlQueryParams]);
+
useEffect(() => {
tableState.setIsLoading(
isFetching ||
@@ -699,6 +716,21 @@ export function InvenTreeTable>({
onToggleColumn={toggleColumn}
/>
)}
+ {urlQueryParams.size > 0 && (
+
+
+ {
+ setUrlQueryParams({});
+ }}
+ />
+
+
+ )}
{tableProps.enableFilters && filters.length > 0 && (