mirror of
https://github.com/inventree/InvenTree.git
synced 2025-05-10 17:28:50 +00:00
[PUI] Table query params (#8279)
* Pass more information through in redirect after login - Include query parameters in redirect * InvenTreeTable: Update filters based on URL query parameters * Add button to remove custom URL query filters
This commit is contained in:
parent
7d3eb433d6
commit
eeab8d30fb
@ -17,7 +17,11 @@ import { useLocation, useNavigate } from 'react-router-dom';
|
|||||||
|
|
||||||
import { api } from '../../App';
|
import { api } from '../../App';
|
||||||
import { ApiEndpoints } from '../../enums/ApiEndpoints';
|
import { ApiEndpoints } from '../../enums/ApiEndpoints';
|
||||||
import { doBasicLogin, doSimpleLogin } from '../../functions/auth';
|
import {
|
||||||
|
doBasicLogin,
|
||||||
|
doSimpleLogin,
|
||||||
|
followRedirect
|
||||||
|
} from '../../functions/auth';
|
||||||
import { showLoginNotification } from '../../functions/notifications';
|
import { showLoginNotification } from '../../functions/notifications';
|
||||||
import { apiUrl, useServerApiState } from '../../states/ApiState';
|
import { apiUrl, useServerApiState } from '../../states/ApiState';
|
||||||
import { useUserState } from '../../states/UserState';
|
import { useUserState } from '../../states/UserState';
|
||||||
@ -51,8 +55,7 @@ export function AuthenticationForm() {
|
|||||||
title: t`Login successful`,
|
title: t`Login successful`,
|
||||||
message: t`Logged in successfully`
|
message: t`Logged in successfully`
|
||||||
});
|
});
|
||||||
|
followRedirect(navigate, location?.state);
|
||||||
navigate(location?.state?.redirectFrom ?? '/home');
|
|
||||||
} else {
|
} else {
|
||||||
showLoginNotification({
|
showLoginNotification({
|
||||||
title: t`Login failed`,
|
title: t`Login failed`,
|
||||||
|
@ -18,7 +18,14 @@ export const ProtectedRoute = ({ children }: { children: JSX.Element }) => {
|
|||||||
|
|
||||||
if (!isLoggedIn()) {
|
if (!isLoggedIn()) {
|
||||||
return (
|
return (
|
||||||
<Navigate to="/logged-in" state={{ redirectFrom: location.pathname }} />
|
<Navigate
|
||||||
|
to="/logged-in"
|
||||||
|
state={{
|
||||||
|
redirectUrl: location.pathname,
|
||||||
|
queryParams: location.search,
|
||||||
|
anchor: location.hash
|
||||||
|
}}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
import { notifications } from '@mantine/notifications';
|
import { notifications } from '@mantine/notifications';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { NavigateFunction } from 'react-router-dom';
|
import { Navigate, NavigateFunction } from 'react-router-dom';
|
||||||
|
|
||||||
import { api, setApiDefaults } from '../App';
|
import { api, setApiDefaults } from '../App';
|
||||||
import { ApiEndpoints } from '../enums/ApiEndpoints';
|
import { ApiEndpoints } from '../enums/ApiEndpoints';
|
||||||
@ -11,6 +11,17 @@ import { useUserState } from '../states/UserState';
|
|||||||
import { fetchGlobalStates } from '../states/states';
|
import { fetchGlobalStates } from '../states/states';
|
||||||
import { showLoginNotification } from './notifications';
|
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.
|
* 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
|
* @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 (
|
export const checkLoginState = async (
|
||||||
navigate: any,
|
navigate: any,
|
||||||
redirect?: string,
|
redirect?: any,
|
||||||
no_redirect?: boolean
|
no_redirect?: boolean
|
||||||
) => {
|
) => {
|
||||||
setApiDefaults();
|
setApiDefaults();
|
||||||
@ -197,13 +208,13 @@ export const checkLoginState = async (
|
|||||||
|
|
||||||
fetchGlobalStates();
|
fetchGlobalStates();
|
||||||
|
|
||||||
navigate(redirect ?? '/home');
|
followRedirect(navigate, redirect);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Callback function when login fails
|
// Callback function when login fails
|
||||||
const loginFailure = () => {
|
const loginFailure = () => {
|
||||||
if (!no_redirect) {
|
if (!no_redirect) {
|
||||||
navigate('/login', { state: { redirectFrom: redirect } });
|
navigate('/login', { state: redirect });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ export default function Logged_In() {
|
|||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
checkLoginState(navigate, location?.state?.redirectFrom);
|
checkLoginState(navigate, location?.state);
|
||||||
}, [navigate]);
|
}, [navigate]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -13,7 +13,11 @@ import {
|
|||||||
} from '../../components/forms/AuthenticationForm';
|
} from '../../components/forms/AuthenticationForm';
|
||||||
import { InstanceOptions } from '../../components/forms/InstanceOptions';
|
import { InstanceOptions } from '../../components/forms/InstanceOptions';
|
||||||
import { defaultHostKey } from '../../defaults/defaultHostList';
|
import { defaultHostKey } from '../../defaults/defaultHostList';
|
||||||
import { checkLoginState, doBasicLogin } from '../../functions/auth';
|
import {
|
||||||
|
checkLoginState,
|
||||||
|
doBasicLogin,
|
||||||
|
followRedirect
|
||||||
|
} from '../../functions/auth';
|
||||||
import { useServerApiState } from '../../states/ApiState';
|
import { useServerApiState } from '../../states/ApiState';
|
||||||
import { useLocalState } from '../../states/LocalState';
|
import { useLocalState } from '../../states/LocalState';
|
||||||
|
|
||||||
@ -49,7 +53,7 @@ export default function Login() {
|
|||||||
ChangeHost(defaultHostKey);
|
ChangeHost(defaultHostKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
checkLoginState(navigate, location?.state?.redirectFrom, true);
|
checkLoginState(navigate, location?.state, true);
|
||||||
|
|
||||||
// check if we got login params (login and password)
|
// check if we got login params (login and password)
|
||||||
if (searchParams.has('login') && searchParams.has('password')) {
|
if (searchParams.has('login') && searchParams.has('password')) {
|
||||||
@ -57,7 +61,7 @@ export default function Login() {
|
|||||||
searchParams.get('login') ?? '',
|
searchParams.get('login') ?? '',
|
||||||
searchParams.get('password') ?? ''
|
searchParams.get('password') ?? ''
|
||||||
).then(() => {
|
).then(() => {
|
||||||
navigate(location?.state?.redirectFrom ?? '/home');
|
followRedirect(navigate, location?.state);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
@ -12,6 +12,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
IconBarcode,
|
IconBarcode,
|
||||||
IconFilter,
|
IconFilter,
|
||||||
|
IconFilterCancel,
|
||||||
IconRefresh,
|
IconRefresh,
|
||||||
IconTrash
|
IconTrash
|
||||||
} from '@tabler/icons-react';
|
} from '@tabler/icons-react';
|
||||||
@ -28,7 +29,7 @@ import React, {
|
|||||||
useMemo,
|
useMemo,
|
||||||
useState
|
useState
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate, useSearchParams } from 'react-router-dom';
|
||||||
|
|
||||||
import { api } from '../App';
|
import { api } from '../App';
|
||||||
import { Boundary } from '../components/Boundary';
|
import { Boundary } from '../components/Boundary';
|
||||||
@ -155,10 +156,14 @@ export function InvenTreeTable<T extends Record<string, any>>({
|
|||||||
setTableSorting,
|
setTableSorting,
|
||||||
loader
|
loader
|
||||||
} = useLocalState();
|
} = useLocalState();
|
||||||
|
|
||||||
const [fieldNames, setFieldNames] = useState<Record<string, string>>({});
|
const [fieldNames, setFieldNames] = useState<Record<string, string>>({});
|
||||||
|
|
||||||
const navigate = useNavigate();
|
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
|
// Construct table filters - note that we can introspect filter labels from column names
|
||||||
const filters: TableFilter[] = useMemo(() => {
|
const filters: TableFilter[] = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
@ -361,6 +366,13 @@ export function InvenTreeTable<T extends Record<string, any>>({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Allow override of filters based on URL query parameters
|
||||||
|
if (urlQueryParams) {
|
||||||
|
for (let [key, value] of urlQueryParams) {
|
||||||
|
queryParams[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Add custom search term
|
// Add custom search term
|
||||||
if (tableState.searchTerm) {
|
if (tableState.searchTerm) {
|
||||||
queryParams.search = tableState.searchTerm;
|
queryParams.search = tableState.searchTerm;
|
||||||
@ -522,6 +534,11 @@ export function InvenTreeTable<T extends Record<string, any>>({
|
|||||||
refetchOnMount: true
|
refetchOnMount: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Refetch data when the query parameters change
|
||||||
|
useEffect(() => {
|
||||||
|
refetch();
|
||||||
|
}, [urlQueryParams]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
tableState.setIsLoading(
|
tableState.setIsLoading(
|
||||||
isFetching ||
|
isFetching ||
|
||||||
@ -699,6 +716,21 @@ export function InvenTreeTable<T extends Record<string, any>>({
|
|||||||
onToggleColumn={toggleColumn}
|
onToggleColumn={toggleColumn}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{urlQueryParams.size > 0 && (
|
||||||
|
<ActionIcon
|
||||||
|
variant="transparent"
|
||||||
|
color="red"
|
||||||
|
aria-label="table-clear-query-filters"
|
||||||
|
>
|
||||||
|
<Tooltip label={t`Clear custom query filters`}>
|
||||||
|
<IconFilterCancel
|
||||||
|
onClick={() => {
|
||||||
|
setUrlQueryParams({});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</ActionIcon>
|
||||||
|
)}
|
||||||
{tableProps.enableFilters && filters.length > 0 && (
|
{tableProps.enableFilters && filters.length > 0 && (
|
||||||
<Indicator
|
<Indicator
|
||||||
size="xs"
|
size="xs"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user