From 1364929dcdc0950bec8c7b2b4c5c3ff7e3b38b3b Mon Sep 17 00:00:00 2001 From: Lucas Amiaud Date: Fri, 18 Feb 2022 13:16:08 +0100 Subject: [PATCH 01/19] start implem log api --- templates/admin/src/components/Routes.ts | 1 + .../admin/src/components/layout/Navigation.tsx | 15 ++++++++++++++- .../admin/src/i18n/translations/Translations.ts | 2 ++ templates/admin/src/i18n/translations/en.ts | 2 ++ templates/admin/src/i18n/translations/fr.ts | 2 ++ 5 files changed, 21 insertions(+), 1 deletion(-) diff --git a/templates/admin/src/components/Routes.ts b/templates/admin/src/components/Routes.ts index 61e503ff..d5225bb0 100644 --- a/templates/admin/src/components/Routes.ts +++ b/templates/admin/src/components/Routes.ts @@ -1,5 +1,6 @@ export const HOME = '/home'; export const USERS = '/users'; +export const LOG_API = '/log-api'; export const LOGIN = '/login' export const FORGOT_PASSWORD = '/forgot-password'; diff --git a/templates/admin/src/components/layout/Navigation.tsx b/templates/admin/src/components/layout/Navigation.tsx index 7679b1eb..8d57107b 100644 --- a/templates/admin/src/components/layout/Navigation.tsx +++ b/templates/admin/src/components/layout/Navigation.tsx @@ -6,7 +6,7 @@ import MessageService from '../../i18n/messages/MessageService'; import useToggle from '../../lib/react-hook-toggle/ReactHookToggle'; import Permission from '../../services/session/Permission'; import SessionService from '../../services/session/SessionService'; -import { HOME, USERS } from '../Routes'; +import { HOME, LOG_API, USERS } from '../Routes'; import { IconType } from '../theme/IconType'; type LinkListItemProps = { @@ -143,6 +143,19 @@ export default function Navigation() { ) } + { + sessionService.hasPermission(Permission.MANAGE_SYSTEM) + && ( + + + + ) + } ); diff --git a/templates/admin/src/i18n/translations/Translations.ts b/templates/admin/src/i18n/translations/Translations.ts index faeb50ad..6b7bc906 100644 --- a/templates/admin/src/i18n/translations/Translations.ts +++ b/templates/admin/src/i18n/translations/Translations.ts @@ -33,6 +33,8 @@ export type Translations = { 'nav.home': string, 'nav.users': string, 'nav.user-list': string, + 'nav.settings': string, + 'nav.log-api': string, // home 'home.title': string, // login diff --git a/templates/admin/src/i18n/translations/en.ts b/templates/admin/src/i18n/translations/en.ts index b1d00920..683b1340 100644 --- a/templates/admin/src/i18n/translations/en.ts +++ b/templates/admin/src/i18n/translations/en.ts @@ -32,6 +32,8 @@ const enMessages: Translations = { 'nav.home': 'Home', 'nav.users': 'User management', 'nav.user-list': 'Users', + 'nav.settings': 'Paramètres', + 'nav.log-api': 'API Logs', // home 'home.title': 'Home page', 'login.title': 'Please authenticate', diff --git a/templates/admin/src/i18n/translations/fr.ts b/templates/admin/src/i18n/translations/fr.ts index 210ca381..10cb35ac 100644 --- a/templates/admin/src/i18n/translations/fr.ts +++ b/templates/admin/src/i18n/translations/fr.ts @@ -32,6 +32,8 @@ const frMessages: Translations = { 'nav.home': 'Accueil', 'nav.users': 'Gestion des utilisateurs', 'nav.user-list': 'Utilisateurs', + 'nav.settings': 'Paramètres', + 'nav.log-api': 'API Logs', // home 'home.title': 'Page d\'accueil', 'login.title': 'Se connecter', From 4c8c494630faa9688e45950a663a2bd4ad9105e2 Mon Sep 17 00:00:00 2001 From: Lucas Amiaud Date: Fri, 18 Feb 2022 14:00:46 +0100 Subject: [PATCH 02/19] start implem log api --- .../lib/plume-admin-log-api/api/LogApiApi.ts | 31 +++++++++ .../plume-admin-log-api/api/LogApiTypes.ts | 46 ++++++++++++++ .../components/LogApiList.tsx | 63 +++++++++++++++++++ .../lib/plume-admin-log-api/pages/LogApi.tsx | 36 +++++++++++ .../pages/LogApiDetails.tsx | 9 +++ .../plume-admin-log-api-module.ts | 8 +++ 6 files changed, 193 insertions(+) create mode 100644 templates/admin/src/lib/plume-admin-log-api/api/LogApiApi.ts create mode 100644 templates/admin/src/lib/plume-admin-log-api/api/LogApiTypes.ts create mode 100644 templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx create mode 100644 templates/admin/src/lib/plume-admin-log-api/pages/LogApi.tsx create mode 100644 templates/admin/src/lib/plume-admin-log-api/pages/LogApiDetails.tsx create mode 100644 templates/admin/src/lib/plume-admin-log-api/plume-admin-log-api-module.ts diff --git a/templates/admin/src/lib/plume-admin-log-api/api/LogApiApi.ts b/templates/admin/src/lib/plume-admin-log-api/api/LogApiApi.ts new file mode 100644 index 00000000..586fa1cb --- /dev/null +++ b/templates/admin/src/lib/plume-admin-log-api/api/LogApiApi.ts @@ -0,0 +1,31 @@ +import HttpMethod from '../../simple-http-request-builder/HttpMethod'; +import PlumeAdminHttpClient from '../../plume-admin-api/PlumeHttpClient'; +import { LogApiDetailsType, LogApiParams, LogApiTrimmed } from './LogApiTypes'; + +export default class LogApiApi { + constructor(private readonly httpClient: PlumeAdminHttpClient) { + } + + fetchAll(apiParam: LogApiParams) { + return this + .httpClient + .restRequest(HttpMethod.GET, '/admin/logs') + .queryParams([ + ['limit', apiParam.limit || ''], + ['method', apiParam.method || ''], + ['statusCode', apiParam.statusCode || ''], + ['apiName', apiParam.apiName || ''], + ['url', apiParam.url || ''], + ['startDate', apiParam.startDate || ''], + ['endDate', apiParam.endDate || ''] + ]) + .execute(); + } + + fetchById(idLog: string) { + return this + .httpClient + .restRequest(HttpMethod.GET, `/admin/logs/${idLog}`) + .execute(); + } +} diff --git a/templates/admin/src/lib/plume-admin-log-api/api/LogApiTypes.ts b/templates/admin/src/lib/plume-admin-log-api/api/LogApiTypes.ts new file mode 100644 index 00000000..5a0a3072 --- /dev/null +++ b/templates/admin/src/lib/plume-admin-log-api/api/LogApiTypes.ts @@ -0,0 +1,46 @@ +export type LogApiTrimmed = { + id: string, + date: string, + method: string, + api: string, + url: string, + statusCode: number, +}; + +export type LogHeader = { + id: string, + idLogApi: string, + name: string, + type: string, + value: string, +} + +export type HttpHeaders = { + headers: LogHeader[], + mimeType: string, +} + +export type LogApiDetailsType = { + id: string, + api: string, + url: string, + date: string, + method: string, + statusCode: string, + bodyRequest: string, + bodyResponse: string, + headerRequest: HttpHeaders, + headerResponse: HttpHeaders, + isCompleteTextRequest: boolean, + isCompleteTextResponse: boolean, +}; + +export type LogApiParams = { + limit?: number, + method?: string, + statusCode?: number, + apiName?: string, + url?: string, + startDate?: string, + endDate?: string, +} diff --git a/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx b/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx new file mode 100644 index 00000000..766c6108 --- /dev/null +++ b/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx @@ -0,0 +1,63 @@ +import React, { useState } from 'react'; +import { getGlobalInstance } from 'plume-ts-di'; +import { useHistory } from 'react-router-dom'; +import { LogApiTrimmed } from '../api/LogApiTypes'; +import MessageService from '../../../i18n/messages/MessageService'; +import PlumeAdminTheme from '../../plume-admin-theme/PlumeAdminTheme'; +import userFilters from '../../plume-admin-users/pages/UserFilter'; +import { FilterElementProps } from '../../plume-admin-theme/list/ListProps'; +import { AdminUserDetails } from '../../plume-admin-users/api/AdminUserTypes'; +import { handleFilterValue } from '../../plume-admin-users/utils/FilterUtils'; + +type Props = { + logApiUrl: string, +} + +function LogApiList({ logApiUrl }: Props) { + const messages = getGlobalInstance(MessageService).t(); + const theme = getGlobalInstance(PlumeAdminTheme); + const history = useHistory(); + + const [logsApi, setLogsApi] = useState(); + + return ( + <> + + + , value: string, isChecked: boolean) => { + setCurrentUserFilters(handleFilterValue(filterElement, value, isChecked, currentUserFilters)); + }} + activeFilters={currentUserFilters} + rawList={usersWithRoles?.users} + /> + + + + + { + React.Children.toArray( + userList.map((logApi: LogApiTrimmed) => ( +
{ + history.push(`${logApiUrl}/${logApi.id}`) + }} + > + {logApi.url} +
+ )) + ) + } +
+
+
+ + ); +} + +export default (LogApiList); diff --git a/templates/admin/src/lib/plume-admin-log-api/pages/LogApi.tsx b/templates/admin/src/lib/plume-admin-log-api/pages/LogApi.tsx new file mode 100644 index 00000000..1f097fd3 --- /dev/null +++ b/templates/admin/src/lib/plume-admin-log-api/pages/LogApi.tsx @@ -0,0 +1,36 @@ +import React from 'react'; +import { Route, Switch, useRouteMatch } from 'react-router-dom'; +import LogApiApi from '../api/LogApiApi'; +import LogApiDetails from './LogApiDetails'; +import LogApiList from '../components/LogApiList'; + +class LogApi { + constructor( + private readonly logApiApi: LogApiApi, + private readonly logApiDetails: LogApiDetails, + ) { + } + + render = () => { + const { path } = useRouteMatch(); + + return ( +
+ + + + + + +
+ ) + } +} + +export default (LogApi); diff --git a/templates/admin/src/lib/plume-admin-log-api/pages/LogApiDetails.tsx b/templates/admin/src/lib/plume-admin-log-api/pages/LogApiDetails.tsx new file mode 100644 index 00000000..bf49af5e --- /dev/null +++ b/templates/admin/src/lib/plume-admin-log-api/pages/LogApiDetails.tsx @@ -0,0 +1,9 @@ +import React from 'react'; + +class LogApiDetails { + render = () => { + return (<>); + } +} + +export default (LogApiDetails); diff --git a/templates/admin/src/lib/plume-admin-log-api/plume-admin-log-api-module.ts b/templates/admin/src/lib/plume-admin-log-api/plume-admin-log-api-module.ts new file mode 100644 index 00000000..405fe7cc --- /dev/null +++ b/templates/admin/src/lib/plume-admin-log-api/plume-admin-log-api-module.ts @@ -0,0 +1,8 @@ +import { Injector } from 'plume-ts-di'; +import LogApiApi from './api/LogApiApi'; +import LogApiDetails from './pages/LogApiDetails'; + +export default function installPlumeAdminLogApiModule(injector: Injector) { + injector.registerSingleton(LogApiApi); + injector.registerSingleton(LogApiDetails); +} From f7507c6d7b87eee88f2e7122b8aa005e216553d8 Mon Sep 17 00:00:00 2001 From: Lucas Amiaud Date: Fri, 18 Feb 2022 14:03:59 +0100 Subject: [PATCH 03/19] add route for log API --- templates/admin/src/components/layout/Router.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/templates/admin/src/components/layout/Router.tsx b/templates/admin/src/components/layout/Router.tsx index 3caf2b37..0e412c80 100644 --- a/templates/admin/src/components/layout/Router.tsx +++ b/templates/admin/src/components/layout/Router.tsx @@ -5,20 +5,25 @@ import { Redirect, } from 'react-router-dom'; import { getGlobalInstance } from 'plume-ts-di'; +import LogApi from '../../lib/plume-admin-log-api/pages/LogApi'; import Home from '../pages/Home'; import Users from '../../lib/plume-admin-users/pages/Users'; import PermissionRoute from '../theme/routes/PermissionRoute'; import Permission from '../../services/session/Permission'; -import { HOME, USERS } from '../Routes'; +import { HOME, LOG_API, USERS } from '../Routes'; export default function Router() { const users = getGlobalInstance(Users); + const logApi = getGlobalInstance(LogApi); return ( + + + From 2623ae98c22483cc17f2a8ea736b0a12e16896eb Mon Sep 17 00:00:00 2001 From: Lucas Amiaud Date: Fri, 18 Feb 2022 15:00:18 +0100 Subject: [PATCH 04/19] implem log API filters --- .../src/i18n/translations/Translations.ts | 5 + templates/admin/src/i18n/translations/en.ts | 5 + templates/admin/src/i18n/translations/fr.ts | 5 + templates/admin/src/index.tsx | 21 +++-- .../lib/plume-admin-log-api/api/LogApiApi.ts | 9 +- .../plume-admin-log-api/api/LogApiTypes.ts | 5 + .../components/LogApiList.tsx | 92 +++++++++++++------ .../lib/plume-admin-log-api/pages/LogApi.tsx | 5 +- .../plume-admin-log-api/pages/LogsApiSort.ts | 14 +++ .../plume-admin-log-api-module.ts | 2 + 10 files changed, 118 insertions(+), 45 deletions(-) create mode 100644 templates/admin/src/lib/plume-admin-log-api/pages/LogsApiSort.ts diff --git a/templates/admin/src/i18n/translations/Translations.ts b/templates/admin/src/i18n/translations/Translations.ts index 6b7bc906..dd8d0e51 100644 --- a/templates/admin/src/i18n/translations/Translations.ts +++ b/templates/admin/src/i18n/translations/Translations.ts @@ -70,6 +70,11 @@ export type Translations = { 'title': string, 'name': string, 'role': string, + }, + 'logs-api': { + 'title': string, + 'api_names': string, + 'status_code': string, } } // sample with pluralization diff --git a/templates/admin/src/i18n/translations/en.ts b/templates/admin/src/i18n/translations/en.ts index 683b1340..7b2cc3c3 100644 --- a/templates/admin/src/i18n/translations/en.ts +++ b/templates/admin/src/i18n/translations/en.ts @@ -68,6 +68,11 @@ const enMessages: Translations = { 'title': 'Filters', 'name': 'Name', 'role': 'Role', + }, + 'logs-api': { + 'title': 'Filters', + 'api_names': 'API Name', + 'status_code': 'Status code', } }, // sample with pluralization diff --git a/templates/admin/src/i18n/translations/fr.ts b/templates/admin/src/i18n/translations/fr.ts index 10cb35ac..71cd9851 100644 --- a/templates/admin/src/i18n/translations/fr.ts +++ b/templates/admin/src/i18n/translations/fr.ts @@ -69,6 +69,11 @@ const frMessages: Translations = { 'name': 'Nom', 'role': 'Rôle', }, + 'logs-api': { + 'title': 'Filtres', + 'api_names': 'Nom de l\'API', + 'status_code': 'Code de retour', + } }, // sample with pluralization 'clicks.count': (count: number) => `Il y a eu ${count} clic${count > 1 ? 's' : ''} !`, diff --git a/templates/admin/src/index.tsx b/templates/admin/src/index.tsx index 37b7e743..85800c01 100644 --- a/templates/admin/src/index.tsx +++ b/templates/admin/src/index.tsx @@ -1,20 +1,20 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; // eslint-disable-next-line @typescript-eslint/no-unused-vars -import { CssBaseline } from '@mui/material'; -import 'react-toastify/dist/ReactToastify.css'; import 'micro-observables/batchingForReactDom'; +import { configureGlobalInjector, Injector } from 'plume-ts-di'; +import React from 'react'; +import ReactDOM from 'react-dom'; import { BrowserRouter as Router } from 'react-router-dom'; +import 'react-toastify/dist/ReactToastify.css'; import { Logger } from 'simple-logging-system'; -import { configureGlobalInjector, Injector } from 'plume-ts-di'; -import './polyfill-loader'; -import installServicesModule from './services/services-module'; -import installComponentsModule from './components/components-module'; -import App from './components/App'; import installApiModule from './api/api-module'; -import SessionService from './services/session/SessionService'; +import App from './components/App'; +import installComponentsModule from './components/components-module'; import installI18nModule from './i18n/i18n-module'; +import installPlumeAdminLogApiModule from './lib/plume-admin-log-api/plume-admin-log-api-module'; import installPlumeAdminUsersModule from './lib/plume-admin-users/plume-admin-users-module'; +import './polyfill-loader'; +import installServicesModule from './services/services-module'; +import SessionService from './services/session/SessionService'; const currentMillis = Date.now(); const logger = new Logger('index'); @@ -25,6 +25,7 @@ installComponentsModule(injector); installApiModule(injector); installI18nModule(injector); installPlumeAdminUsersModule(injector); +installPlumeAdminLogApiModule(injector); injector.initializeSingletonInstances(); diff --git a/templates/admin/src/lib/plume-admin-log-api/api/LogApiApi.ts b/templates/admin/src/lib/plume-admin-log-api/api/LogApiApi.ts index 586fa1cb..5a842ead 100644 --- a/templates/admin/src/lib/plume-admin-log-api/api/LogApiApi.ts +++ b/templates/admin/src/lib/plume-admin-log-api/api/LogApiApi.ts @@ -1,6 +1,6 @@ import HttpMethod from '../../simple-http-request-builder/HttpMethod'; import PlumeAdminHttpClient from '../../plume-admin-api/PlumeHttpClient'; -import { LogApiDetailsType, LogApiParams, LogApiTrimmed } from './LogApiTypes'; +import { LogApiDetailsType, LogApiFilters, LogApiParams, LogApiTrimmed } from './LogApiTypes'; export default class LogApiApi { constructor(private readonly httpClient: PlumeAdminHttpClient) { @@ -28,4 +28,11 @@ export default class LogApiApi { .restRequest(HttpMethod.GET, `/admin/logs/${idLog}`) .execute(); } + + fetchLogApiFilters() { + return this + .httpClient + .restRequest(HttpMethod.GET, '/admin/logs-filters') + .execute(); + } } diff --git a/templates/admin/src/lib/plume-admin-log-api/api/LogApiTypes.ts b/templates/admin/src/lib/plume-admin-log-api/api/LogApiTypes.ts index 5a0a3072..a3a5d2c8 100644 --- a/templates/admin/src/lib/plume-admin-log-api/api/LogApiTypes.ts +++ b/templates/admin/src/lib/plume-admin-log-api/api/LogApiTypes.ts @@ -44,3 +44,8 @@ export type LogApiParams = { startDate?: string, endDate?: string, } + +export type LogApiFilters = { + apiNames: string[], + statusCodes: number[], +} diff --git a/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx b/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx index 766c6108..47969892 100644 --- a/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx +++ b/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx @@ -1,56 +1,88 @@ -import React, { useState } from 'react'; import { getGlobalInstance } from 'plume-ts-di'; +import React, { useState } from 'react'; import { useHistory } from 'react-router-dom'; -import { LogApiTrimmed } from '../api/LogApiTypes'; import MessageService from '../../../i18n/messages/MessageService'; +import { RawFilterProps } from '../../plume-admin-theme/list/ListProps'; import PlumeAdminTheme from '../../plume-admin-theme/PlumeAdminTheme'; -import userFilters from '../../plume-admin-users/pages/UserFilter'; -import { FilterElementProps } from '../../plume-admin-theme/list/ListProps'; -import { AdminUserDetails } from '../../plume-admin-users/api/AdminUserTypes'; -import { handleFilterValue } from '../../plume-admin-users/utils/FilterUtils'; +import useLoader from '../../plume-http-react-hook-loader/promiseLoaderHook'; +import { useOnComponentMounted } from '../../react-hooks-alias/ReactHooksAlias'; +import LogApiApi from '../api/LogApiApi'; +import { LogApiFilters, LogApiTrimmed } from '../api/LogApiTypes'; type Props = { - logApiUrl: string, + logApiPath: string, } -function LogApiList({ logApiUrl }: Props) { +function LogApiList({ logApiPath }: Props) { const messages = getGlobalInstance(MessageService).t(); const theme = getGlobalInstance(PlumeAdminTheme); + const logApiApi = getGlobalInstance(LogApiApi); const history = useHistory(); const [logsApi, setLogsApi] = useState(); + const logsApiLoader = useLoader(); + const fetchLogsApi = () => logsApiLoader.monitor( + logApiApi + .fetchAll({}) + .then(setLogsApi) + ); + + // filters + const [logsApiFilters, setLogsApiFilters] = useState(); + const [currentLogsApiFilters, setCurrentLogsApiFilters] = useState>(new Map()); + const logApiFiltersLoader = useLoader(); + const fetchFilters = () => logApiFiltersLoader.monitor( + logApiApi.fetchLogApiFilters() + .then(setLogsApiFilters) + ); + + const filters = (): RawFilterProps[] => { + const apiNamesFilters: RawFilterProps = { + filterKey: 'api_names', + possibleValues: logsApiFilters?.apiNames || [], + }; + const statusCodeFilters: RawFilterProps = { + filterKey: 'status_code', + possibleValues: logsApiFilters?.statusCodes.map(code => code.toString()) || [], + }; + return [apiNamesFilters, statusCodeFilters]; + } + + useOnComponentMounted(() => { + fetchLogsApi(); + fetchFilters(); + }); return ( <> - - , value: string, isChecked: boolean) => { - setCurrentUserFilters(handleFilterValue(filterElement, value, isChecked, currentUserFilters)); + + { }} - activeFilters={currentUserFilters} - rawList={usersWithRoles?.users} + selectedValues={currentLogsApiFilters} /> - - + {/* - + sortConfiguration={{}} + />*/} + { React.Children.toArray( - userList.map((logApi: LogApiTrimmed) => ( -
{ - history.push(`${logApiUrl}/${logApi.id}`) - }} - > - {logApi.url} -
- )) + logsApi?.map((logApi: LogApiTrimmed) => ( +
{ + history.push(`${logApiPath}/${logApi.id}`) + }} + > + {logApi.url} +
+ ) + ) ) }
diff --git a/templates/admin/src/lib/plume-admin-log-api/pages/LogApi.tsx b/templates/admin/src/lib/plume-admin-log-api/pages/LogApi.tsx index 1f097fd3..dda9786c 100644 --- a/templates/admin/src/lib/plume-admin-log-api/pages/LogApi.tsx +++ b/templates/admin/src/lib/plume-admin-log-api/pages/LogApi.tsx @@ -6,7 +6,6 @@ import LogApiList from '../components/LogApiList'; class LogApi { constructor( - private readonly logApiApi: LogApiApi, private readonly logApiDetails: LogApiDetails, ) { } @@ -18,11 +17,9 @@ class LogApi {
- + diff --git a/templates/admin/src/lib/plume-admin-log-api/pages/LogsApiSort.ts b/templates/admin/src/lib/plume-admin-log-api/pages/LogsApiSort.ts new file mode 100644 index 00000000..c32bdfbb --- /dev/null +++ b/templates/admin/src/lib/plume-admin-log-api/pages/LogsApiSort.ts @@ -0,0 +1,14 @@ +import dayjs from 'dayjs'; +import { SortElementProps } from '../../plume-admin-theme/list/ListProps'; +import { LogApiTrimmed } from '../api/LogApiTypes'; + +export const DATE_DESC: SortElementProps = { + sortKey: 'DATE_DESC', + sortFunction: (a: LogApiTrimmed, b: LogApiTrimmed) => { + return dayjs(a.date).diff(dayjs(b.date)); + } +} + +export default function logsApiSortsList() { + return [DATE_DESC]; +} diff --git a/templates/admin/src/lib/plume-admin-log-api/plume-admin-log-api-module.ts b/templates/admin/src/lib/plume-admin-log-api/plume-admin-log-api-module.ts index 405fe7cc..e1823bea 100644 --- a/templates/admin/src/lib/plume-admin-log-api/plume-admin-log-api-module.ts +++ b/templates/admin/src/lib/plume-admin-log-api/plume-admin-log-api-module.ts @@ -1,8 +1,10 @@ import { Injector } from 'plume-ts-di'; import LogApiApi from './api/LogApiApi'; +import LogApi from './pages/LogApi'; import LogApiDetails from './pages/LogApiDetails'; export default function installPlumeAdminLogApiModule(injector: Injector) { + injector.registerSingleton(LogApi); injector.registerSingleton(LogApiApi); injector.registerSingleton(LogApiDetails); } From 8d96127f2d1dec7a3b9372a43d6b52ab67588dd4 Mon Sep 17 00:00:00 2001 From: Lucas Amiaud Date: Fri, 18 Feb 2022 15:24:18 +0100 Subject: [PATCH 05/19] add log api sorting --- .../src/i18n/translations/Translations.ts | 4 +++ templates/admin/src/i18n/translations/en.ts | 4 +++ templates/admin/src/i18n/translations/fr.ts | 4 +++ .../components/LogApiList.tsx | 25 +++++++++++++++---- .../plume-admin-log-api/pages/LogsApiSort.ts | 9 ++++++- 5 files changed, 40 insertions(+), 6 deletions(-) diff --git a/templates/admin/src/i18n/translations/Translations.ts b/templates/admin/src/i18n/translations/Translations.ts index dd8d0e51..2323eee2 100644 --- a/templates/admin/src/i18n/translations/Translations.ts +++ b/templates/admin/src/i18n/translations/Translations.ts @@ -63,6 +63,10 @@ export type Translations = { 'name_desc': string, 'name_asc': string, }, + 'logs-api': { + 'date_desc': string, + 'date_asc': string, + }, } // filters wording 'filter': { diff --git a/templates/admin/src/i18n/translations/en.ts b/templates/admin/src/i18n/translations/en.ts index 7b2cc3c3..7f40be50 100644 --- a/templates/admin/src/i18n/translations/en.ts +++ b/templates/admin/src/i18n/translations/en.ts @@ -61,6 +61,10 @@ const enMessages: Translations = { 'name_desc': 'Sort by descendant alphabetical order', 'name_asc': 'Sort by ascendant alphabetical order', }, + 'logs-api': { + 'date_desc': 'Sort newest to oldest', + 'date_asc': 'Sort oldest to newest', + }, }, // filters wording 'filter': { diff --git a/templates/admin/src/i18n/translations/fr.ts b/templates/admin/src/i18n/translations/fr.ts index 71cd9851..62eafa8f 100644 --- a/templates/admin/src/i18n/translations/fr.ts +++ b/templates/admin/src/i18n/translations/fr.ts @@ -61,6 +61,10 @@ const frMessages: Translations = { 'name_desc': 'Trier par ordre alphabétique descendant', 'name_asc': 'Trier par ordre alphabétique ascendant', }, + 'logs-api': { + 'date_desc': 'Trier du plus nouveau au plus ancien', + 'date_asc': 'Trier du plus ancien au plus nouveau', + }, }, // filters wording 'filter': { diff --git a/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx b/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx index 47969892..2cdb0868 100644 --- a/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx +++ b/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx @@ -2,12 +2,13 @@ import { getGlobalInstance } from 'plume-ts-di'; import React, { useState } from 'react'; import { useHistory } from 'react-router-dom'; import MessageService from '../../../i18n/messages/MessageService'; -import { RawFilterProps } from '../../plume-admin-theme/list/ListProps'; +import { RawFilterProps, SortElementProps } from '../../plume-admin-theme/list/ListProps'; import PlumeAdminTheme from '../../plume-admin-theme/PlumeAdminTheme'; import useLoader from '../../plume-http-react-hook-loader/promiseLoaderHook'; import { useOnComponentMounted } from '../../react-hooks-alias/ReactHooksAlias'; import LogApiApi from '../api/LogApiApi'; import { LogApiFilters, LogApiTrimmed } from '../api/LogApiTypes'; +import logsApiSortsList, { DATE_DESC } from '../pages/LogsApiSort'; type Props = { logApiPath: string, @@ -27,6 +28,9 @@ function LogApiList({ logApiPath }: Props) { .then(setLogsApi) ); + // sorting + const [currentLogsApiSorting, setCurrentLogsApiSorting] = useState(DATE_DESC); + // filters const [logsApiFilters, setLogsApiFilters] = useState(); const [currentLogsApiFilters, setCurrentLogsApiFilters] = useState>(new Map()); @@ -53,6 +57,10 @@ function LogApiList({ logApiPath }: Props) { fetchFilters(); }); + const sortedList = () => { + return logsApi?.sort(currentLogsApiSorting.sortFunction) || []; + } + return ( <> @@ -66,14 +74,21 @@ function LogApiList({ logApiPath }: Props) { /> - {/**/} + sortConfiguration={{ + sortedObjectKey: 'logs-api', + sortPossibilities: logsApiSortsList(), + defaultSortPossibility: DATE_DESC, + onSort: (sortElement: SortElementProps) => { + setCurrentLogsApiSorting(sortElement); + }, + }} + /> { React.Children.toArray( - logsApi?.map((logApi: LogApiTrimmed) => ( + sortedList().map((logApi: LogApiTrimmed) => (
{ history.push(`${logApiPath}/${logApi.id}`) diff --git a/templates/admin/src/lib/plume-admin-log-api/pages/LogsApiSort.ts b/templates/admin/src/lib/plume-admin-log-api/pages/LogsApiSort.ts index c32bdfbb..b381f104 100644 --- a/templates/admin/src/lib/plume-admin-log-api/pages/LogsApiSort.ts +++ b/templates/admin/src/lib/plume-admin-log-api/pages/LogsApiSort.ts @@ -9,6 +9,13 @@ export const DATE_DESC: SortElementProps = { } } +export const DATE_ASC: SortElementProps = { + sortKey: 'DATE_ASC', + sortFunction: (a: LogApiTrimmed, b: LogApiTrimmed) => { + return dayjs(b.date).diff(dayjs(a.date)); + } +} + export default function logsApiSortsList() { - return [DATE_DESC]; + return [DATE_DESC, DATE_ASC]; } From b22f0aac7344531a59a9cdd6c42679797cf5474c Mon Sep 17 00:00:00 2001 From: Lucas Amiaud Date: Mon, 21 Feb 2022 18:38:24 +0100 Subject: [PATCH 06/19] add log api js filter --- .../components/LogApiList.tsx | 40 +++++++++---------- .../lib/plume-admin-log-api/pages/LogApi.tsx | 3 +- .../pages/LogApiDetails.tsx | 9 +++++ 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx b/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx index 2cdb0868..fa6b3c34 100644 --- a/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx +++ b/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx @@ -2,8 +2,9 @@ import { getGlobalInstance } from 'plume-ts-di'; import React, { useState } from 'react'; import { useHistory } from 'react-router-dom'; import MessageService from '../../../i18n/messages/MessageService'; -import { RawFilterProps, SortElementProps } from '../../plume-admin-theme/list/ListProps'; +import { SortElementProps } from '../../plume-admin-theme/list/ListProps'; import PlumeAdminTheme from '../../plume-admin-theme/PlumeAdminTheme'; +import { compare } from '../../plume-admin-users/utils/FilterUtils'; import useLoader from '../../plume-http-react-hook-loader/promiseLoaderHook'; import { useOnComponentMounted } from '../../react-hooks-alias/ReactHooksAlias'; import LogApiApi from '../api/LogApiApi'; @@ -28,51 +29,48 @@ function LogApiList({ logApiPath }: Props) { .then(setLogsApi) ); + // search bar + const [currentSearchBarFilter, setCurrentSearchBarFilter] = useState(); + // sorting const [currentLogsApiSorting, setCurrentLogsApiSorting] = useState(DATE_DESC); // filters const [logsApiFilters, setLogsApiFilters] = useState(); - const [currentLogsApiFilters, setCurrentLogsApiFilters] = useState>(new Map()); const logApiFiltersLoader = useLoader(); const fetchFilters = () => logApiFiltersLoader.monitor( logApiApi.fetchLogApiFilters() .then(setLogsApiFilters) ); - const filters = (): RawFilterProps[] => { - const apiNamesFilters: RawFilterProps = { - filterKey: 'api_names', - possibleValues: logsApiFilters?.apiNames || [], - }; - const statusCodeFilters: RawFilterProps = { - filterKey: 'status_code', - possibleValues: logsApiFilters?.statusCodes.map(code => code.toString()) || [], - }; - return [apiNamesFilters, statusCodeFilters]; - } - useOnComponentMounted(() => { fetchLogsApi(); fetchFilters(); }); + const applySearchBarFilter = (logApi: LogApiTrimmed) => { + if (!currentSearchBarFilter || currentSearchBarFilter === '') { + return true; + } + return compare(logApi.url, currentSearchBarFilter); + } + const sortedList = () => { - return logsApi?.sort(currentLogsApiSorting.sortFunction) || []; + return logsApi?.sort(currentLogsApiSorting.sortFunction).filter(applySearchBarFilter) || []; } return ( <> - - { + + ) => { + setCurrentSearchBarFilter(event.target.value); }} - selectedValues={currentLogsApiFilters} /> + + { return (<>); } From 467076b68bf85eb239517ef2ecb8b873cd2117d5 Mon Sep 17 00:00:00 2001 From: Lucas Amiaud Date: Wed, 13 Apr 2022 12:21:30 +0200 Subject: [PATCH 07/19] add message and titles --- templates/admin/src/i18n/translations/Translations.ts | 4 ++++ templates/admin/src/i18n/translations/en.ts | 4 ++++ templates/admin/src/i18n/translations/fr.ts | 4 ++++ .../src/lib/plume-admin-log-api/components/LogApiList.tsx | 1 + .../admin/src/lib/plume-admin-log-api/pages/LogApi.tsx | 8 +++++++- 5 files changed, 20 insertions(+), 1 deletion(-) diff --git a/templates/admin/src/i18n/translations/Translations.ts b/templates/admin/src/i18n/translations/Translations.ts index 95189c18..ea8c3c31 100644 --- a/templates/admin/src/i18n/translations/Translations.ts +++ b/templates/admin/src/i18n/translations/Translations.ts @@ -84,6 +84,10 @@ export type Translations = { count: (count: number) => string, }, }, + // logs api + logs_api: { + title_list: string, + }, // sorts wording 'sort': { 'user': { diff --git a/templates/admin/src/i18n/translations/en.ts b/templates/admin/src/i18n/translations/en.ts index b70f1d8e..35ccc916 100644 --- a/templates/admin/src/i18n/translations/en.ts +++ b/templates/admin/src/i18n/translations/en.ts @@ -83,6 +83,10 @@ const enMessages: Translations = { cancel: 'Cancel entry', } }, + // logs api + logs_api: { + title_list: 'API calls List', + }, // sorts wording 'sort': { 'user': { diff --git a/templates/admin/src/i18n/translations/fr.ts b/templates/admin/src/i18n/translations/fr.ts index ab7403d3..bf6fca57 100644 --- a/templates/admin/src/i18n/translations/fr.ts +++ b/templates/admin/src/i18n/translations/fr.ts @@ -83,6 +83,10 @@ const frMessages: Translations = { count: (count: number) => 'Nombre d\'utilisateurs : ' + count, }, }, + // logs api + logs_api: { + title_list: 'Liste des appels API', + }, // sorts wording 'sort': { 'user': { diff --git a/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx b/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx index ad611191..66e9ca61 100644 --- a/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx +++ b/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx @@ -61,6 +61,7 @@ function LogApiList({ logApiPath }: Props) { return ( <> + {messages.logs_api.title_list} { From 4b02b099c580e819b6fc31f0b03e270623ed43bf Mon Sep 17 00:00:00 2001 From: Lucas Amiaud Date: Wed, 20 Apr 2022 10:34:11 +0200 Subject: [PATCH 08/19] merge new libraries --- templates/admin/src/lib/plume-admin-log-api/api/LogApiApi.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/admin/src/lib/plume-admin-log-api/api/LogApiApi.ts b/templates/admin/src/lib/plume-admin-log-api/api/LogApiApi.ts index 5a842ead..6d251cb2 100644 --- a/templates/admin/src/lib/plume-admin-log-api/api/LogApiApi.ts +++ b/templates/admin/src/lib/plume-admin-log-api/api/LogApiApi.ts @@ -1,4 +1,4 @@ -import HttpMethod from '../../simple-http-request-builder/HttpMethod'; +import { HttpMethod } from 'simple-http-request-builder'; import PlumeAdminHttpClient from '../../plume-admin-api/PlumeHttpClient'; import { LogApiDetailsType, LogApiFilters, LogApiParams, LogApiTrimmed } from './LogApiTypes'; From 454faad55ca8c2d54218cf14b1ed13528a179315 Mon Sep 17 00:00:00 2001 From: Lucas Amiaud Date: Wed, 27 Apr 2022 13:23:52 +0200 Subject: [PATCH 09/19] wip add radio buttons --- .../theme/list/SingleChoiceFilterMenu.tsx | 105 ++++++++++++++++++ .../src/i18n/translations/Translations.ts | 5 + templates/admin/src/i18n/translations/en.ts | 5 + templates/admin/src/i18n/translations/fr.ts | 5 + .../plume-admin-log-api/api/LogApiTypes.ts | 2 +- .../components/LogApiList.tsx | 51 ++++++++- 6 files changed, 167 insertions(+), 6 deletions(-) create mode 100644 templates/admin/src/components/theme/list/SingleChoiceFilterMenu.tsx diff --git a/templates/admin/src/components/theme/list/SingleChoiceFilterMenu.tsx b/templates/admin/src/components/theme/list/SingleChoiceFilterMenu.tsx new file mode 100644 index 00000000..b015e207 --- /dev/null +++ b/templates/admin/src/components/theme/list/SingleChoiceFilterMenu.tsx @@ -0,0 +1,105 @@ +import { FormControlLabel, Radio, RadioGroup } from '@mui/material'; +import { getGlobalInstance } from 'plume-ts-di'; +import React from 'react'; +import MessageService from '../../../i18n/messages/MessageService'; +import { + ListObjectFiltersProps, + ObjectFilterProps, + RawFilterProps +} from '../../../lib/plume-admin-theme/list/ListProps'; + +/** + * ListObjectFilters generates filters for a give object type + * @param filterMenuKey the key in translation file to be used + * @param onFilterValueClicked function executed when a checkbox is clicked + * @param filters The filters for the given type. + * Each filter must contain a key extractor of the given object + * Each filter must contain a key filter for identification + * @param rawList the whole given type list to be filtered + * @param selectedValue the map of the current selected value by the key filter + * @constructor + */ +export function ObjectSingleChoiceFilterMenu( + { + filterMenuKey, + onFilterValueClicked, + filters, + rawList, + selectedValues + }: ListObjectFiltersProps +) { + return ( + ) => ({ + filterKey: o.filterKey, + possibleValues: rawList.map(o.keyExtractor), + })) + } + selectedValues={selectedValues} + /> + ) +} + +/** + * ListFilters is a generic component for filtering in a list + * @param filterMenuKey the key in translation file to be used + * @param filters The filters to be displayed. + * Each filter must contain possible values + * Each filter must contain a key filter for identification + * @param onFilterValueClicked function executed when a checkbox is clicked + * @param selectedValue the map of the current selected value by the key filter + * @constructor + */ +export function SingleChoiceFilterMenu( + { filterMenuKey, filters, onFilterValueClicked, selectedValues }: + { + filters: RawFilterProps[], + filterMenuKey: string, + onFilterValueClicked: (filterKey: string, valueSelected: string) => void, + selectedValues: Map + } +) { + const messages = getGlobalInstance(MessageService).t(); + + return ( +
+

{(messages['filter'] as any)[filterMenuKey]['title']}

+
+ { + filters.map((filterPossibility) => ( +
+ + {(messages['filter'] as any)[filterMenuKey][filterPossibility.filterKey]} + + ) => { + onFilterValueClicked(filterPossibility.filterKey, e.target.value); + }} + value={selectedValues.get(filterPossibility.filterKey)} + > + { + Array.from(new Set([...filterPossibility.possibleValues])) + .map((value: string) => ( + + )} + /> + ) + ) + } + +
+ )) + } +
+
+ ) +} \ No newline at end of file diff --git a/templates/admin/src/i18n/translations/Translations.ts b/templates/admin/src/i18n/translations/Translations.ts index ea8c3c31..52930149 100644 --- a/templates/admin/src/i18n/translations/Translations.ts +++ b/templates/admin/src/i18n/translations/Translations.ts @@ -106,6 +106,11 @@ export type Translations = { 'name': string, 'role': string, }, + logs_api: { + api_name: string, + status_code: string, + method: string, + } } // errors error: { diff --git a/templates/admin/src/i18n/translations/en.ts b/templates/admin/src/i18n/translations/en.ts index 35ccc916..236f915d 100644 --- a/templates/admin/src/i18n/translations/en.ts +++ b/templates/admin/src/i18n/translations/en.ts @@ -105,6 +105,11 @@ const enMessages: Translations = { 'name': 'Name', 'role': 'Role', }, + logs_api: { + api_name: 'API Name', + status_code: 'Status code', + method: 'HTTP Method', + }, }, // errors error: { diff --git a/templates/admin/src/i18n/translations/fr.ts b/templates/admin/src/i18n/translations/fr.ts index bf6fca57..bb25ff4a 100644 --- a/templates/admin/src/i18n/translations/fr.ts +++ b/templates/admin/src/i18n/translations/fr.ts @@ -105,6 +105,11 @@ const frMessages: Translations = { 'name': 'Nom', 'role': 'Rôle', }, + logs_api: { + api_name: 'Nom d\'API', + status_code: 'Code de retour', + method: 'Méthode HTTP', + }, }, // errors error: { diff --git a/templates/admin/src/lib/plume-admin-log-api/api/LogApiTypes.ts b/templates/admin/src/lib/plume-admin-log-api/api/LogApiTypes.ts index a3a5d2c8..7494767a 100644 --- a/templates/admin/src/lib/plume-admin-log-api/api/LogApiTypes.ts +++ b/templates/admin/src/lib/plume-admin-log-api/api/LogApiTypes.ts @@ -38,7 +38,7 @@ export type LogApiDetailsType = { export type LogApiParams = { limit?: number, method?: string, - statusCode?: number, + statusCode?: string, apiName?: string, url?: string, startDate?: string, diff --git a/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx b/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx index 66e9ca61..0816a6dc 100644 --- a/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx +++ b/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx @@ -1,14 +1,16 @@ import { getGlobalInstance } from 'plume-ts-di'; import React, { useState } from 'react'; import { useHistory } from 'react-router-dom'; +import ListSingleChoiceFilters from '../../../components/theme/list/ListSingleChoiceFilters'; import MessageService from '../../../i18n/messages/MessageService'; import { SortElementProps } from '../../plume-admin-theme/list/ListProps'; import PlumeAdminTheme from '../../plume-admin-theme/PlumeAdminTheme'; -import { rawIncludes } from '../../../components/theme/utils/FilterUtils'; +import { checkValueForFilter, rawIncludes } from '../../../components/theme/utils/FilterUtils'; +import userFilters from '../../plume-admin-users/pages/UserFilter'; import useLoader from '../../plume-http-react-hook-loader/promiseLoaderHook'; import { useOnComponentMounted } from '../../react-hooks-alias/ReactHooksAlias'; import LogApiApi from '../api/LogApiApi'; -import { LogApiFilters, LogApiTrimmed } from '../api/LogApiTypes'; +import { LogApiFilters, LogApiParams, LogApiTrimmed } from '../api/LogApiTypes'; import logsApiSortsList, { DATE_DESC } from '../pages/LogsApiSort'; type Props = { @@ -23,9 +25,9 @@ function LogApiList({ logApiPath }: Props) { const [logsApi, setLogsApi] = useState(); const logsApiLoader = useLoader(); - const fetchLogsApi = () => logsApiLoader.monitor( + const fetchLogsApi = (apiParam: LogApiParams) => logsApiLoader.monitor( logApiApi - .fetchAll({}) + .fetchAll(apiParam) .then(setLogsApi) ); @@ -36,6 +38,7 @@ function LogApiList({ logApiPath }: Props) { const [currentLogsApiSorting, setCurrentLogsApiSorting] = useState(DATE_DESC); // filters + const [selectedLogsApiFilters, setSelectedLogsApiFilters] = useState>(new Map()); const [logsApiFilters, setLogsApiFilters] = useState(); const logApiFiltersLoader = useLoader(); const fetchFilters = () => logApiFiltersLoader.monitor( @@ -44,7 +47,7 @@ function LogApiList({ logApiPath }: Props) { ); useOnComponentMounted(() => { - fetchLogsApi(); + fetchLogsApi({}); fetchFilters(); }); @@ -55,6 +58,15 @@ function LogApiList({ logApiPath }: Props) { return rawIncludes(logApi.url, currentSearchBarFilter); } + const applyCheckboxesFilters = (newFilters: Map) => { + setSelectedLogsApiFilters(newFilters); + fetchLogsApi({ + method: selectedLogsApiFilters.get('method'), + statusCode: selectedLogsApiFilters.get('status_code'), + apiName: selectedLogsApiFilters.get('api_name'), + }); + } + const sortedList = () => { return logsApi?.sort(currentLogsApiSorting.sortFunction).filter(applySearchBarFilter) || []; } @@ -72,6 +84,35 @@ function LogApiList({ logApiPath }: Props) {
+ + status.toString()) ?? [] + }, + { + filterKey: 'method', + possibleValues: [ + 'GET', + 'POST', + 'PUT' + ] + } + ]} + onFilterValueClicked={(filterElementKey: string, valueSelected: string) => { + const clone: Map = selectedLogsApiFilters; + clone.set(filterElementKey, valueSelected); + applyCheckboxesFilters(clone); + }} + selectedValues={selectedLogsApiFilters} + /> + Date: Wed, 27 Apr 2022 15:56:21 +0200 Subject: [PATCH 10/19] clean single choice filter menu --- .../admin/src/components/theme/AdminTheme.ts | 7 ++- .../{ => filter}/SingleChoiceFilterMenu.tsx | 34 +++++------- .../src/components/theme/utils/FilterUtils.ts | 19 +++++++ .../components/LogApiList.tsx | 55 +++++++++---------- .../plume-admin-log-api/pages/LogsApiSort.ts | 2 +- .../lib/plume-admin-theme/PlumeAdminTheme.ts | 6 ++ .../list/filter/FilterProps.ts | 14 +++++ 7 files changed, 86 insertions(+), 51 deletions(-) rename templates/admin/src/components/theme/list/{ => filter}/SingleChoiceFilterMenu.tsx (80%) diff --git a/templates/admin/src/components/theme/AdminTheme.ts b/templates/admin/src/components/theme/AdminTheme.ts index 40f2e2ae..52352b83 100644 --- a/templates/admin/src/components/theme/AdminTheme.ts +++ b/templates/admin/src/components/theme/AdminTheme.ts @@ -9,8 +9,9 @@ import { PageBloc, PageBlocColumn } from './layout/PageBloc'; import PageTitle from './layout/PageTitle'; import { Panel, PanelSeparator } from './layout/Panel'; import StatusDot from './layout/StatusDot'; -import { ListElements, ListSingleElement } from './list/ListElements'; import MultipleChoiceFilterMenu, { MultipleChoiceObjectFilterMenu } from './list/filter/MultipleChoiceFilterMenu'; +import SingleChoiceFilterMenu, { SingleObjectChoiceFilterMenu, } from './list/filter/SingleChoiceFilterMenu'; +import { ListElements, ListSingleElement } from './list/ListElements'; import ListHeader from './list/ListHeader'; import SearchBar from './list/search/SearchBar'; import SortMenu from './list/sort/SortMenu'; @@ -41,6 +42,10 @@ export default class AdminTheme implements PlumeAdminTheme { multipleChoiceObjectFilterMenu = MultipleChoiceObjectFilterMenu; + singleChoiceFilterMenu = SingleChoiceFilterMenu; + + singleChoiceObjectFilterMenu = SingleObjectChoiceFilterMenu; + listHeader = ListHeader; listElements = ListElements; diff --git a/templates/admin/src/components/theme/list/SingleChoiceFilterMenu.tsx b/templates/admin/src/components/theme/list/filter/SingleChoiceFilterMenu.tsx similarity index 80% rename from templates/admin/src/components/theme/list/SingleChoiceFilterMenu.tsx rename to templates/admin/src/components/theme/list/filter/SingleChoiceFilterMenu.tsx index b015e207..84bde2f4 100644 --- a/templates/admin/src/components/theme/list/SingleChoiceFilterMenu.tsx +++ b/templates/admin/src/components/theme/list/filter/SingleChoiceFilterMenu.tsx @@ -1,15 +1,15 @@ import { FormControlLabel, Radio, RadioGroup } from '@mui/material'; import { getGlobalInstance } from 'plume-ts-di'; import React from 'react'; -import MessageService from '../../../i18n/messages/MessageService'; +import MessageService from '../../../../i18n/messages/MessageService'; import { - ListObjectFiltersProps, ObjectFilterProps, - RawFilterProps -} from '../../../lib/plume-admin-theme/list/ListProps'; + SingleChoiceObjectFilterMenuProps, + SingleChoiceRawFilterMenuProps +} from '../../../../lib/plume-admin-theme/list/filter/FilterProps'; /** - * ListObjectFilters generates filters for a give object type + * SingleObjectChoiceFilterMenu generates a single choice filter menu for a give object type * @param filterMenuKey the key in translation file to be used * @param onFilterValueClicked function executed when a checkbox is clicked * @param filters The filters for the given type. @@ -19,14 +19,14 @@ import { * @param selectedValue the map of the current selected value by the key filter * @constructor */ -export function ObjectSingleChoiceFilterMenu( +export function SingleObjectChoiceFilterMenu( { filterMenuKey, onFilterValueClicked, filters, rawList, selectedValues - }: ListObjectFiltersProps + }: SingleChoiceObjectFilterMenuProps ) { return ( ( } /** - * ListFilters is a generic component for filtering in a list + * SingleChoiceFilterMenu is a generic component for filtering in a list * @param filterMenuKey the key in translation file to be used * @param filters The filters to be displayed. * Each filter must contain possible values * Each filter must contain a key filter for identification - * @param onFilterValueClicked function executed when a checkbox is clicked + * @param onFilterValueClicked function executed when a radio button is clicked * @param selectedValue the map of the current selected value by the key filter * @constructor */ -export function SingleChoiceFilterMenu( - { filterMenuKey, filters, onFilterValueClicked, selectedValues }: - { - filters: RawFilterProps[], - filterMenuKey: string, - onFilterValueClicked: (filterKey: string, valueSelected: string) => void, - selectedValues: Map - } +function SingleChoiceFilterMenu( + { filterMenuKey, filters, onFilterValueClicked, selectedValues }: SingleChoiceRawFilterMenuProps ) { const messages = getGlobalInstance(MessageService).t(); @@ -79,7 +73,7 @@ export function SingleChoiceFilterMenu( onChange={(e: React.ChangeEvent) => { onFilterValueClicked(filterPossibility.filterKey, e.target.value); }} - value={selectedValues.get(filterPossibility.filterKey)} + value={selectedValues.get(filterPossibility.filterKey) || ''} > { Array.from(new Set([...filterPossibility.possibleValues])) @@ -102,4 +96,6 @@ export function SingleChoiceFilterMenu(
) -} \ No newline at end of file +} + +export default (SingleChoiceFilterMenu); \ No newline at end of file diff --git a/templates/admin/src/components/theme/utils/FilterUtils.ts b/templates/admin/src/components/theme/utils/FilterUtils.ts index 11a46bf2..f9f537d4 100644 --- a/templates/admin/src/components/theme/utils/FilterUtils.ts +++ b/templates/admin/src/components/theme/utils/FilterUtils.ts @@ -30,6 +30,25 @@ export function checkValueForFilter( return currentFiltersClone; } +/** + * This method returns the allFilters state after adding a value for a filterElementKey + * @param filterElementKey + * @param valueSelected + * @param allFilters + */ +export function replaceValueForFilter( + filterElementKey: string, + valueSelected: string, + allFilters: Map, +): Map { + if (allFilters.get(filterElementKey) === valueSelected) { + return allFilters; + } + const clone: Map = new Map(allFilters); + clone.set(filterElementKey, valueSelected); + return clone; +} + /** * This methods checks if a filter has selected values to filter * @param currentFilters: the filters state diff --git a/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx b/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx index 0816a6dc..35747fab 100644 --- a/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx +++ b/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx @@ -1,16 +1,14 @@ import { getGlobalInstance } from 'plume-ts-di'; -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { useHistory } from 'react-router-dom'; -import ListSingleChoiceFilters from '../../../components/theme/list/ListSingleChoiceFilters'; +import { replaceValueForFilter } from '../../../components/theme/utils/FilterUtils'; import MessageService from '../../../i18n/messages/MessageService'; -import { SortElementProps } from '../../plume-admin-theme/list/ListProps'; +import { SortElementProps } from '../../plume-admin-theme/list/sort/SortProps'; import PlumeAdminTheme from '../../plume-admin-theme/PlumeAdminTheme'; -import { checkValueForFilter, rawIncludes } from '../../../components/theme/utils/FilterUtils'; -import userFilters from '../../plume-admin-users/pages/UserFilter'; import useLoader from '../../plume-http-react-hook-loader/promiseLoaderHook'; import { useOnComponentMounted } from '../../react-hooks-alias/ReactHooksAlias'; import LogApiApi from '../api/LogApiApi'; -import { LogApiFilters, LogApiParams, LogApiTrimmed } from '../api/LogApiTypes'; +import { LogApiFilters, LogApiTrimmed } from '../api/LogApiTypes'; import logsApiSortsList, { DATE_DESC } from '../pages/LogsApiSort'; type Props = { @@ -25,9 +23,14 @@ function LogApiList({ logApiPath }: Props) { const [logsApi, setLogsApi] = useState(); const logsApiLoader = useLoader(); - const fetchLogsApi = (apiParam: LogApiParams) => logsApiLoader.monitor( + const fetchLogsApi = () => logsApiLoader.monitor( logApiApi - .fetchAll(apiParam) + .fetchAll({ + method: selectedLogsApiFilters.get('method'), + statusCode: selectedLogsApiFilters.get('status_code'), + apiName: selectedLogsApiFilters.get('api_name'), + url: currentSearchBarFilter, + }) .then(setLogsApi) ); @@ -47,28 +50,20 @@ function LogApiList({ logApiPath }: Props) { ); useOnComponentMounted(() => { - fetchLogsApi({}); + fetchLogsApi(); fetchFilters(); }); - const applySearchBarFilter = (logApi: LogApiTrimmed) => { - if (!currentSearchBarFilter || currentSearchBarFilter === '') { - return true; - } - return rawIncludes(logApi.url, currentSearchBarFilter); - } + useEffect(() => { + fetchLogsApi(); + }, [selectedLogsApiFilters, currentSearchBarFilter]); - const applyCheckboxesFilters = (newFilters: Map) => { - setSelectedLogsApiFilters(newFilters); - fetchLogsApi({ - method: selectedLogsApiFilters.get('method'), - statusCode: selectedLogsApiFilters.get('status_code'), - apiName: selectedLogsApiFilters.get('api_name'), - }); + const applySearchBarFilter = (searchedText: string) => { + setCurrentSearchBarFilter(searchedText); } const sortedList = () => { - return logsApi?.sort(currentLogsApiSorting.sortFunction).filter(applySearchBarFilter) || []; + return logsApi?.sort(currentLogsApiSorting.sortFunction) || []; } return ( @@ -76,16 +71,16 @@ function LogApiList({ logApiPath }: Props) { {messages.logs_api.title_list} - ) => { - setCurrentSearchBarFilter(event.target.value); + applySearchBarFilter(event.target.value); }} /> - { - const clone: Map = selectedLogsApiFilters; - clone.set(filterElementKey, valueSelected); - applyCheckboxesFilters(clone); + setSelectedLogsApiFilters(replaceValueForFilter(filterElementKey, valueSelected, selectedLogsApiFilters)); }} selectedValues={selectedLogsApiFilters} /> diff --git a/templates/admin/src/lib/plume-admin-log-api/pages/LogsApiSort.ts b/templates/admin/src/lib/plume-admin-log-api/pages/LogsApiSort.ts index b381f104..4fc809de 100644 --- a/templates/admin/src/lib/plume-admin-log-api/pages/LogsApiSort.ts +++ b/templates/admin/src/lib/plume-admin-log-api/pages/LogsApiSort.ts @@ -1,5 +1,5 @@ import dayjs from 'dayjs'; -import { SortElementProps } from '../../plume-admin-theme/list/ListProps'; +import { SortElementProps } from '../../plume-admin-theme/list/sort/SortProps'; import { LogApiTrimmed } from '../api/LogApiTypes'; export const DATE_DESC: SortElementProps = { diff --git a/templates/admin/src/lib/plume-admin-theme/PlumeAdminTheme.ts b/templates/admin/src/lib/plume-admin-theme/PlumeAdminTheme.ts index 29a98a85..3c45b616 100644 --- a/templates/admin/src/lib/plume-admin-theme/PlumeAdminTheme.ts +++ b/templates/admin/src/lib/plume-admin-theme/PlumeAdminTheme.ts @@ -12,6 +12,8 @@ import { import { MultipleChoiceObjectFilterMenuProps, MultipleChoiceRawFilterMenuProps, + SingleChoiceObjectFilterMenuProps, + SingleChoiceRawFilterMenuProps, } from './list/filter/FilterProps'; import { ListElementsProps, @@ -42,6 +44,10 @@ export default abstract class PlumeAdminTheme { abstract multipleChoiceObjectFilterMenu: (props: MultipleChoiceObjectFilterMenuProps) => JSX.Element; + abstract singleChoiceFilterMenu: (props: SingleChoiceRawFilterMenuProps) => JSX.Element; + + abstract singleChoiceObjectFilterMenu: (props: SingleChoiceObjectFilterMenuProps) => JSX.Element; + abstract listHeader: (props: ListHeaderProps) => JSX.Element; abstract listElements: (props: ListElementsProps) => JSX.Element; diff --git a/templates/admin/src/lib/plume-admin-theme/list/filter/FilterProps.ts b/templates/admin/src/lib/plume-admin-theme/list/filter/FilterProps.ts index f2ccbecd..6f9b9ca4 100644 --- a/templates/admin/src/lib/plume-admin-theme/list/filter/FilterProps.ts +++ b/templates/admin/src/lib/plume-admin-theme/list/filter/FilterProps.ts @@ -26,4 +26,18 @@ export interface MultipleChoiceRawFilterMenuProps extends MultipleChoiceFilterMe export interface MultipleChoiceObjectFilterMenuProps extends MultipleChoiceFilterMenuProps { filters: ObjectFilterProps[], rawList: T[], +} + +export interface SingleChoiceFilterMenuProps extends FilterMenuProps { + onFilterValueClicked: (filterKey: string, valueSelected: string) => void, + selectedValues: Map, +} + +export interface SingleChoiceRawFilterMenuProps extends SingleChoiceFilterMenuProps { + filters: RawFilterProps[], +} + +export interface SingleChoiceObjectFilterMenuProps extends SingleChoiceFilterMenuProps { + filters: ObjectFilterProps[], + rawList: T[], } \ No newline at end of file From 5c6eed17d7fd174469d0c49b2c209bebe26ffe2f Mon Sep 17 00:00:00 2001 From: Lucas Amiaud Date: Fri, 29 Apr 2022 18:14:19 +0200 Subject: [PATCH 11/19] clean log API --- .../admin/assets/scss/components/_index.scss | 1 + .../assets/scss/components/_log-api.scss | 44 ++++++ .../src/i18n/translations/Translations.ts | 10 ++ templates/admin/src/i18n/translations/en.ts | 10 ++ templates/admin/src/i18n/translations/fr.ts | 10 ++ .../components/LogApiList.tsx | 8 +- .../components/LogApiTile.tsx | 52 +++++++ .../lib/plume-admin-log-api/pages/LogApi.tsx | 3 +- .../pages/LogApiDetails.tsx | 138 ++++++++++++++++-- .../plume-admin-log-api-module.ts | 2 - 10 files changed, 257 insertions(+), 21 deletions(-) create mode 100644 templates/admin/assets/scss/components/_log-api.scss create mode 100644 templates/admin/src/lib/plume-admin-log-api/components/LogApiTile.tsx diff --git a/templates/admin/assets/scss/components/_index.scss b/templates/admin/assets/scss/components/_index.scss index d4093621..52f9859f 100644 --- a/templates/admin/assets/scss/components/_index.scss +++ b/templates/admin/assets/scss/components/_index.scss @@ -1 +1,2 @@ @import 'user-tile'; +@import 'log-api'; diff --git a/templates/admin/assets/scss/components/_log-api.scss b/templates/admin/assets/scss/components/_log-api.scss new file mode 100644 index 00000000..ac4cb9cd --- /dev/null +++ b/templates/admin/assets/scss/components/_log-api.scss @@ -0,0 +1,44 @@ +@use '../variables' as *; + +$log-api-ok: #49cc90; +$log-api-warning: #fca130; +$log-api-error: #f93e3e; + +.log-api-tile { + display: flex; + justify-content: space-between; + align-items: center; + flex-wrap: wrap; + cursor: pointer; + + * { + flex-shrink: 0; + } + + .log-api-data { + height: 100%; + display: flex; + flex-wrap: wrap; + justify-content: space-between; + align-items: flex-start; + font-size: $font-size-normal; + + .data { + display: flex; + width: 15%; + height: 40px; + flex-direction: column; + align-items: flex-start; + justify-content: center; + padding: 0 $spacer-2; + margin-left: $spacer-3; + + &--large { + width: 40%; + } + &--small { + width: 30px; + } + } + } +} \ No newline at end of file diff --git a/templates/admin/src/i18n/translations/Translations.ts b/templates/admin/src/i18n/translations/Translations.ts index 52930149..acaf6659 100644 --- a/templates/admin/src/i18n/translations/Translations.ts +++ b/templates/admin/src/i18n/translations/Translations.ts @@ -87,6 +87,16 @@ export type Translations = { // logs api logs_api: { title_list: string, + title_detail: (api: string) => string, + api: string, + url: string, + date: string, + method: string, + status_code: string, + body_request: string, + body_response: string, + header_request: string, + header_response: string, }, // sorts wording 'sort': { diff --git a/templates/admin/src/i18n/translations/en.ts b/templates/admin/src/i18n/translations/en.ts index 236f915d..5c2f6fb6 100644 --- a/templates/admin/src/i18n/translations/en.ts +++ b/templates/admin/src/i18n/translations/en.ts @@ -86,6 +86,16 @@ const enMessages: Translations = { // logs api logs_api: { title_list: 'API calls List', + title_detail: (api: string) => api + ' API request details', + api: 'API', + url: 'URL', + date: 'Request date', + method: 'HTTP method', + status_code: 'Response code', + body_request: 'Body request', + body_response: 'Body response', + header_request: 'Request headers', + header_response: 'Response headers', }, // sorts wording 'sort': { diff --git a/templates/admin/src/i18n/translations/fr.ts b/templates/admin/src/i18n/translations/fr.ts index bb25ff4a..82287aee 100644 --- a/templates/admin/src/i18n/translations/fr.ts +++ b/templates/admin/src/i18n/translations/fr.ts @@ -86,6 +86,16 @@ const frMessages: Translations = { // logs api logs_api: { title_list: 'Liste des appels API', + title_detail: (api: string) => 'Détails de l\'appel à l\'API ' + api, + api: 'API', + url: 'URL', + date: 'Date de l\'appel', + method: 'Méthode HTTP', + status_code: 'Code de retour', + body_request: 'Corps de la requête', + body_response: 'Corps de la réponse', + header_request: 'Entêtes de la requête', + header_response: 'Entêtes de la réponse', }, // sorts wording 'sort': { diff --git a/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx b/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx index 35747fab..841e19e1 100644 --- a/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx +++ b/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx @@ -10,6 +10,7 @@ import { useOnComponentMounted } from '../../react-hooks-alias/ReactHooksAlias'; import LogApiApi from '../api/LogApiApi'; import { LogApiFilters, LogApiTrimmed } from '../api/LogApiTypes'; import logsApiSortsList, { DATE_DESC } from '../pages/LogsApiSort'; +import LogApiTile from './LogApiTile'; type Props = { logApiPath: string, @@ -124,13 +125,12 @@ function LogApiList({ logApiPath }: Props) { { React.Children.toArray( sortedList().map((logApi: LogApiTrimmed) => ( -
{ history.push(`${logApiPath}/${logApi.id}`) }} - > - {logApi.url} -
+ /> ) ) ) diff --git a/templates/admin/src/lib/plume-admin-log-api/components/LogApiTile.tsx b/templates/admin/src/lib/plume-admin-log-api/components/LogApiTile.tsx new file mode 100644 index 00000000..725c0b1b --- /dev/null +++ b/templates/admin/src/lib/plume-admin-log-api/components/LogApiTile.tsx @@ -0,0 +1,52 @@ +import dayjs from 'dayjs'; +import { getGlobalInstance } from 'plume-ts-di'; +import React from 'react'; +import Status from '../../plume-admin-theme/layout/Status'; +import PlumeAdminTheme from '../../plume-admin-theme/PlumeAdminTheme'; +import { LogApiTrimmed } from '../api/LogApiTypes'; + +type Props = { + logApi: LogApiTrimmed, + onClick: () => void, +} +export default function LogApiTile({ logApi, onClick }: Props) { + const theme = getGlobalInstance(PlumeAdminTheme); + + const logApiStatus = (): Status => { + if (logApi.statusCode >= 400) { + return Status.DANGER; + } + if (logApi.statusCode >= 300) { + return Status.WARN; + } + return Status.OK; + } + + return ( + +
+
+ +
+
+ {dayjs(logApi.date).format('L LT')} +
+
+ {logApi.method} +
+
+ {logApi.api} +
+
+ {logApi.url} +
+
+ {logApi.statusCode} +
+
+
+ ) +} \ No newline at end of file diff --git a/templates/admin/src/lib/plume-admin-log-api/pages/LogApi.tsx b/templates/admin/src/lib/plume-admin-log-api/pages/LogApi.tsx index dd6de05a..6b6c16ed 100644 --- a/templates/admin/src/lib/plume-admin-log-api/pages/LogApi.tsx +++ b/templates/admin/src/lib/plume-admin-log-api/pages/LogApi.tsx @@ -9,7 +9,6 @@ class LogApi { constructor( private readonly theme: PlumeAdminTheme, private readonly messages: PlumeMessageResolver, - private readonly logApiDetails: LogApiDetails, ) { } @@ -23,7 +22,7 @@ class LogApi { /> - diff --git a/templates/admin/src/lib/plume-admin-log-api/pages/LogApiDetails.tsx b/templates/admin/src/lib/plume-admin-log-api/pages/LogApiDetails.tsx index 96903cba..94d554cf 100644 --- a/templates/admin/src/lib/plume-admin-log-api/pages/LogApiDetails.tsx +++ b/templates/admin/src/lib/plume-admin-log-api/pages/LogApiDetails.tsx @@ -1,18 +1,130 @@ -import React from 'react'; +import dayjs from 'dayjs'; +import { getGlobalInstance } from 'plume-ts-di'; +import React, { useEffect, useState } from 'react'; +import { useForm } from 'react-hook-form'; +import { useHistory, useParams } from 'react-router-dom'; import PlumeAdminTheme from '../../plume-admin-theme/PlumeAdminTheme'; -import UserApi from '../../plume-admin-users/api/UserApi'; +import useLoader from '../../plume-http-react-hook-loader/promiseLoaderHook'; import PlumeMessageResolver from '../../plume-messages/MessageResolver'; -import NotificationEngine from '../../plume-notification/NotificationEngine'; - -class LogApiDetails { - constructor(private readonly userApi: UserApi, - private readonly notificationEngine: NotificationEngine, - private readonly theme: PlumeAdminTheme, - private readonly messages: PlumeMessageResolver) { - } - render = () => { - return (<>); - } +import { useOnComponentMounted } from '../../react-hooks-alias/ReactHooksAlias'; +import LogApiApi from '../api/LogApiApi'; +import { LogApiDetailsType } from '../api/LogApiTypes'; + +type Props = { + logApiPath: string, +} + +type LogApiRouteParams = { + logApiId: string, +}; + +function LogApiDetails({ logApiPath }: Props) { + const logApiApi = getGlobalInstance(LogApiApi); + const theme = getGlobalInstance(PlumeAdminTheme); + const messages = getGlobalInstance(PlumeMessageResolver); + + const history = useHistory(); + const logApiLoader = useLoader(); + const { logApiId } = useParams(); + + const [logApiDetail, setLogApiDetail] = useState(); + const fetchLogById = () => { + logApiLoader.monitor( + logApiApi.fetchById(logApiId) + .then(setLogApiDetail) + ) + }; + + useOnComponentMounted(() => { + fetchLogById(); + }); + + const { + control, + reset + } = useForm(); + + useEffect(() => { + reset(logApiDetail); + }, [logApiDetail]) + + return ( + { + history.push(logApiPath) + }} + > + { + logApiLoader.isLoading + && ( +
+ Loding +
+ ) + } + { + logApiLoader.isLoaded + && logApiDetail + && ( + +
+ + + + + + + + + + + + + + + + + + +
+ ) + } +
+ ); } export default (LogApiDetails); diff --git a/templates/admin/src/lib/plume-admin-log-api/plume-admin-log-api-module.ts b/templates/admin/src/lib/plume-admin-log-api/plume-admin-log-api-module.ts index e1823bea..69f1975a 100644 --- a/templates/admin/src/lib/plume-admin-log-api/plume-admin-log-api-module.ts +++ b/templates/admin/src/lib/plume-admin-log-api/plume-admin-log-api-module.ts @@ -1,10 +1,8 @@ import { Injector } from 'plume-ts-di'; import LogApiApi from './api/LogApiApi'; import LogApi from './pages/LogApi'; -import LogApiDetails from './pages/LogApiDetails'; export default function installPlumeAdminLogApiModule(injector: Injector) { injector.registerSingleton(LogApi); injector.registerSingleton(LogApiApi); - injector.registerSingleton(LogApiDetails); } From dc83335a233e926867d86fa23ee08662af4837b9 Mon Sep 17 00:00:00 2001 From: Lucas Amiaud Date: Fri, 29 Apr 2022 18:46:21 +0200 Subject: [PATCH 12/19] clean log API --- templates/admin/src/i18n/translations/Translations.ts | 3 +++ templates/admin/src/i18n/translations/en.ts | 3 +++ templates/admin/src/i18n/translations/fr.ts | 3 +++ .../src/lib/plume-admin-log-api/components/LogApiList.tsx | 2 +- 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/templates/admin/src/i18n/translations/Translations.ts b/templates/admin/src/i18n/translations/Translations.ts index acaf6659..0064e2db 100644 --- a/templates/admin/src/i18n/translations/Translations.ts +++ b/templates/admin/src/i18n/translations/Translations.ts @@ -97,6 +97,9 @@ export type Translations = { body_response: string, header_request: string, header_response: string, + list: { + count: (count: number) => string, + }, }, // sorts wording 'sort': { diff --git a/templates/admin/src/i18n/translations/en.ts b/templates/admin/src/i18n/translations/en.ts index 5c2f6fb6..3357390b 100644 --- a/templates/admin/src/i18n/translations/en.ts +++ b/templates/admin/src/i18n/translations/en.ts @@ -96,6 +96,9 @@ const enMessages: Translations = { body_response: 'Body response', header_request: 'Request headers', header_response: 'Response headers', + list: { + count: (count: number) => 'API logs count : ' + count, + }, }, // sorts wording 'sort': { diff --git a/templates/admin/src/i18n/translations/fr.ts b/templates/admin/src/i18n/translations/fr.ts index 82287aee..0bacbf67 100644 --- a/templates/admin/src/i18n/translations/fr.ts +++ b/templates/admin/src/i18n/translations/fr.ts @@ -96,6 +96,9 @@ const frMessages: Translations = { body_response: 'Corps de la réponse', header_request: 'Entêtes de la requête', header_response: 'Entêtes de la réponse', + list: { + count: (count: number) => 'Nombre de logs API : ' + count, + }, }, // sorts wording 'sort': { diff --git a/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx b/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx index 841e19e1..4b201fbe 100644 --- a/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx +++ b/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx @@ -111,7 +111,7 @@ function LogApiList({ logApiPath }: Props) {
Date: Tue, 3 May 2022 12:04:02 +0200 Subject: [PATCH 13/19] add date pickers --- .../assets/scss/components/_log-api.scss | 4 + templates/admin/package.json | 1 + .../admin/src/components/theme/AdminTheme.ts | 6 ++ .../theme/form/fields/InputDatePicker.tsx | 86 ++++++++++++++++ .../form/fields/InputDateRangePicker.tsx | 99 +++++++++++++++++++ .../src/i18n/translations/Translations.ts | 7 ++ templates/admin/src/i18n/translations/en.ts | 7 ++ templates/admin/src/i18n/translations/fr.ts | 7 ++ .../components/LogApiList.tsx | 29 ++++-- .../components/LogApiRangeSelector.tsx | 42 ++++++++ .../lib/plume-admin-theme/PlumeAdminTheme.ts | 11 ++- .../plume-admin-theme/form/FormInputProps.ts | 17 +++- .../react-hook-debounce/ReactHookDebounce.ts | 8 ++ 13 files changed, 315 insertions(+), 9 deletions(-) create mode 100644 templates/admin/src/components/theme/form/fields/InputDatePicker.tsx create mode 100644 templates/admin/src/components/theme/form/fields/InputDateRangePicker.tsx create mode 100644 templates/admin/src/lib/plume-admin-log-api/components/LogApiRangeSelector.tsx create mode 100644 templates/admin/src/lib/react-hook-debounce/ReactHookDebounce.ts diff --git a/templates/admin/assets/scss/components/_log-api.scss b/templates/admin/assets/scss/components/_log-api.scss index ac4cb9cd..60309c09 100644 --- a/templates/admin/assets/scss/components/_log-api.scss +++ b/templates/admin/assets/scss/components/_log-api.scss @@ -17,6 +17,7 @@ $log-api-error: #f93e3e; .log-api-data { height: 100%; + width: 100%; display: flex; flex-wrap: wrap; justify-content: space-between; @@ -32,6 +33,9 @@ $log-api-error: #f93e3e; justify-content: center; padding: 0 $spacer-2; margin-left: $spacer-3; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; &--large { width: 40%; diff --git a/templates/admin/package.json b/templates/admin/package.json index ab9a6df4..e6d93243 100644 --- a/templates/admin/package.json +++ b/templates/admin/package.json @@ -6,6 +6,7 @@ "@emotion/react": "^11.4.1", "@emotion/styled": "^11.3.0", "@fontsource/roboto": "^4.5.0", + "@mui/lab": "5.0.0-alpha.49", "@mui/material": "^5.0.6", "@mui/styles": "^5.0.2", "@mui/system": "^5.0.6", diff --git a/templates/admin/src/components/theme/AdminTheme.ts b/templates/admin/src/components/theme/AdminTheme.ts index 52352b83..70cbd22f 100644 --- a/templates/admin/src/components/theme/AdminTheme.ts +++ b/templates/admin/src/components/theme/AdminTheme.ts @@ -2,6 +2,8 @@ import PlumeAdminTheme from '../../lib/plume-admin-theme/PlumeAdminTheme'; import { ActionButton, ActionLink, ActionsContainer } from './action/Actions'; import Drawer from './drawer/Drawer'; import UncontrolledDrawer from './drawer/UncontrolledDrawer'; +import InputDatePicker from './form/fields/InputDatePicker'; +import InputDateRangePicker from './form/fields/InputDateRangePicker'; import InputSelect from './form/fields/InputSelect'; import InputText from './form/fields/InputText'; import FormField from './form/FormField'; @@ -67,4 +69,8 @@ export default class AdminTheme implements PlumeAdminTheme { inputText = InputText; inputSelect = InputSelect; + + inputDate = InputDatePicker; + + inputDateRange = InputDateRangePicker; } diff --git a/templates/admin/src/components/theme/form/fields/InputDatePicker.tsx b/templates/admin/src/components/theme/form/fields/InputDatePicker.tsx new file mode 100644 index 00000000..3adbf850 --- /dev/null +++ b/templates/admin/src/components/theme/form/fields/InputDatePicker.tsx @@ -0,0 +1,86 @@ +import React from 'react'; +import { DatePicker, LocalizationProvider } from '@mui/lab'; +import DateAdapter from '@mui/lab/AdapterDayjs'; +import { MuiTextFieldProps } from '@mui/lab/internal/pickers/PureDateInput'; +import { TextField } from '@mui/material'; +import { useController } from 'react-hook-form'; +import en from '../../../../i18n/translations/en'; +import fr from '../../../../i18n/translations/fr'; +import { Translations } from '../../../../i18n/translations/Translations'; +import { + InputDateProps +} from '../../../../lib/plume-admin-theme/form/FormInputProps'; + +function InputDatePicker( + { + placeholder, + label, + name, + id, + useNameAsId, + control, + rules, + disabled, + defaultValue, + onDateChange, + autoComplete, + disableOpenPicker, + locale, + }: InputDateProps) { + const fieldId: string = (useNameAsId ? name : (id ?? name)) || ''; + + const localeMap = { + en, + fr, + }; + + const { field } = useController({ + name: fieldId, + control, + rules, + defaultValue: defaultValue || null, + }); + + const onChangeCombined = (value: any) => { + field.onChange(value); + if (onDateChange) { + onDateChange(value); + } + }; + + const currentLocale: Translations = localeMap[locale as 'fr' | 'en']; + + return ( + + ( + + )} + /> + + ); +} + +export default (InputDatePicker); \ No newline at end of file diff --git a/templates/admin/src/components/theme/form/fields/InputDateRangePicker.tsx b/templates/admin/src/components/theme/form/fields/InputDateRangePicker.tsx new file mode 100644 index 00000000..c9a49db8 --- /dev/null +++ b/templates/admin/src/components/theme/form/fields/InputDateRangePicker.tsx @@ -0,0 +1,99 @@ +import { DateRangePicker, LocalizationProvider } from '@mui/lab'; +import DateAdapter from '@mui/lab/AdapterDayjs'; +import { DateRange } from '@mui/lab/DateRangePicker/RangeTypes'; +import { MuiTextFieldProps } from '@mui/lab/internal/pickers/PureDateInput'; +import { Icon, TextField } from '@mui/material'; +import { Dayjs } from 'dayjs'; +import React from 'react'; +import { useController } from 'react-hook-form'; +import en from '../../../../i18n/translations/en'; +import fr from '../../../../i18n/translations/fr'; +import { Translations } from '../../../../i18n/translations/Translations'; +import { InputDateRangeProps } from '../../../../lib/plume-admin-theme/form/FormInputProps'; + +function InputDateRangePicker( + { + name, + id, + useNameAsId, + control, + rules, + disabled, + defaultValue, + onBlur, + locale, + onDateChange + }: InputDateRangeProps +) { + const fieldId: string = (useNameAsId ? name : (id ?? name)) || ''; + + const { field } = useController({ + name: fieldId, + control, + rules, + defaultValue: defaultValue || [], + }); + + const onBlurCombined = (value: any) => { + field.onBlur(); + if (onBlur) { + onBlur(value); + } + }; + + const onCustomChange = (val: DateRange, keyboardInputValue?: string) => { + // Update the date when it has been updated using the datepicker and not the text fields + if (!keyboardInputValue) { + field.onChange(val); + if (onDateChange) { + onDateChange(val); + } + } + }; + + const localeMap = { + en, + fr, + }; + + const currentLocale: Translations = localeMap[locale as 'fr' | 'en']; + + return ( + + , keyboardInputValue?: string) => { + onCustomChange(date, keyboardInputValue); + }} + renderInput={(startProps: MuiTextFieldProps, endProps: MuiTextFieldProps) => ( + <> + + arrow_forward + + + )} + /> + + ); +} + +export default (InputDateRangePicker); \ No newline at end of file diff --git a/templates/admin/src/i18n/translations/Translations.ts b/templates/admin/src/i18n/translations/Translations.ts index 0064e2db..ead35df7 100644 --- a/templates/admin/src/i18n/translations/Translations.ts +++ b/templates/admin/src/i18n/translations/Translations.ts @@ -49,6 +49,13 @@ export type Translations = { settings: string, log_api: string, }, + //format + format : { + date: string, + date_mask: string, + hour: string, + date_hour: string, + }, // home home: { title: string, diff --git a/templates/admin/src/i18n/translations/en.ts b/templates/admin/src/i18n/translations/en.ts index 3357390b..d0e4492c 100644 --- a/templates/admin/src/i18n/translations/en.ts +++ b/templates/admin/src/i18n/translations/en.ts @@ -48,6 +48,13 @@ const enMessages: Translations = { settings: 'Paramètres', log_api: 'API Logs', }, + //format + format : { + date: 'YYYY-MM-DD', + date_mask: '____-__-__', + hour: 'hh:mm a', + date_hour: 'YYYY-MM-DD hh:mm a', + }, // home home: { title: 'Home page', diff --git a/templates/admin/src/i18n/translations/fr.ts b/templates/admin/src/i18n/translations/fr.ts index 0bacbf67..450ab610 100644 --- a/templates/admin/src/i18n/translations/fr.ts +++ b/templates/admin/src/i18n/translations/fr.ts @@ -48,6 +48,13 @@ const frMessages: Translations = { settings: 'Paramètres', log_api: 'API Logs', }, + //format + format : { + date: 'DD/MM/YYYY', + date_mask: '__/__/____', + hour: 'hh:mm', + date_hour: 'DD/MM/YYYY hh:mm', + }, // home home: { title: 'Page d\'accueil', diff --git a/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx b/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx index 4b201fbe..0543f8fd 100644 --- a/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx +++ b/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx @@ -1,5 +1,7 @@ +import dayjs, { Dayjs } from 'dayjs'; import { getGlobalInstance } from 'plume-ts-di'; import React, { useEffect, useState } from 'react'; +import { useForm } from 'react-hook-form'; import { useHistory } from 'react-router-dom'; import { replaceValueForFilter } from '../../../components/theme/utils/FilterUtils'; import MessageService from '../../../i18n/messages/MessageService'; @@ -10,6 +12,7 @@ import { useOnComponentMounted } from '../../react-hooks-alias/ReactHooksAlias'; import LogApiApi from '../api/LogApiApi'; import { LogApiFilters, LogApiTrimmed } from '../api/LogApiTypes'; import logsApiSortsList, { DATE_DESC } from '../pages/LogsApiSort'; +import LogApiRangeSelector from './LogApiRangeSelector'; import LogApiTile from './LogApiTile'; type Props = { @@ -31,6 +34,8 @@ function LogApiList({ logApiPath }: Props) { statusCode: selectedLogsApiFilters.get('status_code'), apiName: selectedLogsApiFilters.get('api_name'), url: currentSearchBarFilter, + startDate: selectedStartDate?.startOf('day').toISOString(), + endDate: selectedEndDate?.endOf('day').toISOString(), }) .then(setLogsApi) ); @@ -42,6 +47,8 @@ function LogApiList({ logApiPath }: Props) { const [currentLogsApiSorting, setCurrentLogsApiSorting] = useState(DATE_DESC); // filters + const [selectedStartDate, setSelectedStartDate] = useState(); + const [selectedEndDate, setSelectedEndDate] = useState(); const [selectedLogsApiFilters, setSelectedLogsApiFilters] = useState>(new Map()); const [logsApiFilters, setLogsApiFilters] = useState(); const logApiFiltersLoader = useLoader(); @@ -57,11 +64,7 @@ function LogApiList({ logApiPath }: Props) { useEffect(() => { fetchLogsApi(); - }, [selectedLogsApiFilters, currentSearchBarFilter]); - - const applySearchBarFilter = (searchedText: string) => { - setCurrentSearchBarFilter(searchedText); - } + }, [selectedLogsApiFilters, currentSearchBarFilter, selectedStartDate, selectedEndDate]); const sortedList = () => { return logsApi?.sort(currentLogsApiSorting.sortFunction) || []; @@ -74,7 +77,19 @@ function LogApiList({ logApiPath }: Props) { ) => { - applySearchBarFilter(event.target.value); + setCurrentSearchBarFilter(event.target.value); + }} + /> + +
+ + + { + setSelectedStartDate(date); + }} + onEndDateChange={(date: Dayjs | null) => { + setSelectedEndDate(date); }} /> @@ -90,7 +105,7 @@ function LogApiList({ logApiPath }: Props) { }, { filterKey: 'status_code', - possibleValues: logsApiFilters?.statusCodes?.map(status => status.toString()) ?? [] + possibleValues: logsApiFilters?.statusCodes?.map((status: number) => status.toString()) ?? [] }, { filterKey: 'method', diff --git a/templates/admin/src/lib/plume-admin-log-api/components/LogApiRangeSelector.tsx b/templates/admin/src/lib/plume-admin-log-api/components/LogApiRangeSelector.tsx new file mode 100644 index 00000000..d49038fa --- /dev/null +++ b/templates/admin/src/lib/plume-admin-log-api/components/LogApiRangeSelector.tsx @@ -0,0 +1,42 @@ +import { DateRange } from '@mui/lab'; +import { Dayjs } from 'dayjs'; +import { getGlobalInstance } from 'plume-ts-di'; +import React, { useState } from 'react'; +import { useForm } from 'react-hook-form'; +import PlumeAdminTheme from '../../plume-admin-theme/PlumeAdminTheme'; +import useDebounce from '../../react-hook-debounce/ReactHookDebounce'; + +type Props = { + onStartDateChange: (date: Dayjs | null) => void, + onEndDateChange: (date: Dayjs | null) => void, +} + +function LogApiRangeSelector({ onStartDateChange, onEndDateChange }: Props) { + const theme = getGlobalInstance(PlumeAdminTheme); + const [dateRange, setDateRange] = useState>(); + + useDebounce(() => { + if (dateRange) { + onStartDateChange(dateRange[0]); + onEndDateChange(dateRange[1]); + } + }, + 1500, + [dateRange] + ) + + const { + control, + } = useForm<{ dateRange: string }>(); + + return ( + + ) +} + +export default (LogApiRangeSelector); diff --git a/templates/admin/src/lib/plume-admin-theme/PlumeAdminTheme.ts b/templates/admin/src/lib/plume-admin-theme/PlumeAdminTheme.ts index 3c45b616..684f9a59 100644 --- a/templates/admin/src/lib/plume-admin-theme/PlumeAdminTheme.ts +++ b/templates/admin/src/lib/plume-admin-theme/PlumeAdminTheme.ts @@ -1,7 +1,12 @@ import { ActionButtonProps, ActionContainerProps, ActionLinkProps } from './action/ActionProps'; import { DrawerTypeProps, UncontrolledDrawerTypeProps } from './drawer/DrawerProps'; import { FormFieldProps } from './form/FormFieldProps'; -import { InputSelectProps, InputTextProps } from './form/FormInputProps'; +import { + InputDateProps, + InputDateRangeProps, + InputSelectProps, + InputTextProps +} from './form/FormInputProps'; import { LayoutPageBlocColumnProps, LayoutPageBlocProps, @@ -80,4 +85,8 @@ export default abstract class PlumeAdminTheme { abstract inputText: (props: InputTextProps) => JSX.Element; abstract inputSelect: (props: InputSelectProps) => JSX.Element; + + abstract inputDate: (props: InputDateProps) => JSX.Element; + + abstract inputDateRange: (props: InputDateRangeProps) => JSX.Element; } diff --git a/templates/admin/src/lib/plume-admin-theme/form/FormInputProps.ts b/templates/admin/src/lib/plume-admin-theme/form/FormInputProps.ts index bf6c8412..78c7badb 100644 --- a/templates/admin/src/lib/plume-admin-theme/form/FormInputProps.ts +++ b/templates/admin/src/lib/plume-admin-theme/form/FormInputProps.ts @@ -1,3 +1,5 @@ +import { DateRange } from '@mui/lab'; +import { Dayjs } from 'dayjs'; import { FocusEventHandler } from 'react'; import { Control } from 'react-hook-form/dist/types/form'; import { RegisterOptions } from 'react-hook-form/dist/types/validator'; @@ -41,4 +43,17 @@ export type InputSelectProps = { export type SelectOptionProps = { label: string, value: any, -} +}; + +type GenericInputDateProps = { + locale: string, + disableOpenPicker?: boolean, +} & InputTextProps; + +export type InputDateProps = { + onDateChange?: (value: Dayjs) => void, +} & GenericInputDateProps; + +export type InputDateRangeProps = { + onDateChange?: (values: DateRange) => void, +} & GenericInputDateProps; diff --git a/templates/admin/src/lib/react-hook-debounce/ReactHookDebounce.ts b/templates/admin/src/lib/react-hook-debounce/ReactHookDebounce.ts new file mode 100644 index 00000000..62658575 --- /dev/null +++ b/templates/admin/src/lib/react-hook-debounce/ReactHookDebounce.ts @@ -0,0 +1,8 @@ +import { useEffect } from 'react'; +import useTimeout from '../plume-http-react-hook-loader/timeoutHook'; + +export default function useDebounce(callback: () => void, delay: number, dependencies: any[]) { + const { restartTimeout, stopTimeout } = useTimeout(callback, delay); + useEffect(restartTimeout, [...dependencies, restartTimeout]); + useEffect(stopTimeout, []); +} \ No newline at end of file From b1a27df478e7bff23cdc7aa54f550a9322cb24c5 Mon Sep 17 00:00:00 2001 From: Lucas Amiaud Date: Tue, 3 May 2022 14:16:28 +0200 Subject: [PATCH 14/19] fix style pickers --- .../admin/src/components/theme/AdminTheme.ts | 3 + .../theme/form/fields/InputDatePicker.tsx | 5 +- .../form/fields/InputDateRangePicker.tsx | 13 ++- .../theme/form/fields/InputDateTimePicker.tsx | 87 +++++++++++++++++++ .../src/i18n/translations/Translations.ts | 2 + templates/admin/src/i18n/translations/en.ts | 2 + templates/admin/src/i18n/translations/fr.ts | 2 + .../components/LogApiRangeSelector.tsx | 5 +- .../lib/plume-admin-theme/PlumeAdminTheme.ts | 2 + .../plume-admin-theme/form/FormInputProps.ts | 2 + 10 files changed, 117 insertions(+), 6 deletions(-) create mode 100644 templates/admin/src/components/theme/form/fields/InputDateTimePicker.tsx diff --git a/templates/admin/src/components/theme/AdminTheme.ts b/templates/admin/src/components/theme/AdminTheme.ts index 70cbd22f..ee551114 100644 --- a/templates/admin/src/components/theme/AdminTheme.ts +++ b/templates/admin/src/components/theme/AdminTheme.ts @@ -4,6 +4,7 @@ import Drawer from './drawer/Drawer'; import UncontrolledDrawer from './drawer/UncontrolledDrawer'; import InputDatePicker from './form/fields/InputDatePicker'; import InputDateRangePicker from './form/fields/InputDateRangePicker'; +import InputDateTimePicker from './form/fields/InputDateTimePicker'; import InputSelect from './form/fields/InputSelect'; import InputText from './form/fields/InputText'; import FormField from './form/FormField'; @@ -72,5 +73,7 @@ export default class AdminTheme implements PlumeAdminTheme { inputDate = InputDatePicker; + inputDateTime = InputDateTimePicker; + inputDateRange = InputDateRangePicker; } diff --git a/templates/admin/src/components/theme/form/fields/InputDatePicker.tsx b/templates/admin/src/components/theme/form/fields/InputDatePicker.tsx index 3adbf850..fe34d91f 100644 --- a/templates/admin/src/components/theme/form/fields/InputDatePicker.tsx +++ b/templates/admin/src/components/theme/form/fields/InputDatePicker.tsx @@ -24,6 +24,8 @@ function InputDatePicker( defaultValue, onDateChange, autoComplete, + showTodayButton, + disableFuture, disableOpenPicker, locale, }: InputDateProps) { @@ -56,6 +58,8 @@ function InputDatePicker( onChange={onChangeCombined} value={field.value} disableOpenPicker={disableOpenPicker} + showTodayButton={showTodayButton ?? false} + disableFuture={disableFuture ?? false} inputFormat={currentLocale.format.date} mask={currentLocale.format.date_mask} renderInput={(params: MuiTextFieldProps) => ( @@ -71,7 +75,6 @@ function InputDatePicker( ...params.inputProps, placeholder: placeholder || currentLocale.format.date, }} - variant="outlined" autoComplete={autoComplete} disabled={disabled ?? false} onBlur={field.onBlur} diff --git a/templates/admin/src/components/theme/form/fields/InputDateRangePicker.tsx b/templates/admin/src/components/theme/form/fields/InputDateRangePicker.tsx index c9a49db8..f3232e1c 100644 --- a/templates/admin/src/components/theme/form/fields/InputDateRangePicker.tsx +++ b/templates/admin/src/components/theme/form/fields/InputDateRangePicker.tsx @@ -22,7 +22,9 @@ function InputDateRangePicker( defaultValue, onBlur, locale, - onDateChange + onDateChange, + showTodayButton, + disableFuture, }: InputDateRangeProps ) { const fieldId: string = (useNameAsId ? name : (id ?? name)) || ''; @@ -61,30 +63,33 @@ function InputDateRangePicker( return ( , keyboardInputValue?: string) => { onCustomChange(date, keyboardInputValue); }} renderInput={(startProps: MuiTextFieldProps, endProps: MuiTextFieldProps) => ( <> arrow_forward { + field.onChange(value); + if (onDateChange) { + onDateChange(value); + } + }; + + const currentLocale: Translations = localeMap[locale as 'fr' | 'en']; + + return ( + + ( + + )} + /> + + ); +} + +export default (InputDatePicker); \ No newline at end of file diff --git a/templates/admin/src/i18n/translations/Translations.ts b/templates/admin/src/i18n/translations/Translations.ts index ead35df7..e8940eef 100644 --- a/templates/admin/src/i18n/translations/Translations.ts +++ b/templates/admin/src/i18n/translations/Translations.ts @@ -54,7 +54,9 @@ export type Translations = { date: string, date_mask: string, hour: string, + hour_mask: string, date_hour: string, + date_hour_mask: string, }, // home home: { diff --git a/templates/admin/src/i18n/translations/en.ts b/templates/admin/src/i18n/translations/en.ts index d0e4492c..8643b98b 100644 --- a/templates/admin/src/i18n/translations/en.ts +++ b/templates/admin/src/i18n/translations/en.ts @@ -53,7 +53,9 @@ const enMessages: Translations = { date: 'YYYY-MM-DD', date_mask: '____-__-__', hour: 'hh:mm a', + hour_mask: '__:__ _M', date_hour: 'YYYY-MM-DD hh:mm a', + date_hour_mask: '____-__-__ __:__ _M', }, // home home: { diff --git a/templates/admin/src/i18n/translations/fr.ts b/templates/admin/src/i18n/translations/fr.ts index 450ab610..bef1e720 100644 --- a/templates/admin/src/i18n/translations/fr.ts +++ b/templates/admin/src/i18n/translations/fr.ts @@ -53,7 +53,9 @@ const frMessages: Translations = { date: 'DD/MM/YYYY', date_mask: '__/__/____', hour: 'hh:mm', + hour_mask: '__:__', date_hour: 'DD/MM/YYYY hh:mm', + date_hour_mask: '__/__/____ __:__', }, // home home: { diff --git a/templates/admin/src/lib/plume-admin-log-api/components/LogApiRangeSelector.tsx b/templates/admin/src/lib/plume-admin-log-api/components/LogApiRangeSelector.tsx index d49038fa..29261996 100644 --- a/templates/admin/src/lib/plume-admin-log-api/components/LogApiRangeSelector.tsx +++ b/templates/admin/src/lib/plume-admin-log-api/components/LogApiRangeSelector.tsx @@ -3,6 +3,7 @@ import { Dayjs } from 'dayjs'; import { getGlobalInstance } from 'plume-ts-di'; import React, { useState } from 'react'; import { useForm } from 'react-hook-form'; +import LocaleService from '../../../i18n/locale/LocaleService'; import PlumeAdminTheme from '../../plume-admin-theme/PlumeAdminTheme'; import useDebounce from '../../react-hook-debounce/ReactHookDebounce'; @@ -12,6 +13,7 @@ type Props = { } function LogApiRangeSelector({ onStartDateChange, onEndDateChange }: Props) { + const localeService = getGlobalInstance(LocaleService); const theme = getGlobalInstance(PlumeAdminTheme); const [dateRange, setDateRange] = useState>(); @@ -32,9 +34,10 @@ function LogApiRangeSelector({ onStartDateChange, onEndDateChange }: Props) { return ( ) } diff --git a/templates/admin/src/lib/plume-admin-theme/PlumeAdminTheme.ts b/templates/admin/src/lib/plume-admin-theme/PlumeAdminTheme.ts index 684f9a59..bdbbe1ae 100644 --- a/templates/admin/src/lib/plume-admin-theme/PlumeAdminTheme.ts +++ b/templates/admin/src/lib/plume-admin-theme/PlumeAdminTheme.ts @@ -88,5 +88,7 @@ export default abstract class PlumeAdminTheme { abstract inputDate: (props: InputDateProps) => JSX.Element; + abstract inputDateTime: (props: InputDateProps) => JSX.Element; + abstract inputDateRange: (props: InputDateRangeProps) => JSX.Element; } diff --git a/templates/admin/src/lib/plume-admin-theme/form/FormInputProps.ts b/templates/admin/src/lib/plume-admin-theme/form/FormInputProps.ts index 78c7badb..500df381 100644 --- a/templates/admin/src/lib/plume-admin-theme/form/FormInputProps.ts +++ b/templates/admin/src/lib/plume-admin-theme/form/FormInputProps.ts @@ -48,6 +48,8 @@ export type SelectOptionProps = { type GenericInputDateProps = { locale: string, disableOpenPicker?: boolean, + disableFuture?: boolean, + showTodayButton?: boolean, } & InputTextProps; export type InputDateProps = { From fb9e326bc594262c91ae1d63c98630d645d7789b Mon Sep 17 00:00:00 2001 From: Lucas Amiaud Date: Tue, 3 May 2022 17:26:57 +0200 Subject: [PATCH 15/19] esling fixes --- templates/admin/src/components/Routes.ts | 2 +- .../admin/src/components/layout/Header.tsx | 30 +- .../theme/form/fields/InputDatePicker.tsx | 9 +- .../form/fields/InputDateRangePicker.tsx | 14 +- .../theme/form/fields/InputDateTimePicker.tsx | 7 +- .../list/filter/SingleChoiceFilterMenu.tsx | 105 +++--- .../lib/plume-admin-log-api/api/LogApiApi.ts | 6 +- .../plume-admin-log-api/api/LogApiTypes.ts | 4 +- .../components/LogApiList.tsx | 64 ++-- .../components/LogApiRangeSelector.tsx | 11 +- .../components/LogApiTile.tsx | 9 +- .../lib/plume-admin-log-api/pages/LogApi.tsx | 12 +- .../pages/LogApiDetails.tsx | 2 +- .../plume-admin-log-api/pages/LogsApiSort.ts | 8 +- templates/admin/yarn.lock | 339 +++++++++++++++--- 15 files changed, 420 insertions(+), 202 deletions(-) diff --git a/templates/admin/src/components/Routes.ts b/templates/admin/src/components/Routes.ts index d5225bb0..0bd50ece 100644 --- a/templates/admin/src/components/Routes.ts +++ b/templates/admin/src/components/Routes.ts @@ -2,5 +2,5 @@ export const HOME = '/home'; export const USERS = '/users'; export const LOG_API = '/log-api'; -export const LOGIN = '/login' +export const LOGIN = '/login'; export const FORGOT_PASSWORD = '/forgot-password'; diff --git a/templates/admin/src/components/layout/Header.tsx b/templates/admin/src/components/layout/Header.tsx index 444f9100..6ced349a 100644 --- a/templates/admin/src/components/layout/Header.tsx +++ b/templates/admin/src/components/layout/Header.tsx @@ -1,13 +1,13 @@ -import React from 'react'; -import { getGlobalInstance } from 'plume-ts-di'; import { MenuItem } from '@mui/material'; +import { getGlobalInstance } from 'plume-ts-di'; +import React from 'react'; import LocaleService from '../../i18n/locale/LocaleService'; +import MessageService from '../../i18n/messages/MessageService'; import { Locale } from '../../lib/locale-resolver/LocaleResolver'; -import { User } from '../../services/session/User'; -import LocaleSelector from '../theme/LocaleSelector'; import SessionService from '../../services/session/SessionService'; -import MessageService from '../../i18n/messages/MessageService'; +import { User } from '../../services/session/User'; import DropdownMenu from '../theme/DropdownMenu'; +import LocaleSelector from '../theme/LocaleSelector'; type HeaderProps = { currentLocale: Locale; @@ -38,16 +38,16 @@ export default function Header({ currentLocale, currentUser }: HeaderProps) { onLocaleSelected={(newLocale) => localeService.setCurrentLocale(newLocale)} /> -
- -
{currentUser.fullName}
- sessionService.disconnect()} - > - {messages.action.disconnect} - -
-
+
+ +
{currentUser.fullName}
+ sessionService.disconnect()} + > + {messages.action.disconnect} + +
+
); diff --git a/templates/admin/src/components/theme/form/fields/InputDatePicker.tsx b/templates/admin/src/components/theme/form/fields/InputDatePicker.tsx index fe34d91f..11a0f0b1 100644 --- a/templates/admin/src/components/theme/form/fields/InputDatePicker.tsx +++ b/templates/admin/src/components/theme/form/fields/InputDatePicker.tsx @@ -1,3 +1,4 @@ +import { Dayjs } from 'dayjs'; import React from 'react'; import { DatePicker, LocalizationProvider } from '@mui/lab'; import DateAdapter from '@mui/lab/AdapterDayjs'; @@ -8,7 +9,7 @@ import en from '../../../../i18n/translations/en'; import fr from '../../../../i18n/translations/fr'; import { Translations } from '../../../../i18n/translations/Translations'; import { - InputDateProps + InputDateProps, } from '../../../../lib/plume-admin-theme/form/FormInputProps'; function InputDatePicker( @@ -43,9 +44,9 @@ function InputDatePicker( defaultValue: defaultValue || null, }); - const onChangeCombined = (value: any) => { + const onChangeCombined = (value: Dayjs | null) => { field.onChange(value); - if (onDateChange) { + if (value && onDateChange) { onDateChange(value); } }; @@ -86,4 +87,4 @@ function InputDatePicker( ); } -export default (InputDatePicker); \ No newline at end of file +export default (InputDatePicker); diff --git a/templates/admin/src/components/theme/form/fields/InputDateRangePicker.tsx b/templates/admin/src/components/theme/form/fields/InputDateRangePicker.tsx index f3232e1c..5138b3ed 100644 --- a/templates/admin/src/components/theme/form/fields/InputDateRangePicker.tsx +++ b/templates/admin/src/components/theme/form/fields/InputDateRangePicker.tsx @@ -20,12 +20,11 @@ function InputDateRangePicker( rules, disabled, defaultValue, - onBlur, locale, onDateChange, showTodayButton, disableFuture, - }: InputDateRangeProps + }: InputDateRangeProps, ) { const fieldId: string = (useNameAsId ? name : (id ?? name)) || ''; @@ -36,13 +35,6 @@ function InputDateRangePicker( defaultValue: defaultValue || [], }); - const onBlurCombined = (value: any) => { - field.onBlur(); - if (onBlur) { - onBlur(value); - } - }; - const onCustomChange = (val: DateRange, keyboardInputValue?: string) => { // Update the date when it has been updated using the datepicker and not the text fields if (!keyboardInputValue) { @@ -82,7 +74,6 @@ function InputDateRangePicker( name={name} id={fieldId} disabled={disabled ?? false} - onBlur={onBlurCombined} /> arrow_forward )} @@ -101,4 +91,4 @@ function InputDateRangePicker( ); } -export default (InputDateRangePicker); \ No newline at end of file +export default (InputDateRangePicker); diff --git a/templates/admin/src/components/theme/form/fields/InputDateTimePicker.tsx b/templates/admin/src/components/theme/form/fields/InputDateTimePicker.tsx index 8afd1fdf..5b885584 100644 --- a/templates/admin/src/components/theme/form/fields/InputDateTimePicker.tsx +++ b/templates/admin/src/components/theme/form/fields/InputDateTimePicker.tsx @@ -2,6 +2,7 @@ import { DateTimePicker, LocalizationProvider } from '@mui/lab'; import DateAdapter from '@mui/lab/AdapterDayjs'; import { MuiTextFieldProps } from '@mui/lab/internal/pickers/PureDateInput'; import { TextField } from '@mui/material'; +import { Dayjs } from 'dayjs'; import React from 'react'; import { useController } from 'react-hook-form'; import en from '../../../../i18n/translations/en'; @@ -41,9 +42,9 @@ function InputDatePicker( defaultValue: defaultValue || null, }); - const onChangeCombined = (value: any) => { + const onChangeCombined = (value: Dayjs | null) => { field.onChange(value); - if (onDateChange) { + if (value && onDateChange) { onDateChange(value); } }; @@ -84,4 +85,4 @@ function InputDatePicker( ); } -export default (InputDatePicker); \ No newline at end of file +export default (InputDatePicker); diff --git a/templates/admin/src/components/theme/list/filter/SingleChoiceFilterMenu.tsx b/templates/admin/src/components/theme/list/filter/SingleChoiceFilterMenu.tsx index 84bde2f4..355b8f3c 100644 --- a/templates/admin/src/components/theme/list/filter/SingleChoiceFilterMenu.tsx +++ b/templates/admin/src/components/theme/list/filter/SingleChoiceFilterMenu.tsx @@ -5,45 +5,9 @@ import MessageService from '../../../../i18n/messages/MessageService'; import { ObjectFilterProps, SingleChoiceObjectFilterMenuProps, - SingleChoiceRawFilterMenuProps + SingleChoiceRawFilterMenuProps, } from '../../../../lib/plume-admin-theme/list/filter/FilterProps'; -/** - * SingleObjectChoiceFilterMenu generates a single choice filter menu for a give object type - * @param filterMenuKey the key in translation file to be used - * @param onFilterValueClicked function executed when a checkbox is clicked - * @param filters The filters for the given type. - * Each filter must contain a key extractor of the given object - * Each filter must contain a key filter for identification - * @param rawList the whole given type list to be filtered - * @param selectedValue the map of the current selected value by the key filter - * @constructor - */ -export function SingleObjectChoiceFilterMenu( - { - filterMenuKey, - onFilterValueClicked, - filters, - rawList, - selectedValues - }: SingleChoiceObjectFilterMenuProps -) { - return ( - ) => ({ - filterKey: o.filterKey, - possibleValues: rawList.map(o.keyExtractor), - })) - } - selectedValues={selectedValues} - /> - ) -} - /** * SingleChoiceFilterMenu is a generic component for filtering in a list * @param filterMenuKey the key in translation file to be used @@ -55,19 +19,21 @@ export function SingleObjectChoiceFilterMenu( * @constructor */ function SingleChoiceFilterMenu( - { filterMenuKey, filters, onFilterValueClicked, selectedValues }: SingleChoiceRawFilterMenuProps + { + filterMenuKey, filters, onFilterValueClicked, selectedValues, + }: SingleChoiceRawFilterMenuProps, ) { const messages = getGlobalInstance(MessageService).t(); return (
-

{(messages['filter'] as any)[filterMenuKey]['title']}

+

{(messages.filter as any)[filterMenuKey].title}

{ filters.map((filterPossibility) => (
- {(messages['filter'] as any)[filterMenuKey][filterPossibility.filterKey]} + {(messages.filter as any)[filterMenuKey][filterPossibility.filterKey]} ) => { @@ -78,16 +44,15 @@ function SingleChoiceFilterMenu( { Array.from(new Set([...filterPossibility.possibleValues])) .map((value: string) => ( - - )} - /> - ) - ) + + )} + /> + )) }
@@ -95,7 +60,43 @@ function SingleChoiceFilterMenu( }
- ) + ); } -export default (SingleChoiceFilterMenu); \ No newline at end of file +export default (SingleChoiceFilterMenu); + +/** + * SingleObjectChoiceFilterMenu generates a single choice filter menu for a give object type + * @param filterMenuKey the key in translation file to be used + * @param onFilterValueClicked function executed when a checkbox is clicked + * @param filters The filters for the given type. + * Each filter must contain a key extractor of the given object + * Each filter must contain a key filter for identification + * @param rawList the whole given type list to be filtered + * @param selectedValue the map of the current selected value by the key filter + * @constructor + */ +export function SingleObjectChoiceFilterMenu( + { + filterMenuKey, + onFilterValueClicked, + filters, + rawList, + selectedValues, + }: SingleChoiceObjectFilterMenuProps, +) { + return ( + ) => ({ + filterKey: o.filterKey, + possibleValues: rawList.map(o.keyExtractor), + })) + } + selectedValues={selectedValues} + /> + ); +} diff --git a/templates/admin/src/lib/plume-admin-log-api/api/LogApiApi.ts b/templates/admin/src/lib/plume-admin-log-api/api/LogApiApi.ts index 6d251cb2..4fc93bd7 100644 --- a/templates/admin/src/lib/plume-admin-log-api/api/LogApiApi.ts +++ b/templates/admin/src/lib/plume-admin-log-api/api/LogApiApi.ts @@ -1,6 +1,8 @@ import { HttpMethod } from 'simple-http-request-builder'; import PlumeAdminHttpClient from '../../plume-admin-api/PlumeHttpClient'; -import { LogApiDetailsType, LogApiFilters, LogApiParams, LogApiTrimmed } from './LogApiTypes'; +import { + LogApiDetailsType, LogApiFilters, LogApiParams, LogApiTrimmed, +} from './LogApiTypes'; export default class LogApiApi { constructor(private readonly httpClient: PlumeAdminHttpClient) { @@ -17,7 +19,7 @@ export default class LogApiApi { ['apiName', apiParam.apiName || ''], ['url', apiParam.url || ''], ['startDate', apiParam.startDate || ''], - ['endDate', apiParam.endDate || ''] + ['endDate', apiParam.endDate || ''], ]) .execute(); } diff --git a/templates/admin/src/lib/plume-admin-log-api/api/LogApiTypes.ts b/templates/admin/src/lib/plume-admin-log-api/api/LogApiTypes.ts index 7494767a..443ad7c5 100644 --- a/templates/admin/src/lib/plume-admin-log-api/api/LogApiTypes.ts +++ b/templates/admin/src/lib/plume-admin-log-api/api/LogApiTypes.ts @@ -43,9 +43,9 @@ export type LogApiParams = { url?: string, startDate?: string, endDate?: string, -} +}; export type LogApiFilters = { apiNames: string[], statusCodes: number[], -} +}; diff --git a/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx b/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx index 0543f8fd..eafcb8ba 100644 --- a/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx +++ b/templates/admin/src/lib/plume-admin-log-api/components/LogApiList.tsx @@ -1,7 +1,6 @@ -import dayjs, { Dayjs } from 'dayjs'; +import { Dayjs } from 'dayjs'; import { getGlobalInstance } from 'plume-ts-di'; import React, { useEffect, useState } from 'react'; -import { useForm } from 'react-hook-form'; import { useHistory } from 'react-router-dom'; import { replaceValueForFilter } from '../../../components/theme/utils/FilterUtils'; import MessageService from '../../../i18n/messages/MessageService'; @@ -17,7 +16,7 @@ import LogApiTile from './LogApiTile'; type Props = { logApiPath: string, -} +}; function LogApiList({ logApiPath }: Props) { const messages = getGlobalInstance(MessageService).t(); @@ -25,21 +24,6 @@ function LogApiList({ logApiPath }: Props) { const logApiApi = getGlobalInstance(LogApiApi); const history = useHistory(); - const [logsApi, setLogsApi] = useState(); - const logsApiLoader = useLoader(); - const fetchLogsApi = () => logsApiLoader.monitor( - logApiApi - .fetchAll({ - method: selectedLogsApiFilters.get('method'), - statusCode: selectedLogsApiFilters.get('status_code'), - apiName: selectedLogsApiFilters.get('api_name'), - url: currentSearchBarFilter, - startDate: selectedStartDate?.startOf('day').toISOString(), - endDate: selectedEndDate?.endOf('day').toISOString(), - }) - .then(setLogsApi) - ); - // search bar const [currentSearchBarFilter, setCurrentSearchBarFilter] = useState(); @@ -54,7 +38,22 @@ function LogApiList({ logApiPath }: Props) { const logApiFiltersLoader = useLoader(); const fetchFilters = () => logApiFiltersLoader.monitor( logApiApi.fetchLogApiFilters() - .then(setLogsApiFilters) + .then(setLogsApiFilters), + ); + + const [logsApi, setLogsApi] = useState(); + const logsApiLoader = useLoader(); + const fetchLogsApi = () => logsApiLoader.monitor( + logApiApi + .fetchAll({ + method: selectedLogsApiFilters.get('method'), + statusCode: selectedLogsApiFilters.get('status_code'), + apiName: selectedLogsApiFilters.get('api_name'), + url: currentSearchBarFilter, + startDate: selectedStartDate?.startOf('day').toISOString(), + endDate: selectedEndDate?.endOf('day').toISOString(), + }) + .then(setLogsApi), ); useOnComponentMounted(() => { @@ -66,9 +65,7 @@ function LogApiList({ logApiPath }: Props) { fetchLogsApi(); }, [selectedLogsApiFilters, currentSearchBarFilter, selectedStartDate, selectedEndDate]); - const sortedList = () => { - return logsApi?.sort(currentLogsApiSorting.sortFunction) || []; - } + const sortedList = () => logsApi?.sort(currentLogsApiSorting.sortFunction) || []; return ( <> @@ -101,11 +98,11 @@ function LogApiList({ logApiPath }: Props) { filters={[ { filterKey: 'api_name', - possibleValues: logsApiFilters?.apiNames ?? [] + possibleValues: logsApiFilters?.apiNames ?? [], }, { filterKey: 'status_code', - possibleValues: logsApiFilters?.statusCodes?.map((status: number) => status.toString()) ?? [] + possibleValues: logsApiFilters?.statusCodes?.map((status: number) => status.toString()) ?? [], }, { filterKey: 'method', @@ -115,8 +112,8 @@ function LogApiList({ logApiPath }: Props) { 'PUT', 'PATCH', 'DELETE', - ] - } + ], + }, ]} onFilterValueClicked={(filterElementKey: string, valueSelected: string) => { setSelectedLogsApiFilters(replaceValueForFilter(filterElementKey, valueSelected, selectedLogsApiFilters)); @@ -140,14 +137,13 @@ function LogApiList({ logApiPath }: Props) { { React.Children.toArray( sortedList().map((logApi: LogApiTrimmed) => ( - { - history.push(`${logApiPath}/${logApi.id}`) - }} - /> - ) - ) + { + history.push(`${logApiPath}/${logApi.id}`); + }} + /> + )), ) }
diff --git a/templates/admin/src/lib/plume-admin-log-api/components/LogApiRangeSelector.tsx b/templates/admin/src/lib/plume-admin-log-api/components/LogApiRangeSelector.tsx index 29261996..f207dd58 100644 --- a/templates/admin/src/lib/plume-admin-log-api/components/LogApiRangeSelector.tsx +++ b/templates/admin/src/lib/plume-admin-log-api/components/LogApiRangeSelector.tsx @@ -10,22 +10,23 @@ import useDebounce from '../../react-hook-debounce/ReactHookDebounce'; type Props = { onStartDateChange: (date: Dayjs | null) => void, onEndDateChange: (date: Dayjs | null) => void, -} +}; function LogApiRangeSelector({ onStartDateChange, onEndDateChange }: Props) { const localeService = getGlobalInstance(LocaleService); const theme = getGlobalInstance(PlumeAdminTheme); const [dateRange, setDateRange] = useState>(); - useDebounce(() => { + useDebounce( + () => { if (dateRange) { onStartDateChange(dateRange[0]); onEndDateChange(dateRange[1]); } }, 1500, - [dateRange] - ) + [dateRange], + ); const { control, @@ -39,7 +40,7 @@ function LogApiRangeSelector({ onStartDateChange, onEndDateChange }: Props) { onDateChange={setDateRange} disableFuture /> - ) + ); } export default (LogApiRangeSelector); diff --git a/templates/admin/src/lib/plume-admin-log-api/components/LogApiTile.tsx b/templates/admin/src/lib/plume-admin-log-api/components/LogApiTile.tsx index 725c0b1b..bcbbd925 100644 --- a/templates/admin/src/lib/plume-admin-log-api/components/LogApiTile.tsx +++ b/templates/admin/src/lib/plume-admin-log-api/components/LogApiTile.tsx @@ -8,7 +8,8 @@ import { LogApiTrimmed } from '../api/LogApiTypes'; type Props = { logApi: LogApiTrimmed, onClick: () => void, -} +}; + export default function LogApiTile({ logApi, onClick }: Props) { const theme = getGlobalInstance(PlumeAdminTheme); @@ -20,7 +21,7 @@ export default function LogApiTile({ logApi, onClick }: Props) { return Status.WARN; } return Status.OK; - } + }; return ( - ) -} \ No newline at end of file + ); +} diff --git a/templates/admin/src/lib/plume-admin-log-api/pages/LogApi.tsx b/templates/admin/src/lib/plume-admin-log-api/pages/LogApi.tsx index 6b6c16ed..5aadd53a 100644 --- a/templates/admin/src/lib/plume-admin-log-api/pages/LogApi.tsx +++ b/templates/admin/src/lib/plume-admin-log-api/pages/LogApi.tsx @@ -1,17 +1,9 @@ import React from 'react'; import { Route, Switch, useRouteMatch } from 'react-router-dom'; -import PlumeAdminTheme from '../../plume-admin-theme/PlumeAdminTheme'; -import PlumeMessageResolver from '../../plume-messages/MessageResolver'; import LogApiList from '../components/LogApiList'; import LogApiDetails from './LogApiDetails'; class LogApi { - constructor( - private readonly theme: PlumeAdminTheme, - private readonly messages: PlumeMessageResolver, - ) { - } - render = () => { const { path } = useRouteMatch(); @@ -28,8 +20,8 @@ class LogApi {
- ) - } + ); + }; } export default (LogApi); diff --git a/templates/admin/src/lib/plume-admin-log-api/pages/LogApiDetails.tsx b/templates/admin/src/lib/plume-admin-log-api/pages/LogApiDetails.tsx index 94d554cf..5361815a 100644 --- a/templates/admin/src/lib/plume-admin-log-api/pages/LogApiDetails.tsx +++ b/templates/admin/src/lib/plume-admin-log-api/pages/LogApiDetails.tsx @@ -68,7 +68,7 @@ function LogApiDetails({ logApiPath }: Props) { && logApiDetail && ( -
+ {}}> { return dayjs(a.date).diff(dayjs(b.date)); - } -} + }, +}; export const DATE_ASC: SortElementProps = { sortKey: 'DATE_ASC', sortFunction: (a: LogApiTrimmed, b: LogApiTrimmed) => { return dayjs(b.date).diff(dayjs(a.date)); - } -} + }, +}; export default function logsApiSortsList() { return [DATE_DESC, DATE_ASC]; diff --git a/templates/admin/yarn.lock b/templates/admin/yarn.lock index 42ebf366..f0a0f761 100644 --- a/templates/admin/yarn.lock +++ b/templates/admin/yarn.lock @@ -847,6 +847,15 @@ __metadata: languageName: node linkType: hard +"@babel/runtime@npm:^7.17.2": + version: 7.17.9 + resolution: "@babel/runtime@npm:7.17.9" + dependencies: + regenerator-runtime: ^0.13.4 + checksum: 4d56bdb82890f386d5a57c40ef985a0ed7f0a78f789377a2d0c3e8826819e0f7f16ba0fe906d9b2241c5f7ca56630ef0653f5bb99f03771f7b87ff8af4bf5fe3 + languageName: node + linkType: hard + "@babel/template@npm:^7.12.13, @babel/template@npm:^7.3.3": version: 7.12.13 resolution: "@babel/template@npm:7.12.13" @@ -995,6 +1004,69 @@ __metadata: languageName: node linkType: hard +"@date-io/core@npm:^2.13.1": + version: 2.13.1 + resolution: "@date-io/core@npm:2.13.1" + checksum: e998454687af579f3172d2b376ea4efedb47ca13ffac3899608c72b59aadf68d461bb07e1a3d67b90c554b42d3b4ddd8d23be5c9b60281d785f740736fa34fb9 + languageName: node + linkType: hard + +"@date-io/date-fns@npm:^2.10.6": + version: 2.13.1 + resolution: "@date-io/date-fns@npm:2.13.1" + dependencies: + "@date-io/core": ^2.13.1 + peerDependencies: + date-fns: ^2.0.0 + peerDependenciesMeta: + date-fns: + optional: true + checksum: 753e37e30537be02adf83583be102d30d5b00d09d8639f8ac26f5ee167d5a52ae156fb0b190466c66ce78680e74a46fb9ae890d12a8f4338c771207d21a0f3c3 + languageName: node + linkType: hard + +"@date-io/dayjs@npm:^2.10.6": + version: 2.13.1 + resolution: "@date-io/dayjs@npm:2.13.1" + dependencies: + "@date-io/core": ^2.13.1 + peerDependencies: + dayjs: ^1.8.17 + peerDependenciesMeta: + dayjs: + optional: true + checksum: c4f264bcae32eede7062627202abb52bf8f07102e7108f8477a9af18bf869d3904c8818d0b80146ee6eacbeeace7fa6842d534da4af9c998f86c00f30866ab11 + languageName: node + linkType: hard + +"@date-io/luxon@npm:^2.10.6": + version: 2.13.1 + resolution: "@date-io/luxon@npm:2.13.1" + dependencies: + "@date-io/core": ^2.13.1 + peerDependencies: + luxon: ^1.21.3 || ^2.x + peerDependenciesMeta: + luxon: + optional: true + checksum: 359b0548d1de022759bb7f763ad0a8c9dfde7da35714ddc101d903088cf714e4117481c1fbd256d1893750e7bec615de6dcc108599e4e4d6597a1a98a67bcfa1 + languageName: node + linkType: hard + +"@date-io/moment@npm:^2.10.6": + version: 2.13.1 + resolution: "@date-io/moment@npm:2.13.1" + dependencies: + "@date-io/core": ^2.13.1 + peerDependencies: + moment: ^2.24.0 + peerDependenciesMeta: + moment: + optional: true + checksum: 815d8fe6c600f0b77844cd591de7517c6d1feaf5d9331657ccc0dc5d096954e276d41e7947881eefbf796fb5da333ddb708f3c8851197d49968b1077e2cdeed3 + languageName: node + linkType: hard + "@emotion/babel-plugin@npm:^11.3.0": version: 11.3.0 resolution: "@emotion/babel-plugin@npm:11.3.0" @@ -1030,16 +1102,16 @@ __metadata: languageName: node linkType: hard -"@emotion/cache@npm:^11.5.0": - version: 11.5.0 - resolution: "@emotion/cache@npm:11.5.0" +"@emotion/cache@npm:^11.7.1": + version: 11.7.1 + resolution: "@emotion/cache@npm:11.7.1" dependencies: "@emotion/memoize": ^0.7.4 - "@emotion/sheet": ^1.0.3 + "@emotion/sheet": ^1.1.0 "@emotion/utils": ^1.0.0 "@emotion/weak-memoize": ^0.2.5 - stylis: ^4.0.10 - checksum: 8b3fac281ea201d617b594d79e4b38903ee538e9aa2117f3f99a4f952b3f93d92659a569b3b934efa31ae450b2ddd9ae435b6c77db70aa99ac8cae4cbd71450b + stylis: 4.0.13 + checksum: cf7aa8fe3bacfdedcda94b53e76a7635e122043439715fcfbf7f1a81340cfe6099a59134481a03ec3e0437466566d18528577d1e6ea92f5b98c372b8b38a8f35 languageName: node linkType: hard @@ -1059,6 +1131,15 @@ __metadata: languageName: node linkType: hard +"@emotion/is-prop-valid@npm:^1.1.2": + version: 1.1.2 + resolution: "@emotion/is-prop-valid@npm:1.1.2" + dependencies: + "@emotion/memoize": ^0.7.4 + checksum: 58b1f2d429a589f8f5bc2c33a8732cbb7bbcb17131a103511ef9a94ac754d7eeb53d627f947da480cd977f9d419fd92e244991680292f3287204159652745707 + languageName: node + linkType: hard + "@emotion/memoize@npm:^0.7.4, @emotion/memoize@npm:^0.7.5": version: 0.7.5 resolution: "@emotion/memoize@npm:0.7.5" @@ -1116,10 +1197,10 @@ __metadata: languageName: node linkType: hard -"@emotion/sheet@npm:^1.0.3": - version: 1.0.3 - resolution: "@emotion/sheet@npm:1.0.3" - checksum: 43a9b9a0e4261d40c02907bbea4d19e7c75d102fbd04e55a94e025b26b7a78bb499c2f76c9a0bd94f36bee0b0219006ab26a1ebb9eb4cbb30f2925313de30b61 +"@emotion/sheet@npm:^1.1.0": + version: 1.1.0 + resolution: "@emotion/sheet@npm:1.1.0" + checksum: a4b74e16a8fea1157413efe4904f5f679d724323cb605d66d20a0b98744422f5d411fca927ceb52e4de454a0a819c5273ca9496db9f011b4ecd17b9f1b212007 languageName: node linkType: hard @@ -1449,14 +1530,36 @@ __metadata: languageName: node linkType: hard -"@mui/core@npm:5.0.0-alpha.53": - version: 5.0.0-alpha.53 - resolution: "@mui/core@npm:5.0.0-alpha.53" +"@mui/base@npm:5.0.0-alpha.78": + version: 5.0.0-alpha.78 + resolution: "@mui/base@npm:5.0.0-alpha.78" + dependencies: + "@babel/runtime": ^7.17.2 + "@emotion/is-prop-valid": ^1.1.2 + "@mui/types": ^7.1.3 + "@mui/utils": ^5.6.1 + "@popperjs/core": ^2.11.5 + clsx: ^1.1.1 + prop-types: ^15.7.2 + react-is: ^17.0.2 + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: f0c3d29c6baa5e696f70c54f3c8f50e6426ce8af904472eb04aea346100b485cc500baaa2390093b79a1339b7adea18e2435ffa387dab5160dcfb113b5aecc16 + languageName: node + linkType: hard + +"@mui/core@npm:5.0.0-alpha.49": + version: 5.0.0-alpha.49 + resolution: "@mui/core@npm:5.0.0-alpha.49" dependencies: "@babel/runtime": ^7.15.4 "@emotion/is-prop-valid": ^1.1.0 "@mui/utils": ^5.0.1 - "@popperjs/core": ^2.4.4 clsx: ^1.1.1 prop-types: ^15.7.2 react-is: ^17.0.2 @@ -1467,22 +1570,63 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 7c5ef0e1a34736ff91a76bf39f9075d25f49b88a059b78e56cefc6843bf15bca3a7b027291fe166dc45e0c68962c4a86baf688020a0e52d6eef4bacb445e6892 + checksum: cc2718df0555be2e5269666252471037cc9651ca0c63219e5cd89cfd7ff83c1c3960a4e1dca57806e2ebaafb8e700fc42ae5c6680d710d2cae09492822ac7d2a languageName: node linkType: hard -"@mui/material@npm:^5.0.6": - version: 5.0.6 - resolution: "@mui/material@npm:5.0.6" +"@mui/lab@npm:5.0.0-alpha.49": + version: 5.0.0-alpha.49 + resolution: "@mui/lab@npm:5.0.0-alpha.49" dependencies: "@babel/runtime": ^7.15.4 - "@mui/core": 5.0.0-alpha.53 - "@mui/system": ^5.0.6 - "@mui/types": ^7.0.0 + "@date-io/date-fns": ^2.10.6 + "@date-io/dayjs": ^2.10.6 + "@date-io/luxon": ^2.10.6 + "@date-io/moment": ^2.10.6 + "@mui/core": 5.0.0-alpha.49 + "@mui/system": ^5.0.2 "@mui/utils": ^5.0.1 + clsx: ^1.1.1 + prop-types: ^15.7.2 + react-is: ^17.0.2 + react-transition-group: ^4.4.2 + rifm: ^0.12.0 + peerDependencies: + "@mui/material": ^5.0.0-rc.0 + "@types/react": ^16.8.6 || ^17.0.0 + date-fns: ^2.24.0 + dayjs: ^1.10.7 + luxon: ^1.28.0 + moment: ^2.29.1 + react: ^17.0.2 + react-dom: ^17.0.2 + peerDependenciesMeta: + "@types/react": + optional: true + date-fns: + optional: true + dayjs: + optional: true + luxon: + optional: true + moment: + optional: true + checksum: 6f7df51cdb38873f4b18e8d83ba0c4df82bb0e0a2d80ae0db0158888ec2db334d2eec35bf0b7148011ed108f8ed56044c3624566e2c9d1ab3bcba502eb1dd254 + languageName: node + linkType: hard + +"@mui/material@npm:^5.0.6": + version: 5.6.3 + resolution: "@mui/material@npm:5.6.3" + dependencies: + "@babel/runtime": ^7.17.2 + "@mui/base": 5.0.0-alpha.78 + "@mui/system": ^5.6.3 + "@mui/types": ^7.1.3 + "@mui/utils": ^5.6.1 "@types/react-transition-group": ^4.4.4 clsx: ^1.1.1 - csstype: ^3.0.9 + csstype: ^3.0.11 hoist-non-react-statics: ^3.3.2 prop-types: ^15.7.2 react-is: ^17.0.2 @@ -1490,9 +1634,9 @@ __metadata: peerDependencies: "@emotion/react": ^11.5.0 "@emotion/styled": ^11.3.0 - "@types/react": ^16.8.6 || ^17.0.0 - react: ^17.0.2 - react-dom: ^17.0.2 + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 peerDependenciesMeta: "@emotion/react": optional: true @@ -1500,7 +1644,7 @@ __metadata: optional: true "@types/react": optional: true - checksum: 79385beadfb13903f7c46a31bf014be69b85c5acceec3d682d8b772576b057dab37d0f56d41396576b58ffadabaace2cbf1daaab2203e0fc721e056bd63dd654 + checksum: d81f2870fc08458ce7bb02fb07adc165eb97e99380d141af75cbc4829fbb2d7ebe4d8d46821dc2e85b491bc2e7e5b3435f168289e3a419107f98d4d63029827f languageName: node linkType: hard @@ -1521,23 +1665,40 @@ __metadata: languageName: node linkType: hard -"@mui/styled-engine@npm:^5.0.2": - version: 5.0.2 - resolution: "@mui/styled-engine@npm:5.0.2" +"@mui/private-theming@npm:^5.6.2": + version: 5.6.2 + resolution: "@mui/private-theming@npm:5.6.2" dependencies: - "@babel/runtime": ^7.15.4 - "@emotion/cache": ^11.5.0 + "@babel/runtime": ^7.17.2 + "@mui/utils": ^5.6.1 + prop-types: ^15.7.2 + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 6fa6c16c52255203123a83e9c50e9f5eac70c4b749f32157fbd6a2f7c12716dda5128bc830476a7e39e356a4a4cf2343d84c72d72979ab17aa924a4afb6c41a4 + languageName: node + linkType: hard + +"@mui/styled-engine@npm:^5.6.1": + version: 5.6.1 + resolution: "@mui/styled-engine@npm:5.6.1" + dependencies: + "@babel/runtime": ^7.17.2 + "@emotion/cache": ^11.7.1 prop-types: ^15.7.2 peerDependencies: "@emotion/react": ^11.4.1 "@emotion/styled": ^11.3.0 - react: ^17.0.2 + react: ^17.0.0 || ^18.0.0 peerDependenciesMeta: "@emotion/react": optional: true "@emotion/styled": optional: true - checksum: 3d64edbcc9e0dbcdf70da4c71e1a517599987b53025b4f3b795e8ea0d907037055c8cfcb9cf06176c3b96cb8d888e7a74ceff80279ad3ec4fdfa0bcf38591195 + checksum: cd17d05902118d5cab20e321a2a8240de3be00454b7dfbce9cfb81404a7b3d996ad6b7de19dbf5fcfc7ee7a0f7acd80fc779830af1d2787914fb1b42408b4904 languageName: node linkType: hard @@ -1572,23 +1733,51 @@ __metadata: languageName: node linkType: hard -"@mui/system@npm:^5.0.6": - version: 5.0.6 - resolution: "@mui/system@npm:5.0.6" +"@mui/system@npm:^5.0.2": + version: 5.6.4 + resolution: "@mui/system@npm:5.6.4" dependencies: - "@babel/runtime": ^7.15.4 - "@mui/private-theming": ^5.0.1 - "@mui/styled-engine": ^5.0.2 - "@mui/types": ^7.0.0 - "@mui/utils": ^5.0.1 + "@babel/runtime": ^7.17.2 + "@mui/private-theming": ^5.6.2 + "@mui/styled-engine": ^5.6.1 + "@mui/types": ^7.1.3 + "@mui/utils": ^5.6.1 clsx: ^1.1.1 - csstype: ^3.0.9 + csstype: ^3.0.11 prop-types: ^15.7.2 peerDependencies: "@emotion/react": ^11.5.0 "@emotion/styled": ^11.3.0 - "@types/react": ^16.8.6 || ^17.0.0 - react: ^17.0.2 + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + "@emotion/react": + optional: true + "@emotion/styled": + optional: true + "@types/react": + optional: true + checksum: c483afd137ffa51a06f039c11df9370eec9522770d0264e7a06d0937e404c32e3b96cde660ed55d9f6efba1a1bee3472d767e5f9fdeaa610ce25def40d424659 + languageName: node + linkType: hard + +"@mui/system@npm:^5.0.6, @mui/system@npm:^5.6.3": + version: 5.6.3 + resolution: "@mui/system@npm:5.6.3" + dependencies: + "@babel/runtime": ^7.17.2 + "@mui/private-theming": ^5.6.2 + "@mui/styled-engine": ^5.6.1 + "@mui/types": ^7.1.3 + "@mui/utils": ^5.6.1 + clsx: ^1.1.1 + csstype: ^3.0.11 + prop-types: ^15.7.2 + peerDependencies: + "@emotion/react": ^11.5.0 + "@emotion/styled": ^11.3.0 + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 peerDependenciesMeta: "@emotion/react": optional: true @@ -1596,7 +1785,7 @@ __metadata: optional: true "@types/react": optional: true - checksum: 8d0df5c0f0a6f0fcc86085d1adc32144d6723f398a52ae62df6bda73a1bee2c8a208ed5edf0a52ddd8199c2859e32e6cab173fe3145c27f8e28ea5f7327dae80 + checksum: 63e119b46c829b5ec6c6a2628ca309a9f17e0f0e3123ee7d9a7a57fe838c59e5efdafc5993a7e8c91168722c0618f63eff66afa3b7f61f92bfd8e872fdcf4773 languageName: node linkType: hard @@ -1612,6 +1801,18 @@ __metadata: languageName: node linkType: hard +"@mui/types@npm:^7.1.3": + version: 7.1.3 + resolution: "@mui/types@npm:7.1.3" + peerDependencies: + "@types/react": "*" + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 4990f505f1058bdd4c01ea21a6a6f788e5d3ff73b50962879d33bbf9c98ef1f18d8b6664025ce1dbd42544a79d7697d0011834f8fd83d12c9705f2c702829bb4 + languageName: node + linkType: hard + "@mui/utils@npm:^5.0.1": version: 5.0.1 resolution: "@mui/utils@npm:5.0.1" @@ -1627,6 +1828,21 @@ __metadata: languageName: node linkType: hard +"@mui/utils@npm:^5.6.1": + version: 5.6.1 + resolution: "@mui/utils@npm:5.6.1" + dependencies: + "@babel/runtime": ^7.17.2 + "@types/prop-types": ^15.7.4 + "@types/react-is": ^16.7.1 || ^17.0.0 + prop-types: ^15.7.2 + react-is: ^17.0.2 + peerDependencies: + react: ^17.0.0 || ^18.0.0 + checksum: b05c57263e63d4f518ee416760114cfecfe3bdf23491cf277a69fedc47d00db52e799d90a384854a81d936bbaa7ea9907e4978ebd1c181305c5c2d19818d0b7c + languageName: node + linkType: hard + "@nodelib/fs.scandir@npm:2.1.4": version: 2.1.4 resolution: "@nodelib/fs.scandir@npm:2.1.4" @@ -1664,10 +1880,10 @@ __metadata: languageName: node linkType: hard -"@popperjs/core@npm:^2.4.4": - version: 2.9.1 - resolution: "@popperjs/core@npm:2.9.1" - checksum: fdb99e740307dbb9535be1e923ad06ea38ed8daf3e1f4555d3dfa07402d15e06ea2e02ea001ba68198c9d6cd4d7a3d4fb5146a13cf34ca451a2fe29b1c745cd1 +"@popperjs/core@npm:^2.11.5": + version: 2.11.5 + resolution: "@popperjs/core@npm:2.11.5" + checksum: fd7f9dca3fb716d7426332b6ee283f88d2724c0ab342fb678865a640bad403dfb9eeebd8204a406986162f7e2b33394f104320008b74d0e9066d7322f70ea35d languageName: node linkType: hard @@ -3409,6 +3625,13 @@ __metadata: languageName: node linkType: hard +"csstype@npm:^3.0.11": + version: 3.0.11 + resolution: "csstype@npm:3.0.11" + checksum: 95e56abfe9ca219ae065acb4e43f61771a03170eed919127f558dfa168240867aba7629c8d98a201a0dd06d9a5ce82686f0570031c928516c61816adbc7c877f + languageName: node + linkType: hard + "csstype@npm:^3.0.2": version: 3.0.7 resolution: "csstype@npm:3.0.7" @@ -8208,6 +8431,15 @@ resolve@^2.0.0-next.3: languageName: node linkType: hard +"rifm@npm:^0.12.0": + version: 0.12.1 + resolution: "rifm@npm:0.12.1" + peerDependencies: + react: ">=16.8" + checksum: 7f11621b6a14885bdee0b49c21174627272a5f683f74aaf8444570dae319f86de38d2af55c17e08af1ebb837bf956894971cceadeaca890e4c9cd1d46f02a385 + languageName: node + linkType: hard + "rimraf@npm:^3.0.0, rimraf@npm:^3.0.2": version: 3.0.2 resolution: "rimraf@npm:3.0.2" @@ -8878,10 +9110,10 @@ resolve@^2.0.0-next.3: languageName: node linkType: hard -"stylis@npm:^4.0.10": - version: 4.0.10 - resolution: "stylis@npm:4.0.10" - checksum: 0fecaf5c234ec3ffcb0afc21478742a815a21cb964365259789be9c1692e72e13d8c081c1150fd76ed2146633a3251cdecd6e0c120b158f44bd74c38f81cafb3 +"stylis@npm:4.0.13": + version: 4.0.13 + resolution: "stylis@npm:4.0.13" + checksum: 8ea7a87028b6383c6a982231c4b5b6150031ce028e0fdaf7b2ace82253d28a8af50cc5a9da8a421d3c7c4441592f393086e332795add672aa4a825f0fe3713a3 languageName: node linkType: hard @@ -9129,6 +9361,7 @@ resolve@^2.0.0-next.3: "@emotion/react": ^11.4.1 "@emotion/styled": ^11.3.0 "@fontsource/roboto": ^4.5.0 + "@mui/lab": 5.0.0-alpha.49 "@mui/material": ^5.0.6 "@mui/styles": ^5.0.2 "@mui/system": ^5.0.6 From 568b4336f10dd348e28c2ffd7543e8afb705dad2 Mon Sep 17 00:00:00 2001 From: Lucas Amiaud Date: Wed, 25 May 2022 18:20:43 +0200 Subject: [PATCH 16/19] add readonly props on inputs --- .../theme/form/fields/InputText.tsx | 6 ++- .../pages/LogApiDetails.tsx | 48 ++++++++++++++----- .../plume-admin-theme/form/FormInputProps.ts | 1 + 3 files changed, 41 insertions(+), 14 deletions(-) diff --git a/templates/admin/src/components/theme/form/fields/InputText.tsx b/templates/admin/src/components/theme/form/fields/InputText.tsx index 9627167a..58020446 100644 --- a/templates/admin/src/components/theme/form/fields/InputText.tsx +++ b/templates/admin/src/components/theme/form/fields/InputText.tsx @@ -13,6 +13,7 @@ export default function InputText( control, rules, disabled, + readonly, defaultValue, onChange, onBlur, @@ -61,7 +62,10 @@ export default function InputText( inputRef={field.ref} onChange={onChangeCombined} onBlur={onBlurCombined} - inputProps={{ onWheel: (e: any) => e.target.blur() }} + inputProps={{ + onWheel: (e: any) => e.target.blur(), + readOnly: readonly ?? false, + }} multiline={multiline} rows={rows} /> diff --git a/templates/admin/src/lib/plume-admin-log-api/pages/LogApiDetails.tsx b/templates/admin/src/lib/plume-admin-log-api/pages/LogApiDetails.tsx index 5361815a..15147bd9 100644 --- a/templates/admin/src/lib/plume-admin-log-api/pages/LogApiDetails.tsx +++ b/templates/admin/src/lib/plume-admin-log-api/pages/LogApiDetails.tsx @@ -1,6 +1,6 @@ import dayjs from 'dayjs'; import { getGlobalInstance } from 'plume-ts-di'; -import React, { useEffect, useState } from 'react'; +import React, { FormEvent, useEffect, useState } from 'react'; import { useForm } from 'react-hook-form'; import { useHistory, useParams } from 'react-router-dom'; import PlumeAdminTheme from '../../plume-admin-theme/PlumeAdminTheme'; @@ -31,8 +31,8 @@ function LogApiDetails({ logApiPath }: Props) { const fetchLogById = () => { logApiLoader.monitor( logApiApi.fetchById(logApiId) - .then(setLogApiDetail) - ) + .then(setLogApiDetail), + ); }; useOnComponentMounted(() => { @@ -41,25 +41,25 @@ function LogApiDetails({ logApiPath }: Props) { const { control, - reset + reset, } = useForm(); useEffect(() => { reset(logApiDetail); - }, [logApiDetail]) + }, [logApiDetail]); return ( { - history.push(logApiPath) + history.push(logApiPath); }} > { logApiLoader.isLoading && (
- Loding + Loading
) } @@ -68,7 +68,7 @@ function LogApiDetails({ logApiPath }: Props) { && logApiDetail && ( - {}}> + ) => e.preventDefault()}> + + + + + + @@ -115,7 +137,7 @@ function LogApiDetails({ logApiPath }: Props) {
diff --git a/templates/admin/src/lib/plume-admin-theme/form/FormInputProps.ts b/templates/admin/src/lib/plume-admin-theme/form/FormInputProps.ts index 500df381..0dcee03b 100644 --- a/templates/admin/src/lib/plume-admin-theme/form/FormInputProps.ts +++ b/templates/admin/src/lib/plume-admin-theme/form/FormInputProps.ts @@ -11,6 +11,7 @@ export type InputTextProps = { useNameAsId?: boolean; autoComplete?: string; disabled?: boolean; + readonly?: boolean; defaultValue?: string; rules?: Exclude; control: Control; From c2be5eab73cb19840957fd2fe877283d47727790 Mon Sep 17 00:00:00 2001 From: Lucas Amiaud Date: Tue, 14 Jun 2022 16:37:24 +0200 Subject: [PATCH 17/19] eslint fix --- .../lib/plume-admin-log-api/api/LogApiTypes.ts | 4 ++-- .../plume-admin-log-api/pages/LogApiDetails.tsx | 2 +- .../plume-admin-log-api/pages/LogsApiSort.ts | 17 +++++++++++------ .../react-hook-debounce/ReactHookDebounce.ts | 3 ++- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/templates/admin/src/lib/plume-admin-log-api/api/LogApiTypes.ts b/templates/admin/src/lib/plume-admin-log-api/api/LogApiTypes.ts index 443ad7c5..00ab5665 100644 --- a/templates/admin/src/lib/plume-admin-log-api/api/LogApiTypes.ts +++ b/templates/admin/src/lib/plume-admin-log-api/api/LogApiTypes.ts @@ -13,12 +13,12 @@ export type LogHeader = { name: string, type: string, value: string, -} +}; export type HttpHeaders = { headers: LogHeader[], mimeType: string, -} +}; export type LogApiDetailsType = { id: string, diff --git a/templates/admin/src/lib/plume-admin-log-api/pages/LogApiDetails.tsx b/templates/admin/src/lib/plume-admin-log-api/pages/LogApiDetails.tsx index 15147bd9..ecd8ade2 100644 --- a/templates/admin/src/lib/plume-admin-log-api/pages/LogApiDetails.tsx +++ b/templates/admin/src/lib/plume-admin-log-api/pages/LogApiDetails.tsx @@ -12,7 +12,7 @@ import { LogApiDetailsType } from '../api/LogApiTypes'; type Props = { logApiPath: string, -} +}; type LogApiRouteParams = { logApiId: string, diff --git a/templates/admin/src/lib/plume-admin-log-api/pages/LogsApiSort.ts b/templates/admin/src/lib/plume-admin-log-api/pages/LogsApiSort.ts index 9d4e26b3..c6f1a68a 100644 --- a/templates/admin/src/lib/plume-admin-log-api/pages/LogsApiSort.ts +++ b/templates/admin/src/lib/plume-admin-log-api/pages/LogsApiSort.ts @@ -1,19 +1,24 @@ import dayjs from 'dayjs'; +import { createCustomCompareSorting } from '../../../components/theme/utils/SortUtils'; import { SortElementProps } from '../../plume-admin-theme/list/sort/SortProps'; import { LogApiTrimmed } from '../api/LogApiTypes'; export const DATE_DESC: SortElementProps = { sortKey: 'DATE_DESC', - sortFunction: (a: LogApiTrimmed, b: LogApiTrimmed) => { - return dayjs(a.date).diff(dayjs(b.date)); - }, + sortFunction: createCustomCompareSorting( + (logApi: LogApiTrimmed) => logApi.date, + false, + (a, b) => dayjs(a).diff(dayjs(b)), + ), }; export const DATE_ASC: SortElementProps = { sortKey: 'DATE_ASC', - sortFunction: (a: LogApiTrimmed, b: LogApiTrimmed) => { - return dayjs(b.date).diff(dayjs(a.date)); - }, + sortFunction: createCustomCompareSorting( + (logApi: LogApiTrimmed) => logApi.date, + true, + (a, b) => dayjs(a).diff(dayjs(b)), + ), }; export default function logsApiSortsList() { diff --git a/templates/admin/src/lib/react-hook-debounce/ReactHookDebounce.ts b/templates/admin/src/lib/react-hook-debounce/ReactHookDebounce.ts index 62658575..b33b9969 100644 --- a/templates/admin/src/lib/react-hook-debounce/ReactHookDebounce.ts +++ b/templates/admin/src/lib/react-hook-debounce/ReactHookDebounce.ts @@ -1,8 +1,9 @@ import { useEffect } from 'react'; import useTimeout from '../plume-http-react-hook-loader/timeoutHook'; +/* eslint-disable-next-line @typescript-eslint/no-explicit-any */ export default function useDebounce(callback: () => void, delay: number, dependencies: any[]) { const { restartTimeout, stopTimeout } = useTimeout(callback, delay); useEffect(restartTimeout, [...dependencies, restartTimeout]); useEffect(stopTimeout, []); -} \ No newline at end of file +} From 1f5a056f03a47e3b8d9a84b431dff452b2b19dd2 Mon Sep 17 00:00:00 2001 From: Lucas Amiaud Date: Tue, 14 Jun 2022 16:46:05 +0200 Subject: [PATCH 18/19] eslint fix --- templates/admin/src/components/theme/AdminTheme.ts | 2 +- .../theme/list/filter/SingleChoiceFilterMenu.tsx | 2 ++ .../admin/src/lib/plume-admin-theme/PlumeAdminTheme.ts | 10 +++------- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/templates/admin/src/components/theme/AdminTheme.ts b/templates/admin/src/components/theme/AdminTheme.ts index ee551114..32630670 100644 --- a/templates/admin/src/components/theme/AdminTheme.ts +++ b/templates/admin/src/components/theme/AdminTheme.ts @@ -13,7 +13,7 @@ import PageTitle from './layout/PageTitle'; import { Panel, PanelSeparator } from './layout/Panel'; import StatusDot from './layout/StatusDot'; import MultipleChoiceFilterMenu, { MultipleChoiceObjectFilterMenu } from './list/filter/MultipleChoiceFilterMenu'; -import SingleChoiceFilterMenu, { SingleObjectChoiceFilterMenu, } from './list/filter/SingleChoiceFilterMenu'; +import SingleChoiceFilterMenu, { SingleObjectChoiceFilterMenu } from './list/filter/SingleChoiceFilterMenu'; import { ListElements, ListSingleElement } from './list/ListElements'; import ListHeader from './list/ListHeader'; import SearchBar from './list/search/SearchBar'; diff --git a/templates/admin/src/components/theme/list/filter/SingleChoiceFilterMenu.tsx b/templates/admin/src/components/theme/list/filter/SingleChoiceFilterMenu.tsx index 355b8f3c..26554a6c 100644 --- a/templates/admin/src/components/theme/list/filter/SingleChoiceFilterMenu.tsx +++ b/templates/admin/src/components/theme/list/filter/SingleChoiceFilterMenu.tsx @@ -27,12 +27,14 @@ function SingleChoiceFilterMenu( return (
+ {/* eslint-disable-next-line @typescript-eslint/no-explicit-any */}

{(messages.filter as any)[filterMenuKey].title}

{ filters.map((filterPossibility) => (
+ {/* eslint-disable-next-line @typescript-eslint/no-explicit-any */} {(messages.filter as any)[filterMenuKey][filterPossibility.filterKey]} Date: Tue, 17 Oct 2023 15:36:35 +0200 Subject: [PATCH 19/19] Merge branch 'evol/drawer' into evol/log-api --- templates/admin/src/lib/plume-admin-log-api/pages/LogApi.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/templates/admin/src/lib/plume-admin-log-api/pages/LogApi.tsx b/templates/admin/src/lib/plume-admin-log-api/pages/LogApi.tsx index 7e989951..eb75a59f 100644 --- a/templates/admin/src/lib/plume-admin-log-api/pages/LogApi.tsx +++ b/templates/admin/src/lib/plume-admin-log-api/pages/LogApi.tsx @@ -13,7 +13,6 @@ class LogApi { render = () => { const logApiPath: string = '/log-api'; - this.theme; return (