mirror of
https://github.com/Unleash/unleash.git
synced 2025-03-04 00:18:40 +01:00
refactor: rename sign-on log to login history (#3245)
Renames `sign-on log` to `login history`.
This commit is contained in:
parent
456eb04591
commit
ea83849cd3
@ -3,16 +3,16 @@ import AccessContext from 'contexts/AccessContext';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
||||
import { AdminAlert } from 'component/common/AdminAlert/AdminAlert';
|
||||
import { SignOnLogTable } from './SignOnLogTable/SignOnLogTable';
|
||||
import { LoginHistoryTable } from './LoginHistoryTable/LoginHistoryTable';
|
||||
|
||||
export const SignOnLog = () => {
|
||||
export const LoginHistory = () => {
|
||||
const { hasAccess } = useContext(AccessContext);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ConditionallyRender
|
||||
condition={hasAccess(ADMIN)}
|
||||
show={<SignOnLogTable />}
|
||||
show={<LoginHistoryTable />}
|
||||
elseShow={<AdminAlert />}
|
||||
/>
|
||||
</div>
|
@ -8,13 +8,13 @@ const StyledBox = styled(Box)(() => ({
|
||||
justifyContent: 'center',
|
||||
}));
|
||||
|
||||
interface ISignOnLogActionsCellProps {
|
||||
interface ILoginHistoryActionsCellProps {
|
||||
onDelete: (event: React.SyntheticEvent) => void;
|
||||
}
|
||||
|
||||
export const SignOnLogActionsCell = ({
|
||||
export const LoginHistoryActionsCell = ({
|
||||
onDelete,
|
||||
}: ISignOnLogActionsCellProps) => {
|
||||
}: ILoginHistoryActionsCellProps) => {
|
||||
return (
|
||||
<StyledBox>
|
||||
<PermissionIconButton
|
@ -1,28 +1,28 @@
|
||||
import { Dialogue } from 'component/common/Dialogue/Dialogue';
|
||||
|
||||
interface IServiceAccountDeleteAllDialogProps {
|
||||
interface ILoginHistoryDeleteAllDialogProps {
|
||||
open: boolean;
|
||||
setOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
onConfirm: () => void;
|
||||
}
|
||||
|
||||
export const SignOnLogDeleteAllDialog = ({
|
||||
export const LoginHistoryDeleteAllDialog = ({
|
||||
open,
|
||||
setOpen,
|
||||
onConfirm,
|
||||
}: IServiceAccountDeleteAllDialogProps) => (
|
||||
}: ILoginHistoryDeleteAllDialogProps) => (
|
||||
<Dialogue
|
||||
title="Clear sign-on log?"
|
||||
title="Clear login history?"
|
||||
open={open}
|
||||
primaryButtonText="Clear sign-on log"
|
||||
primaryButtonText="Clear login history"
|
||||
secondaryButtonText="Cancel"
|
||||
onClick={onConfirm}
|
||||
onClose={() => {
|
||||
setOpen(false);
|
||||
}}
|
||||
>
|
||||
You are about to clear the sign-on log.
|
||||
You are about to clear the login history.
|
||||
<br />
|
||||
This will delete all the sign-on events.
|
||||
This will delete all the login events.
|
||||
</Dialogue>
|
||||
);
|
@ -1,19 +1,19 @@
|
||||
import { Dialogue } from 'component/common/Dialogue/Dialogue';
|
||||
import { ISignOnEvent } from 'interfaces/signOnEvent';
|
||||
import { ILoginEvent } from 'interfaces/loginEvent';
|
||||
|
||||
interface IServiceAccountDeleteDialogProps {
|
||||
event?: ISignOnEvent;
|
||||
interface ILoginHistoryDeleteDialogProps {
|
||||
event?: ILoginEvent;
|
||||
open: boolean;
|
||||
setOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
onConfirm: (event: ISignOnEvent) => void;
|
||||
onConfirm: (event: ILoginEvent) => void;
|
||||
}
|
||||
|
||||
export const SignOnLogDeleteDialog = ({
|
||||
export const LoginHistoryDeleteDialog = ({
|
||||
event,
|
||||
open,
|
||||
setOpen,
|
||||
onConfirm,
|
||||
}: IServiceAccountDeleteDialogProps) => (
|
||||
}: ILoginHistoryDeleteDialogProps) => (
|
||||
<Dialogue
|
||||
title="Delete event?"
|
||||
open={open}
|
@ -2,7 +2,7 @@ import { VFC } from 'react';
|
||||
import { Box, styled } from '@mui/material';
|
||||
import { Highlighter } from 'component/common/Highlighter/Highlighter';
|
||||
import { useSearchHighlightContext } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
|
||||
import { ISignOnEvent } from 'interfaces/signOnEvent';
|
||||
import { ILoginEvent } from 'interfaces/loginEvent';
|
||||
import { Badge } from 'component/common/Badge/Badge';
|
||||
import { HtmlTooltip } from 'component/common/HtmlTooltip/HtmlTooltip';
|
||||
|
||||
@ -11,17 +11,16 @@ const StyledBox = styled(Box)(() => ({
|
||||
justifyContent: 'center',
|
||||
}));
|
||||
|
||||
interface ISignOnLogSuccessfulCellProps {
|
||||
interface ILoginHistorySuccessfulCellProps {
|
||||
row: {
|
||||
original: ISignOnEvent;
|
||||
original: ILoginEvent;
|
||||
};
|
||||
value: boolean;
|
||||
}
|
||||
|
||||
export const SignOnLogSuccessfulCell: VFC<ISignOnLogSuccessfulCellProps> = ({
|
||||
row,
|
||||
value,
|
||||
}) => {
|
||||
export const LoginHistorySuccessfulCell: VFC<
|
||||
ILoginHistorySuccessfulCellProps
|
||||
> = ({ row, value }) => {
|
||||
const { searchQuery } = useSearchHighlightContext();
|
||||
|
||||
if (value)
|
@ -16,17 +16,17 @@ import { Search } from 'component/common/Search/Search';
|
||||
import { useConditionallyHiddenColumns } from 'hooks/useConditionallyHiddenColumns';
|
||||
import { useSearch } from 'hooks/useSearch';
|
||||
import { TimeAgoCell } from 'component/common/Table/cells/TimeAgoCell/TimeAgoCell';
|
||||
import { useSignOnLog } from 'hooks/api/getters/useSignOnLog/useSignOnLog';
|
||||
import { SignOnLogSuccessfulCell } from './SignOnLogSuccessfulCell/SignOnLogSuccessfulCell';
|
||||
import { ISignOnEvent } from 'interfaces/signOnEvent';
|
||||
import { SignOnLogActionsCell } from './SignOnLogActionsCell/SignOnLogActionsCell';
|
||||
import { SignOnLogDeleteDialog } from './SignOnLogDeleteDialog/SignOnLogDeleteDialog';
|
||||
import { useSignOnLogApi } from 'hooks/api/actions/useSignOnLogApi/useSignOnLogApi';
|
||||
import { useLoginHistory } from 'hooks/api/getters/useLoginHistory/useLoginHistory';
|
||||
import { LoginHistorySuccessfulCell } from './LoginHistorySuccessfulCell/LoginHistorySuccessfulCell';
|
||||
import { ILoginEvent } from 'interfaces/loginEvent';
|
||||
import { LoginHistoryActionsCell } from './LoginHistoryActionsCell/LoginHistoryActionsCell';
|
||||
import { LoginHistoryDeleteDialog } from './LoginHistoryDeleteDialog/LoginHistoryDeleteDialog';
|
||||
import { useLoginHistoryApi } from 'hooks/api/actions/useLoginHistoryApi/useLoginHistoryApi';
|
||||
import { formatDateYMDHMS } from 'utils/formatDate';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { createLocalStorage } from 'utils/createLocalStorage';
|
||||
import { Delete, Download } from '@mui/icons-material';
|
||||
import { SignOnLogDeleteAllDialog } from './SignOnLogDeleteAllDialog/SignOnLogDeleteAllDialog';
|
||||
import { LoginHistoryDeleteAllDialog } from './LoginHistoryDeleteAllDialog/LoginHistoryDeleteAllDialog';
|
||||
|
||||
export type PageQueryType = Partial<
|
||||
Record<'sort' | 'order' | 'search', string>
|
||||
@ -35,7 +35,7 @@ export type PageQueryType = Partial<
|
||||
const defaultSort: SortingRule<string> = { id: 'created_at' };
|
||||
|
||||
const { value: storedParams, setValue: setStoredParams } = createLocalStorage(
|
||||
'SignOnLogTable:v1',
|
||||
'LoginHistoryTable:v1',
|
||||
defaultSort
|
||||
);
|
||||
|
||||
@ -46,11 +46,11 @@ const AUTH_TYPE_LABEL: { [key: string]: string } = {
|
||||
google: 'Google',
|
||||
};
|
||||
|
||||
export const SignOnLogTable = () => {
|
||||
export const LoginHistoryTable = () => {
|
||||
const { setToastData, setToastApiError } = useToast();
|
||||
|
||||
const { events, loading, refetch } = useSignOnLog();
|
||||
const { removeEvent, removeAllEvents, downloadCSV } = useSignOnLogApi();
|
||||
const { events, loading, refetch } = useLoginHistory();
|
||||
const { removeEvent, removeAllEvents, downloadCSV } = useLoginHistoryApi();
|
||||
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [initialState] = useState(() => ({
|
||||
@ -67,11 +67,11 @@ export const SignOnLogTable = () => {
|
||||
}));
|
||||
|
||||
const [searchValue, setSearchValue] = useState(initialState.globalFilter);
|
||||
const [selectedEvent, setSelectedEvent] = useState<ISignOnEvent>();
|
||||
const [selectedEvent, setSelectedEvent] = useState<ILoginEvent>();
|
||||
const [deleteOpen, setDeleteOpen] = useState(false);
|
||||
const [deleteAllOpen, setDeleteAllOpen] = useState(false);
|
||||
|
||||
const onDeleteConfirm = async (event: ISignOnEvent) => {
|
||||
const onDeleteConfirm = async (event: ILoginEvent) => {
|
||||
try {
|
||||
await removeEvent(event.id);
|
||||
setToastData({
|
||||
@ -89,7 +89,7 @@ export const SignOnLogTable = () => {
|
||||
try {
|
||||
await removeAllEvents();
|
||||
setToastData({
|
||||
title: `Log has been cleared`,
|
||||
title: `History has been cleared`,
|
||||
type: 'success',
|
||||
});
|
||||
refetch();
|
||||
@ -122,7 +122,7 @@ export const SignOnLogTable = () => {
|
||||
},
|
||||
{
|
||||
Header: 'Authentication',
|
||||
accessor: (event: ISignOnEvent) =>
|
||||
accessor: (event: ILoginEvent) =>
|
||||
AUTH_TYPE_LABEL[event.auth_type] || event.auth_type,
|
||||
width: 150,
|
||||
maxWidth: 150,
|
||||
@ -140,7 +140,7 @@ export const SignOnLogTable = () => {
|
||||
Header: 'Success',
|
||||
accessor: 'successful',
|
||||
align: 'center',
|
||||
Cell: SignOnLogSuccessfulCell,
|
||||
Cell: LoginHistorySuccessfulCell,
|
||||
filterName: 'success',
|
||||
filterParsing: (value: boolean) => value.toString(),
|
||||
},
|
||||
@ -149,7 +149,7 @@ export const SignOnLogTable = () => {
|
||||
id: 'Actions',
|
||||
align: 'center',
|
||||
Cell: ({ row: { original: event } }: any) => (
|
||||
<SignOnLogActionsCell
|
||||
<LoginHistoryActionsCell
|
||||
onDelete={() => {
|
||||
setSelectedEvent(event);
|
||||
setDeleteOpen(true);
|
||||
@ -238,7 +238,7 @@ export const SignOnLogTable = () => {
|
||||
isLoading={loading}
|
||||
header={
|
||||
<PageHeader
|
||||
title={`Sign-on log (${rows.length})`}
|
||||
title={`Login history (${rows.length})`}
|
||||
actions={
|
||||
<>
|
||||
<ConditionallyRender
|
||||
@ -261,7 +261,7 @@ export const SignOnLogTable = () => {
|
||||
show={<PageHeader.Divider />}
|
||||
/>
|
||||
<Tooltip
|
||||
title="Download sign-on log"
|
||||
title="Download login history"
|
||||
arrow
|
||||
>
|
||||
<IconButton onClick={downloadCSV}>
|
||||
@ -269,7 +269,7 @@ export const SignOnLogTable = () => {
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
title="Clear sign-on log"
|
||||
title="Clear login history"
|
||||
arrow
|
||||
>
|
||||
<IconButton
|
||||
@ -314,26 +314,26 @@ export const SignOnLogTable = () => {
|
||||
condition={searchValue?.length > 0}
|
||||
show={
|
||||
<TablePlaceholder>
|
||||
No sign-on events found matching “
|
||||
No login events found matching “
|
||||
{searchValue}
|
||||
”
|
||||
</TablePlaceholder>
|
||||
}
|
||||
elseShow={
|
||||
<TablePlaceholder>
|
||||
No sign-on events available.
|
||||
No login events available.
|
||||
</TablePlaceholder>
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<SignOnLogDeleteDialog
|
||||
<LoginHistoryDeleteDialog
|
||||
event={selectedEvent}
|
||||
open={deleteOpen}
|
||||
setOpen={setDeleteOpen}
|
||||
onConfirm={onDeleteConfirm}
|
||||
/>
|
||||
<SignOnLogDeleteAllDialog
|
||||
<LoginHistoryDeleteAllDialog
|
||||
open={deleteAllOpen}
|
||||
setOpen={setDeleteAllOpen}
|
||||
onConfirm={onDeleteAllConfirm}
|
@ -352,8 +352,8 @@ exports[`returns all baseRoutes 1`] = `
|
||||
"menu": {
|
||||
"adminSettings": true,
|
||||
},
|
||||
"path": "/admin/signons",
|
||||
"title": "Sign on log",
|
||||
"path": "/admin/logins",
|
||||
"title": "Login history",
|
||||
"type": "protected",
|
||||
},
|
||||
{
|
||||
|
@ -43,7 +43,7 @@ import { LazyFeatureView } from 'component/feature/FeatureView/LazyFeatureView';
|
||||
import { LazyAdmin } from 'component/admin/LazyAdmin';
|
||||
import { LazyProject } from 'component/project/Project/LazyProject';
|
||||
import { AdminRedirect } from 'component/admin/AdminRedirect';
|
||||
import { SignOnLog } from 'component/signOnLog/SignOnLog';
|
||||
import { LoginHistory } from 'component/loginHistory/LoginHistory';
|
||||
|
||||
export const routes: IRoute[] = [
|
||||
// Splash
|
||||
@ -357,9 +357,9 @@ export const routes: IRoute[] = [
|
||||
},
|
||||
|
||||
{
|
||||
path: '/admin/signons',
|
||||
title: 'Sign on log',
|
||||
component: SignOnLog,
|
||||
path: '/admin/logins',
|
||||
title: 'Login history',
|
||||
component: LoginHistory,
|
||||
type: 'protected',
|
||||
menu: { adminSettings: true },
|
||||
},
|
||||
@ -448,10 +448,10 @@ export const adminMenuRoutes: INavigationMenuItem[] = [
|
||||
menu: { adminSettings: true },
|
||||
},
|
||||
{
|
||||
path: '/admin/signons',
|
||||
title: 'Sign-on log',
|
||||
path: '/admin/logins',
|
||||
title: 'Login history',
|
||||
menu: { adminSettings: true },
|
||||
flag: 'signOnLog',
|
||||
flag: 'loginHistory',
|
||||
},
|
||||
{
|
||||
path: '/admin/users',
|
||||
|
@ -1,6 +1,6 @@
|
||||
import useAPI from '../useApi/useApi';
|
||||
|
||||
export const useSignOnLogApi = () => {
|
||||
export const useLoginHistoryApi = () => {
|
||||
const { loading, makeRequest, createRequest, errors } = useAPI({
|
||||
propagateErrors: true,
|
||||
});
|
||||
@ -8,7 +8,7 @@ export const useSignOnLogApi = () => {
|
||||
const downloadCSV = async () => {
|
||||
const requestId = 'downloadCSV';
|
||||
const req = createRequest(
|
||||
'api/admin/signons',
|
||||
'api/admin/logins',
|
||||
{
|
||||
method: 'GET',
|
||||
responseType: 'blob',
|
||||
@ -25,7 +25,7 @@ export const useSignOnLogApi = () => {
|
||||
const removeEvent = async (eventId: number) => {
|
||||
const requestId = 'removeEvent';
|
||||
const req = createRequest(
|
||||
`api/admin/signons/${eventId}`,
|
||||
`api/admin/logins/${eventId}`,
|
||||
{ method: 'DELETE' },
|
||||
requestId
|
||||
);
|
||||
@ -36,7 +36,7 @@ export const useSignOnLogApi = () => {
|
||||
const removeAllEvents = async () => {
|
||||
const requestId = 'removeAllEvents';
|
||||
const req = createRequest(
|
||||
'api/admin/signons',
|
||||
'api/admin/logins',
|
||||
{ method: 'DELETE' },
|
||||
requestId
|
||||
);
|
@ -1,25 +1,25 @@
|
||||
import { ISignOnEvent } from 'interfaces/signOnEvent';
|
||||
import { ILoginEvent } from 'interfaces/loginEvent';
|
||||
import { useMemo } from 'react';
|
||||
import { formatApiPath } from 'utils/formatPath';
|
||||
import handleErrorResponses from '../httpErrorResponseHandler';
|
||||
import { useConditionalSWR } from '../useConditionalSWR/useConditionalSWR';
|
||||
import useUiConfig from '../useUiConfig/useUiConfig';
|
||||
|
||||
export const useSignOnLog = () => {
|
||||
export const useLoginHistory = () => {
|
||||
const { uiConfig, isEnterprise } = useUiConfig();
|
||||
|
||||
const { signOnLog } = uiConfig.flags;
|
||||
const { loginHistory } = uiConfig.flags;
|
||||
|
||||
const { data, error, mutate } = useConditionalSWR(
|
||||
signOnLog && isEnterprise(),
|
||||
loginHistory && isEnterprise(),
|
||||
{ events: [] },
|
||||
formatApiPath(`api/admin/signons`),
|
||||
formatApiPath(`api/admin/logins`),
|
||||
fetcher
|
||||
);
|
||||
|
||||
return useMemo(
|
||||
() => ({
|
||||
events: (data?.events ?? []) as ISignOnEvent[],
|
||||
events: (data?.events ?? []) as ILoginEvent[],
|
||||
loading: !error && !data,
|
||||
refetch: () => mutate(),
|
||||
error,
|
||||
@ -30,6 +30,6 @@ export const useSignOnLog = () => {
|
||||
|
||||
const fetcher = (path: string) => {
|
||||
return fetch(path)
|
||||
.then(handleErrorResponses('Sign-On Log'))
|
||||
.then(handleErrorResponses('Login History'))
|
||||
.then(res => res.json());
|
||||
};
|
@ -1,4 +1,4 @@
|
||||
export interface ISignOnEvent {
|
||||
export interface ILoginEvent {
|
||||
id: number;
|
||||
username: string;
|
||||
auth_type: string;
|
@ -47,7 +47,7 @@ export interface IFlags {
|
||||
showProjectApiAccess?: boolean;
|
||||
proPlanAutoCharge?: boolean;
|
||||
notifications?: boolean;
|
||||
signOnLog?: boolean;
|
||||
loginHistory?: boolean;
|
||||
}
|
||||
|
||||
export interface IVersionInfo {
|
||||
|
@ -74,6 +74,7 @@ exports[`should create default config 1`] = `
|
||||
"embedProxy": true,
|
||||
"embedProxyFrontend": true,
|
||||
"featuresExportImport": false,
|
||||
"loginHistory": false,
|
||||
"maintenanceMode": false,
|
||||
"messageBanner": false,
|
||||
"newProjectOverview": false,
|
||||
@ -83,7 +84,6 @@ exports[`should create default config 1`] = `
|
||||
"proxyReturnAllToggles": false,
|
||||
"responseTimeWithAppNameKillSwitch": false,
|
||||
"showProjectApiAccess": false,
|
||||
"signOnLog": false,
|
||||
"strictSchemaValidation": false,
|
||||
},
|
||||
},
|
||||
@ -96,6 +96,7 @@ exports[`should create default config 1`] = `
|
||||
"embedProxy": true,
|
||||
"embedProxyFrontend": true,
|
||||
"featuresExportImport": false,
|
||||
"loginHistory": false,
|
||||
"maintenanceMode": false,
|
||||
"messageBanner": false,
|
||||
"newProjectOverview": false,
|
||||
@ -105,7 +106,6 @@ exports[`should create default config 1`] = `
|
||||
"proxyReturnAllToggles": false,
|
||||
"responseTimeWithAppNameKillSwitch": false,
|
||||
"showProjectApiAccess": false,
|
||||
"signOnLog": false,
|
||||
"strictSchemaValidation": false,
|
||||
},
|
||||
"externalResolver": {
|
||||
|
@ -63,7 +63,7 @@ const flags = {
|
||||
false,
|
||||
),
|
||||
notifications: parseEnvVarBoolean(process.env.NOTIFICATIONS, false),
|
||||
signOnLog: parseEnvVarBoolean(process.env.UNLEASH_SIGN_ON_LOG, false),
|
||||
loginHistory: parseEnvVarBoolean(process.env.UNLEASH_LOGIN_HISTORY, false),
|
||||
};
|
||||
|
||||
export const defaultExperimentalOptions: IExperimentalOptions = {
|
||||
|
@ -0,0 +1,20 @@
|
||||
exports.up = function (db, cb) {
|
||||
db.runSql(`ALTER TABLE sign_on_log RENAME TO login_history`, cb);
|
||||
db.runSql(`DELETE FROM settings WHERE name = 'sign_on_log_retention'`, cb);
|
||||
db.runSql(
|
||||
`INSERT INTO settings(name, content) VALUES ('login_history_retention', '{"hours": 336}')`,
|
||||
cb,
|
||||
);
|
||||
};
|
||||
|
||||
exports.down = function (db, cb) {
|
||||
db.runSql(`ALTER TABLE login_history RENAME TO sign_on_log`, cb);
|
||||
db.runSql(
|
||||
`DELETE FROM settings WHERE name = 'login_history_retention'`,
|
||||
cb,
|
||||
);
|
||||
db.runSql(
|
||||
`INSERT INTO settings(name, content) VALUES ('sign_on_log_retention', '{"hours": 336}')`,
|
||||
cb,
|
||||
);
|
||||
};
|
Loading…
Reference in New Issue
Block a user