mirror of
https://github.com/Unleash/unleash.git
synced 2025-07-12 13:48:35 +02:00
refactor: port global settings to TS/hooks (#679)
* refactor: add ref support to PermissionSwitch * refactor: port global settings to TS/hooks * refactor: fix file extension * refactor: format file * refactor: fix inconsistent locationSettings prop * refactor: use correct locationSettings hook * refactor: use objects for settings hooks
This commit is contained in:
parent
36f59b2290
commit
fee1894c34
@ -31,6 +31,7 @@ import Dialogue from '../../../common/Dialogue';
|
|||||||
import { CREATE_API_TOKEN_BUTTON } from '../../../../testIds';
|
import { CREATE_API_TOKEN_BUTTON } from '../../../../testIds';
|
||||||
import { Alert } from '@material-ui/lab';
|
import { Alert } from '@material-ui/lab';
|
||||||
import copy from 'copy-to-clipboard';
|
import copy from 'copy-to-clipboard';
|
||||||
|
import { useLocationSettings } from "../../../../hooks/useLocationSettings";
|
||||||
|
|
||||||
interface IApiToken {
|
interface IApiToken {
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
@ -41,16 +42,13 @@ interface IApiToken {
|
|||||||
environment: string;
|
environment: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IApiTokenList {
|
const ApiTokenList = () => {
|
||||||
location: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ApiTokenList = ({ location }: IApiTokenList) => {
|
|
||||||
const styles = useStyles();
|
const styles = useStyles();
|
||||||
const { hasAccess } = useContext(AccessContext);
|
const { hasAccess } = useContext(AccessContext);
|
||||||
const { uiConfig } = useUiConfig();
|
const { uiConfig } = useUiConfig();
|
||||||
const [showDelete, setShowDelete] = useState(false);
|
const [showDelete, setShowDelete] = useState(false);
|
||||||
const [delToken, setDeleteToken] = useState<IApiToken>();
|
const [delToken, setDeleteToken] = useState<IApiToken>();
|
||||||
|
const { locationSettings } = useLocationSettings()
|
||||||
const { setToastData } = useToast();
|
const { setToastData } = useToast();
|
||||||
const { tokens, loading, refetch, error } = useApiTokens();
|
const { tokens, loading, refetch, error } = useApiTokens();
|
||||||
const { deleteToken } = useApiTokensApi();
|
const { deleteToken } = useApiTokensApi();
|
||||||
@ -150,7 +148,7 @@ const ApiTokenList = ({ location }: IApiTokenList) => {
|
|||||||
>
|
>
|
||||||
{formatDateWithLocale(
|
{formatDateWithLocale(
|
||||||
item.createdAt,
|
item.createdAt,
|
||||||
location.locale
|
locationSettings.locale
|
||||||
)}
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell
|
<TableCell
|
||||||
|
@ -5,7 +5,7 @@ import AdminMenu from '../menu/AdminMenu';
|
|||||||
import usePermissions from '../../../hooks/usePermissions';
|
import usePermissions from '../../../hooks/usePermissions';
|
||||||
import ConditionallyRender from '../../common/ConditionallyRender';
|
import ConditionallyRender from '../../common/ConditionallyRender';
|
||||||
|
|
||||||
const ApiPage = ({ history, location }) => {
|
const ApiPage = ({ history }) => {
|
||||||
const { isAdmin } = usePermissions();
|
const { isAdmin } = usePermissions();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -14,7 +14,7 @@ const ApiPage = ({ history, location }) => {
|
|||||||
condition={isAdmin()}
|
condition={isAdmin()}
|
||||||
show={<AdminMenu history={history} />}
|
show={<AdminMenu history={history} />}
|
||||||
/>
|
/>
|
||||||
<ApiTokenList location={location} />
|
<ApiTokenList />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -22,7 +22,6 @@ const ApiPage = ({ history, location }) => {
|
|||||||
ApiPage.propTypes = {
|
ApiPage.propTypes = {
|
||||||
match: PropTypes.object.isRequired,
|
match: PropTypes.object.isRequired,
|
||||||
history: PropTypes.object.isRequired,
|
history: PropTypes.object.isRequired,
|
||||||
location: PropTypes.object.isRequired,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ApiPage;
|
export default ApiPage;
|
||||||
|
@ -14,15 +14,15 @@ import HeaderTitle from '../../common/HeaderTitle';
|
|||||||
import ConditionallyRender from '../../common/ConditionallyRender';
|
import ConditionallyRender from '../../common/ConditionallyRender';
|
||||||
import { formatApiPath } from '../../../utils/format-path';
|
import { formatApiPath } from '../../../utils/format-path';
|
||||||
import useInvoices from '../../../hooks/api/getters/useInvoices/useInvoices';
|
import useInvoices from '../../../hooks/api/getters/useInvoices/useInvoices';
|
||||||
import { useLocation } from 'react-router-dom';
|
|
||||||
import { IInvoice } from '../../../interfaces/invoice';
|
import { IInvoice } from '../../../interfaces/invoice';
|
||||||
|
import { useLocationSettings } from '../../../hooks/useLocationSettings';
|
||||||
|
|
||||||
const PORTAL_URL = formatApiPath('api/admin/invoices/portal');
|
const PORTAL_URL = formatApiPath('api/admin/invoices/portal');
|
||||||
|
|
||||||
const InvoiceList = () => {
|
const InvoiceList = () => {
|
||||||
const { refetchInvoices, invoices } = useInvoices();
|
const { refetchInvoices, invoices } = useInvoices();
|
||||||
const [isLoaded, setLoaded] = useState(false);
|
const [isLoaded, setLoaded] = useState(false);
|
||||||
const location = useLocation();
|
const { locationSettings } = useLocationSettings();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
refetchInvoices();
|
refetchInvoices();
|
||||||
@ -89,7 +89,7 @@ const InvoiceList = () => {
|
|||||||
{item.dueDate &&
|
{item.dueDate &&
|
||||||
formatDateWithLocale(
|
formatDateWithLocale(
|
||||||
item.dueDate,
|
item.dueDate,
|
||||||
location.locale
|
locationSettings.locale
|
||||||
)}
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell
|
<TableCell
|
||||||
|
@ -14,6 +14,7 @@ import AccessContext from '../../../../../contexts/AccessContext';
|
|||||||
import { IUser } from '../../../../../interfaces/user';
|
import { IUser } from '../../../../../interfaces/user';
|
||||||
import { useStyles } from './UserListItem.styles';
|
import { useStyles } from './UserListItem.styles';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
|
import { ILocationSettings } from "../../../../../hooks/useLocationSettings";
|
||||||
|
|
||||||
interface IUserListItemProps {
|
interface IUserListItemProps {
|
||||||
user: IUser;
|
user: IUser;
|
||||||
@ -21,11 +22,7 @@ interface IUserListItemProps {
|
|||||||
openUpdateDialog: (user: IUser) => (e: SyntheticEvent) => void;
|
openUpdateDialog: (user: IUser) => (e: SyntheticEvent) => void;
|
||||||
openPwDialog: (user: IUser) => (e: SyntheticEvent) => void;
|
openPwDialog: (user: IUser) => (e: SyntheticEvent) => void;
|
||||||
openDelDialog: (user: IUser) => (e: SyntheticEvent) => void;
|
openDelDialog: (user: IUser) => (e: SyntheticEvent) => void;
|
||||||
location: ILocation;
|
locationSettings: ILocationSettings;
|
||||||
}
|
|
||||||
|
|
||||||
interface ILocation {
|
|
||||||
locale: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const UserListItem = ({
|
const UserListItem = ({
|
||||||
@ -34,7 +31,7 @@ const UserListItem = ({
|
|||||||
openDelDialog,
|
openDelDialog,
|
||||||
openPwDialog,
|
openPwDialog,
|
||||||
openUpdateDialog,
|
openUpdateDialog,
|
||||||
location,
|
locationSettings,
|
||||||
}: IUserListItemProps) => {
|
}: IUserListItemProps) => {
|
||||||
const { hasAccess } = useContext(AccessContext);
|
const { hasAccess } = useContext(AccessContext);
|
||||||
const history = useHistory()
|
const history = useHistory()
|
||||||
@ -54,7 +51,7 @@ const UserListItem = ({
|
|||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<span data-loading>
|
<span data-loading>
|
||||||
{formatDateWithLocale(user.createdAt, location.locale)}
|
{formatDateWithLocale(user.createdAt, locationSettings.locale)}
|
||||||
</span>
|
</span>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className={styles.leftTableCell}>
|
<TableCell className={styles.leftTableCell}>
|
||||||
|
@ -20,10 +20,10 @@ import loadingData from './loadingData';
|
|||||||
import useLoading from '../../../../hooks/useLoading';
|
import useLoading from '../../../../hooks/useLoading';
|
||||||
import usePagination from '../../../../hooks/usePagination';
|
import usePagination from '../../../../hooks/usePagination';
|
||||||
import PaginateUI from '../../../common/PaginateUI/PaginateUI';
|
import PaginateUI from '../../../common/PaginateUI/PaginateUI';
|
||||||
import { useHistory } from 'react-router-dom';
|
|
||||||
import { IUser } from '../../../../interfaces/user';
|
import { IUser } from '../../../../interfaces/user';
|
||||||
import IRole from '../../../../interfaces/role';
|
import IRole from '../../../../interfaces/role';
|
||||||
import useToast from '../../../../hooks/useToast';
|
import useToast from '../../../../hooks/useToast';
|
||||||
|
import { useLocationSettings } from "../../../../hooks/useLocationSettings";
|
||||||
|
|
||||||
const UsersList = () => {
|
const UsersList = () => {
|
||||||
const { users, roles, refetch, loading } = useUsers();
|
const { users, roles, refetch, loading } = useUsers();
|
||||||
@ -35,9 +35,8 @@ const UsersList = () => {
|
|||||||
userLoading,
|
userLoading,
|
||||||
userApiErrors,
|
userApiErrors,
|
||||||
} = useAdminUsersApi();
|
} = useAdminUsersApi();
|
||||||
const history = useHistory();
|
|
||||||
const { location } = history;
|
|
||||||
const { hasAccess } = useContext(AccessContext);
|
const { hasAccess } = useContext(AccessContext);
|
||||||
|
const { locationSettings } = useLocationSettings()
|
||||||
const [pwDialog, setPwDialog] = useState<{ open: boolean; user?: IUser }>({
|
const [pwDialog, setPwDialog] = useState<{ open: boolean; user?: IUser }>({
|
||||||
open: false,
|
open: false,
|
||||||
});
|
});
|
||||||
@ -104,7 +103,7 @@ const UsersList = () => {
|
|||||||
user={user}
|
user={user}
|
||||||
openPwDialog={openPwDialog}
|
openPwDialog={openPwDialog}
|
||||||
openDelDialog={openDelDialog}
|
openDelDialog={openDelDialog}
|
||||||
location={location}
|
locationSettings={locationSettings}
|
||||||
renderRole={renderRole}
|
renderRole={renderRole}
|
||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
@ -117,7 +116,7 @@ const UsersList = () => {
|
|||||||
user={user}
|
user={user}
|
||||||
openPwDialog={openPwDialog}
|
openPwDialog={openPwDialog}
|
||||||
openDelDialog={openDelDialog}
|
openDelDialog={openDelDialog}
|
||||||
location={location}
|
locationSettings={locationSettings}
|
||||||
renderRole={renderRole}
|
renderRole={renderRole}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -19,6 +19,7 @@ test('renders correctly if no application', () => {
|
|||||||
storeApplicationMetaData={jest.fn()}
|
storeApplicationMetaData={jest.fn()}
|
||||||
deleteApplication={jest.fn()}
|
deleteApplication={jest.fn()}
|
||||||
history={{}}
|
history={{}}
|
||||||
|
locationSettings={{ locale: 'en-GB' }}
|
||||||
/>
|
/>
|
||||||
</AccessProvider>
|
</AccessProvider>
|
||||||
)
|
)
|
||||||
@ -77,7 +78,7 @@ test('renders correctly without permission', () => {
|
|||||||
url: 'http://example.org',
|
url: 'http://example.org',
|
||||||
description: 'app description',
|
description: 'app description',
|
||||||
}}
|
}}
|
||||||
location={{ locale: 'en-GB' }}
|
locationSettings={{ locale: 'en-GB' }}
|
||||||
/>
|
/>
|
||||||
</AccessProvider>
|
</AccessProvider>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
@ -140,7 +141,7 @@ test('renders correctly with permissions', () => {
|
|||||||
url: 'http://example.org',
|
url: 'http://example.org',
|
||||||
description: 'app description',
|
description: 'app description',
|
||||||
}}
|
}}
|
||||||
location={{ locale: 'en-GB' }}
|
locationSettings={{ locale: 'en-GB' }}
|
||||||
/>
|
/>
|
||||||
</AccessProvider>
|
</AccessProvider>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
|
@ -33,7 +33,7 @@ class ClientApplications extends PureComponent {
|
|||||||
fetchApplication: PropTypes.func.isRequired,
|
fetchApplication: PropTypes.func.isRequired,
|
||||||
appName: PropTypes.string,
|
appName: PropTypes.string,
|
||||||
application: PropTypes.object,
|
application: PropTypes.object,
|
||||||
location: PropTypes.object,
|
locationSettings: PropTypes.object.isRequired,
|
||||||
storeApplicationMetaData: PropTypes.func.isRequired,
|
storeApplicationMetaData: PropTypes.func.isRequired,
|
||||||
deleteApplication: PropTypes.func.isRequired,
|
deleteApplication: PropTypes.func.isRequired,
|
||||||
history: PropTypes.object.isRequired,
|
history: PropTypes.object.isRequired,
|
||||||
@ -54,8 +54,8 @@ class ClientApplications extends PureComponent {
|
|||||||
.finally(() => this.setState({ loading: false }));
|
.finally(() => this.setState({ loading: false }));
|
||||||
}
|
}
|
||||||
formatFullDateTime = v =>
|
formatFullDateTime = v =>
|
||||||
formatFullDateTimeWithLocale(v, this.props.location.locale);
|
formatFullDateTimeWithLocale(v, this.props.locationSettings.locale);
|
||||||
formatDate = v => formatDateWithLocale(v, this.props.location.locale);
|
formatDate = v => formatDateWithLocale(v, this.props.locationSettings.locale);
|
||||||
|
|
||||||
deleteApplication = async evt => {
|
deleteApplication = async evt => {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
import { connect } from 'react-redux';
|
|
||||||
import ApplicationEdit from './application-edit-component';
|
|
||||||
import { fetchApplication, storeApplicationMetaData, deleteApplication } from './../../store/application/actions';
|
|
||||||
|
|
||||||
const mapStateToProps = (state, props) => {
|
|
||||||
let application = state.applications.getIn(['apps', props.appName]);
|
|
||||||
const location = state.settings.toJS().location || {};
|
|
||||||
if (application) {
|
|
||||||
application = application.toJS();
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
application,
|
|
||||||
location,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const Container = connect(mapStateToProps, {
|
|
||||||
fetchApplication,
|
|
||||||
storeApplicationMetaData,
|
|
||||||
deleteApplication,
|
|
||||||
})(ApplicationEdit);
|
|
||||||
|
|
||||||
export default Container;
|
|
@ -0,0 +1,30 @@
|
|||||||
|
import { connect } from 'react-redux';
|
||||||
|
import ApplicationEdit from './application-edit-component';
|
||||||
|
import {
|
||||||
|
deleteApplication,
|
||||||
|
fetchApplication,
|
||||||
|
storeApplicationMetaData,
|
||||||
|
} from '../../store/application/actions';
|
||||||
|
import { useLocationSettings } from '../../hooks/useLocationSettings';
|
||||||
|
|
||||||
|
const ApplicationEditContainer = props => {
|
||||||
|
const { locationSettings } = useLocationSettings();
|
||||||
|
|
||||||
|
return <ApplicationEdit {...props} locationSettings={locationSettings} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = (state, props) => {
|
||||||
|
let application = state.applications.getIn(['apps', props.appName]);
|
||||||
|
if (application) {
|
||||||
|
application = application.toJS();
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
application,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, {
|
||||||
|
fetchApplication,
|
||||||
|
storeApplicationMetaData,
|
||||||
|
deleteApplication,
|
||||||
|
})(ApplicationEditContainer);
|
@ -13,7 +13,11 @@ interface IPermissionSwitchProps extends OverridableComponent<any> {
|
|||||||
checked: boolean;
|
checked: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PermissionSwitch: React.FC<IPermissionSwitchProps> = ({
|
const PermissionSwitch = React.forwardRef<
|
||||||
|
HTMLButtonElement,
|
||||||
|
IPermissionSwitchProps
|
||||||
|
>((props, ref) => {
|
||||||
|
const {
|
||||||
permission,
|
permission,
|
||||||
tooltip = '',
|
tooltip = '',
|
||||||
disabled,
|
disabled,
|
||||||
@ -22,7 +26,8 @@ const PermissionSwitch: React.FC<IPermissionSwitchProps> = ({
|
|||||||
checked,
|
checked,
|
||||||
onChange,
|
onChange,
|
||||||
...rest
|
...rest
|
||||||
}) => {
|
} = props;
|
||||||
|
|
||||||
const { hasAccess } = useContext(AccessContext);
|
const { hasAccess } = useContext(AccessContext);
|
||||||
|
|
||||||
let access;
|
let access;
|
||||||
@ -45,11 +50,12 @@ const PermissionSwitch: React.FC<IPermissionSwitchProps> = ({
|
|||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
disabled={disabled || !access}
|
disabled={disabled || !access}
|
||||||
checked={checked}
|
checked={checked}
|
||||||
|
ref={ref}
|
||||||
{...rest}
|
{...rest}
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
|
||||||
export default PermissionSwitch;
|
export default PermissionSwitch;
|
||||||
|
@ -1,25 +1,21 @@
|
|||||||
import { Tooltip } from '@material-ui/core';
|
import { Tooltip } from '@material-ui/core';
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { formatDateWithLocale, formatFullDateTimeWithLocale } from '../../../common/util';
|
import { formatDateWithLocale, formatFullDateTimeWithLocale } from '../../../common/util';
|
||||||
|
import { useLocationSettings } from "../../../../hooks/useLocationSettings";
|
||||||
|
|
||||||
interface CreatedAtProps {
|
interface CreatedAtProps {
|
||||||
time: Date;
|
time: Date;
|
||||||
//@ts-ignore
|
|
||||||
location: any;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const CreatedAt = ({time, location}: CreatedAtProps) => {
|
const CreatedAt = ({time}: CreatedAtProps) => {
|
||||||
|
const { locationSettings } = useLocationSettings();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip title={`Created at ${formatFullDateTimeWithLocale(time, location.locale)}`}>
|
<Tooltip title={`Created at ${formatFullDateTimeWithLocale(time, locationSettings.locale)}`}>
|
||||||
<span>
|
<span>
|
||||||
{formatDateWithLocale(time, location.locale)}
|
{formatDateWithLocale(time, locationSettings.locale)}
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state: any) => ({
|
export default CreatedAt;
|
||||||
location: state.settings.toJS().location,
|
|
||||||
});
|
|
||||||
|
|
||||||
export default connect(mapStateToProps)(CreatedAt);
|
|
||||||
|
@ -11,24 +11,21 @@ import EventCard from './EventCard/EventCard';
|
|||||||
import { useStyles } from './EventLog.styles.js';
|
import { useStyles } from './EventLog.styles.js';
|
||||||
|
|
||||||
const EventLog = ({
|
const EventLog = ({
|
||||||
updateSetting,
|
|
||||||
title,
|
title,
|
||||||
history,
|
history,
|
||||||
settings,
|
eventSettings,
|
||||||
|
setEventSettings,
|
||||||
|
locationSettings,
|
||||||
displayInline,
|
displayInline,
|
||||||
location,
|
|
||||||
hideName,
|
|
||||||
}) => {
|
}) => {
|
||||||
const styles = useStyles();
|
const styles = useStyles();
|
||||||
const toggleShowDiff = () => {
|
const toggleShowDiff = () => {
|
||||||
updateSetting('showData', !settings.showData);
|
setEventSettings({ showData: !eventSettings.showData });
|
||||||
};
|
};
|
||||||
const formatFulldateTime = v => {
|
const formatFulldateTime = v => {
|
||||||
return formatFullDateTimeWithLocale(v, location.locale);
|
return formatFullDateTimeWithLocale(v, locationSettings.locale);
|
||||||
};
|
};
|
||||||
|
|
||||||
const showData = settings.showData;
|
|
||||||
|
|
||||||
if (!history || history.length < 0) {
|
if (!history || history.length < 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -44,7 +41,7 @@ const EventLog = ({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
if (showData) {
|
if (eventSettings.showData) {
|
||||||
entries = history.map(entry => (
|
entries = history.map(entry => (
|
||||||
<EventJson key={`log${entry.id}`} entry={entry} />
|
<EventJson key={`log${entry.id}`} entry={entry} />
|
||||||
));
|
));
|
||||||
@ -63,7 +60,7 @@ const EventLog = ({
|
|||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
control={
|
control={
|
||||||
<Switch
|
<Switch
|
||||||
checked={showData}
|
checked={eventSettings.showData}
|
||||||
onChange={toggleShowDiff}
|
onChange={toggleShowDiff}
|
||||||
color="primary"
|
color="primary"
|
||||||
/>
|
/>
|
||||||
@ -82,12 +79,12 @@ const EventLog = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
EventLog.propTypes = {
|
EventLog.propTypes = {
|
||||||
updateSettings: PropTypes.func,
|
history: PropTypes.array,
|
||||||
|
eventSettings: PropTypes.object.isRequired,
|
||||||
|
setEventSettings: PropTypes.func.isRequired,
|
||||||
|
locationSettings: PropTypes.object.isRequired,
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
settings: PropTypes.object,
|
|
||||||
displayInline: PropTypes.bool,
|
displayInline: PropTypes.bool,
|
||||||
location: PropTypes.object,
|
|
||||||
hideName: PropTypes.bool,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default EventLog;
|
export default EventLog;
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
import { connect } from 'react-redux';
|
|
||||||
import EventLog from './EventLog';
|
|
||||||
import { updateSettingForGroup } from '../../../store/settings/actions';
|
|
||||||
|
|
||||||
const mapStateToProps = state => {
|
|
||||||
const settings = state.settings.toJS().history || {};
|
|
||||||
const location = state.settings.toJS().location || {};
|
|
||||||
return {
|
|
||||||
settings,
|
|
||||||
location,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const EventLogContainer = connect(mapStateToProps, {
|
|
||||||
updateSetting: updateSettingForGroup('history'),
|
|
||||||
})(EventLog);
|
|
||||||
|
|
||||||
export default EventLogContainer;
|
|
27
frontend/src/component/history/EventLog/index.tsx
Normal file
27
frontend/src/component/history/EventLog/index.tsx
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import EventLog from './EventLog';
|
||||||
|
import { useEventSettings } from "../../../hooks/useEventSettings";
|
||||||
|
import { useLocationSettings } from "../../../hooks/useLocationSettings";
|
||||||
|
|
||||||
|
interface IEventLogContainerProps {
|
||||||
|
title: string;
|
||||||
|
history: unknown[];
|
||||||
|
displayInline?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const EventLogContainer = (props: IEventLogContainerProps) => {
|
||||||
|
const { locationSettings } = useLocationSettings();
|
||||||
|
const { eventSettings, setEventSettings } = useEventSettings();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<EventLog
|
||||||
|
title={props.title}
|
||||||
|
history={props.history}
|
||||||
|
eventSettings={eventSettings}
|
||||||
|
setEventSettings={setEventSettings}
|
||||||
|
locationSettings={locationSettings}
|
||||||
|
displayInline={props.displayInline}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EventLogContainer;
|
@ -1,6 +1,5 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import OutsideClickHandler from 'react-outside-click-handler';
|
import OutsideClickHandler from 'react-outside-click-handler';
|
||||||
|
|
||||||
import { Avatar, Button } from '@material-ui/core';
|
import { Avatar, Button } from '@material-ui/core';
|
||||||
@ -8,17 +7,19 @@ import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown';
|
|||||||
import { useStyles } from './UserProfile.styles';
|
import { useStyles } from './UserProfile.styles';
|
||||||
import { useCommonStyles } from '../../../common.styles';
|
import { useCommonStyles } from '../../../common.styles';
|
||||||
import UserProfileContent from './UserProfileContent/UserProfileContent';
|
import UserProfileContent from './UserProfileContent/UserProfileContent';
|
||||||
import { IUser } from '../../../interfaces/user';
|
import { IUser } from "../../../interfaces/user";
|
||||||
|
import { ILocationSettings } from "../../../hooks/useLocationSettings";
|
||||||
|
|
||||||
interface IUserProfileProps {
|
interface IUserProfileProps {
|
||||||
profile: IUser;
|
profile: IUser
|
||||||
updateSettingLocation: (field: 'locale', value: string) => void;
|
locationSettings: ILocationSettings
|
||||||
|
setLocationSettings: React.Dispatch<React.SetStateAction<ILocationSettings>>
|
||||||
}
|
}
|
||||||
|
|
||||||
const UserProfile = ({
|
const UserProfile = ({
|
||||||
profile,
|
profile,
|
||||||
location,
|
locationSettings,
|
||||||
updateSettingLocation,
|
setLocationSettings,
|
||||||
}: IUserProfileProps) => {
|
}: IUserProfileProps) => {
|
||||||
const [showProfile, setShowProfile] = useState(false);
|
const [showProfile, setShowProfile] = useState(false);
|
||||||
const [currentLocale, setCurrentLocale] = useState<string>();
|
const [currentLocale, setCurrentLocale] = useState<string>();
|
||||||
@ -40,17 +41,15 @@ const UserProfile = ({
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const locale = location.locale || navigator.language;
|
|
||||||
let found = possibleLocales.find(l =>
|
let found = possibleLocales.find(l =>
|
||||||
l.toLowerCase().includes(locale.toLowerCase())
|
l.toLowerCase().includes(locationSettings.locale.toLowerCase())
|
||||||
);
|
);
|
||||||
setCurrentLocale(found);
|
setCurrentLocale(found);
|
||||||
|
|
||||||
if (!found) {
|
if (!found) {
|
||||||
setPossibleLocales(prev => [...prev, locale]);
|
setPossibleLocales(prev => [...prev, locationSettings.locale]);
|
||||||
}
|
}
|
||||||
/* eslint-disable-next-line*/
|
/* eslint-disable-next-line*/
|
||||||
}, []);
|
}, [locationSettings]);
|
||||||
|
|
||||||
const email = profile ? profile.email : '';
|
const email = profile ? profile.email : '';
|
||||||
const imageUrl = email ? profile.imageUrl : 'unknown-user.png';
|
const imageUrl = email ? profile.imageUrl : 'unknown-user.png';
|
||||||
@ -75,7 +74,7 @@ const UserProfile = ({
|
|||||||
showProfile={showProfile}
|
showProfile={showProfile}
|
||||||
imageUrl={imageUrl}
|
imageUrl={imageUrl}
|
||||||
profile={profile}
|
profile={profile}
|
||||||
updateSettingLocation={updateSettingLocation}
|
setLocationSettings={setLocationSettings}
|
||||||
possibleLocales={possibleLocales}
|
possibleLocales={possibleLocales}
|
||||||
setCurrentLocale={setCurrentLocale}
|
setCurrentLocale={setCurrentLocale}
|
||||||
currentLocale={currentLocale}
|
currentLocale={currentLocale}
|
||||||
@ -85,10 +84,4 @@ const UserProfile = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
UserProfile.propTypes = {
|
|
||||||
profile: PropTypes.object,
|
|
||||||
location: PropTypes.object,
|
|
||||||
updateSettingLocation: PropTypes.func.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default UserProfile;
|
export default UserProfile;
|
||||||
|
@ -18,25 +18,28 @@ import legacyStyles from '../../user.module.scss';
|
|||||||
import { getBasePath } from '../../../../utils/format-path';
|
import { getBasePath } from '../../../../utils/format-path';
|
||||||
import useUiConfig from '../../../../hooks/api/getters/useUiConfig/useUiConfig';
|
import useUiConfig from '../../../../hooks/api/getters/useUiConfig/useUiConfig';
|
||||||
import { IUser } from '../../../../interfaces/user';
|
import { IUser } from '../../../../interfaces/user';
|
||||||
|
import { ILocationSettings } from '../../../../hooks/useLocationSettings';
|
||||||
|
|
||||||
interface IUserProfileContentProps {
|
interface IUserProfileContentProps {
|
||||||
showProfile: boolean;
|
showProfile: boolean;
|
||||||
profile: IUser;
|
profile: IUser;
|
||||||
possibleLocales: string[];
|
possibleLocales: string[];
|
||||||
updateSettingLocation: (field: 'locale', value: string) => void;
|
|
||||||
imageUrl: string;
|
imageUrl: string;
|
||||||
currentLocale?: string;
|
currentLocale?: string;
|
||||||
setCurrentLocale: (value: string) => void;
|
setCurrentLocale: (value: string) => void;
|
||||||
|
setLocationSettings: React.Dispatch<
|
||||||
|
React.SetStateAction<ILocationSettings>
|
||||||
|
>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const UserProfileContent = ({
|
const UserProfileContent = ({
|
||||||
showProfile,
|
showProfile,
|
||||||
profile,
|
profile,
|
||||||
possibleLocales,
|
possibleLocales,
|
||||||
updateSettingLocation,
|
|
||||||
imageUrl,
|
imageUrl,
|
||||||
currentLocale,
|
currentLocale,
|
||||||
setCurrentLocale,
|
setCurrentLocale,
|
||||||
|
setLocationSettings,
|
||||||
}: IUserProfileContentProps) => {
|
}: IUserProfileContentProps) => {
|
||||||
const commonStyles = useCommonStyles();
|
const commonStyles = useCommonStyles();
|
||||||
const { uiConfig } = useUiConfig();
|
const { uiConfig } = useUiConfig();
|
||||||
@ -44,10 +47,6 @@ const UserProfileContent = ({
|
|||||||
const [editingProfile, setEditingProfile] = useState(false);
|
const [editingProfile, setEditingProfile] = useState(false);
|
||||||
const styles = useStyles();
|
const styles = useStyles();
|
||||||
|
|
||||||
const setLocale = (value: string) => {
|
|
||||||
updateSettingLocation('locale', value);
|
|
||||||
};
|
|
||||||
|
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
const profileAvatarClasses = classnames(styles.avatar, {
|
const profileAvatarClasses = classnames(styles.avatar, {
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
@ -61,9 +60,9 @@ const UserProfileContent = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const handleChange = (e: React.ChangeEvent<{ value: unknown }>) => {
|
const handleChange = (e: React.ChangeEvent<{ value: unknown }>) => {
|
||||||
const value = e.target.value as string;
|
const locale = e.target.value as string;
|
||||||
setCurrentLocale(value);
|
setCurrentLocale(locale);
|
||||||
setLocale(value);
|
setLocationSettings({ locale });
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -99,19 +98,14 @@ const UserProfileContent = ({
|
|||||||
condition={!editingProfile}
|
condition={!editingProfile}
|
||||||
show={
|
show={
|
||||||
<>
|
<>
|
||||||
<ConditionallyRender
|
<ConditionallyRender condition={!uiConfig.disablePasswordAuth} show={
|
||||||
condition={!uiConfig.disablePasswordAuth}
|
|
||||||
show={
|
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
onClick={() =>
|
onClick={() => setEditingProfile(true)}
|
||||||
setEditingProfile(true)
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
Update password
|
Update password
|
||||||
</Button>
|
</Button>
|
||||||
}
|
} />
|
||||||
/>
|
|
||||||
<div className={commonStyles.divider} />
|
<div className={commonStyles.divider} />
|
||||||
<div className={legacyStyles.showUserSettings}>
|
<div className={legacyStyles.showUserSettings}>
|
||||||
<FormControl
|
<FormControl
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
import useUser from '../../../hooks/api/getters/useUser/useUser';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import UserProfile from './UserProfile';
|
|
||||||
import { updateSettingForGroup } from '../../../store/settings/actions';
|
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
|
||||||
updateSettingLocation: updateSettingForGroup('location'),
|
|
||||||
};
|
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
|
||||||
location: state.settings ? state.settings.toJS().location : {},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default connect(
|
|
||||||
mapStateToProps,
|
|
||||||
mapDispatchToProps
|
|
||||||
)(props => {
|
|
||||||
const user = useUser();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<UserProfile
|
|
||||||
location={props.location}
|
|
||||||
updateSettingLocation={props.updateSettingLocation}
|
|
||||||
profile={user.user}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
|
18
frontend/src/component/user/UserProfile/index.tsx
Normal file
18
frontend/src/component/user/UserProfile/index.tsx
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import useUser from '../../../hooks/api/getters/useUser/useUser';
|
||||||
|
import UserProfile from './UserProfile';
|
||||||
|
import { useLocationSettings } from '../../../hooks/useLocationSettings';
|
||||||
|
|
||||||
|
const UserProfileContainer = () => {
|
||||||
|
const user = useUser();
|
||||||
|
const { locationSettings, setLocationSettings } = useLocationSettings();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<UserProfile
|
||||||
|
locationSettings={locationSettings}
|
||||||
|
setLocationSettings={setLocationSettings}
|
||||||
|
profile={user.user}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default UserProfileContainer;
|
27
frontend/src/hooks/useEventSettings.ts
Normal file
27
frontend/src/hooks/useEventSettings.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { getBasePath } from '../utils/format-path';
|
||||||
|
import { createPersistentGlobalState } from './usePersistentGlobalState';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
export interface IEventSettings {
|
||||||
|
showData: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IUseEventSettingsOutput {
|
||||||
|
eventSettings: IEventSettings;
|
||||||
|
setEventSettings: React.Dispatch<React.SetStateAction<IEventSettings>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useEventSettings = (): IUseEventSettingsOutput => {
|
||||||
|
const [eventSettings, setEventSettings] = useGlobalState();
|
||||||
|
|
||||||
|
return { eventSettings, setEventSettings };
|
||||||
|
};
|
||||||
|
|
||||||
|
const createInitialValue = (): IEventSettings => {
|
||||||
|
return { showData: false };
|
||||||
|
};
|
||||||
|
|
||||||
|
const useGlobalState = createPersistentGlobalState<IEventSettings>(
|
||||||
|
`${getBasePath()}:useEventSettings:v1`,
|
||||||
|
createInitialValue()
|
||||||
|
);
|
29
frontend/src/hooks/useLocationSettings.ts
Normal file
29
frontend/src/hooks/useLocationSettings.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { getBasePath } from '../utils/format-path';
|
||||||
|
import { createPersistentGlobalState } from './usePersistentGlobalState';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
export interface ILocationSettings {
|
||||||
|
locale: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IUseLocationSettingsOutput {
|
||||||
|
locationSettings: ILocationSettings;
|
||||||
|
setLocationSettings: React.Dispatch<
|
||||||
|
React.SetStateAction<ILocationSettings>
|
||||||
|
>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useLocationSettings = (): IUseLocationSettingsOutput => {
|
||||||
|
const [locationSettings, setLocationSettings] = useGlobalState();
|
||||||
|
|
||||||
|
return { locationSettings, setLocationSettings };
|
||||||
|
};
|
||||||
|
|
||||||
|
const createInitialValue = (): ILocationSettings => {
|
||||||
|
return { locale: navigator.language };
|
||||||
|
};
|
||||||
|
|
||||||
|
const useGlobalState = createPersistentGlobalState<ILocationSettings>(
|
||||||
|
`${getBasePath()}:useLocationSettings:v1`,
|
||||||
|
createInitialValue()
|
||||||
|
);
|
@ -7,7 +7,6 @@ import tagTypes from './tag-type';
|
|||||||
import tags from './tag';
|
import tags from './tag';
|
||||||
import strategies from './strategy';
|
import strategies from './strategy';
|
||||||
import error from './error';
|
import error from './error';
|
||||||
import settings from './settings';
|
|
||||||
import user from './user';
|
import user from './user';
|
||||||
import applications from './application';
|
import applications from './application';
|
||||||
import uiConfig from './ui-config';
|
import uiConfig from './ui-config';
|
||||||
@ -27,7 +26,6 @@ const unleashStore = combineReducers({
|
|||||||
tags,
|
tags,
|
||||||
featureTags,
|
featureTags,
|
||||||
error,
|
error,
|
||||||
settings,
|
|
||||||
user,
|
user,
|
||||||
applications,
|
applications,
|
||||||
uiConfig,
|
uiConfig,
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
export const UPDATE_SETTING = 'UPDATE_SETTING';
|
|
||||||
|
|
||||||
export const updateSetting = (group, field, value) => ({
|
|
||||||
type: UPDATE_SETTING,
|
|
||||||
group,
|
|
||||||
field,
|
|
||||||
value,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const updateSettingForGroup = group => (field, value) => updateSetting(group, field, value);
|
|
@ -1,44 +0,0 @@
|
|||||||
import { fromJS } from 'immutable';
|
|
||||||
import { UPDATE_SETTING } from './actions';
|
|
||||||
import { USER_LOGOUT, USER_LOGIN } from '../user/actions';
|
|
||||||
|
|
||||||
import { getBasePath } from '../../utils/format-path';
|
|
||||||
|
|
||||||
const localStorage = window.localStorage || {
|
|
||||||
setItem: () => {},
|
|
||||||
getItem: () => {},
|
|
||||||
};
|
|
||||||
const basePath = getBasePath();
|
|
||||||
const SETTINGS = `${basePath}:settings`;
|
|
||||||
|
|
||||||
const DEFAULT = fromJS({ location: {} });
|
|
||||||
|
|
||||||
function getInitState() {
|
|
||||||
try {
|
|
||||||
const state = JSON.parse(localStorage.getItem(SETTINGS));
|
|
||||||
return state ? DEFAULT.merge(state) : DEFAULT;
|
|
||||||
} catch (e) {
|
|
||||||
return DEFAULT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateSetting(state, action) {
|
|
||||||
const newState = state.updateIn([action.group, action.field], () => action.value);
|
|
||||||
|
|
||||||
localStorage.setItem(SETTINGS, JSON.stringify(newState.toJSON()));
|
|
||||||
return newState;
|
|
||||||
}
|
|
||||||
|
|
||||||
const settingStore = (state = getInitState(), action) => {
|
|
||||||
switch (action.type) {
|
|
||||||
case UPDATE_SETTING:
|
|
||||||
return updateSetting(state, action);
|
|
||||||
case USER_LOGOUT:
|
|
||||||
case USER_LOGIN:
|
|
||||||
return getInitState();
|
|
||||||
default:
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default settingStore;
|
|
Loading…
Reference in New Issue
Block a user