add labels

This commit is contained in:
Simon Larsen 2022-07-19 10:07:09 +01:00
parent 2d9b696b6b
commit d005541a81
No known key found for this signature in database
GPG Key ID: AB45983AA9C81CDE
10 changed files with 139 additions and 22 deletions

View File

@ -0,0 +1,10 @@
import PostgresDatabase from '../Infrastructure/PostgresDatabase';
import Model from 'Common/Models/Label';
import DatabaseService from './DatabaseService';
export class Service extends DatabaseService<Model> {
public constructor(postgresDatabase?: PostgresDatabase) {
super(Model, postgresDatabase);
}
}
export default new Service();

View File

@ -123,19 +123,19 @@ const init: Function = async (appName: string): Promise<ExpressApplication> => {
);
app.post('*', (_req: ExpressRequest, res: ExpressResponse) => {
res.status(404).json({ error: 'API not found' });
res.status(404).json({ error: '404 - Not Found.' });
});
app.put('*', (_req: ExpressRequest, res: ExpressResponse) => {
res.status(404).json({ error: 'API not found' });
res.status(404).json({ error: '404 - Not Found.' });
});
app.delete('*', (_req: ExpressRequest, res: ExpressResponse) => {
res.status(404).json({ error: 'API not found' });
res.status(404).json({ error: '404 - Not Found.' });
});
app.get('*', (_req: ExpressRequest, res: ExpressResponse) => {
res.status(404).json({ error: 'API not found' });
res.status(404).json({ error: '404 - Not Found.' });
});
// await OpenTelemetrySDK.start();

View File

@ -1,10 +1,11 @@
import React, { FunctionComponent, ReactElement } from 'react';
import React, { CSSProperties, FunctionComponent, ReactElement } from 'react';
export interface ComponentProps {
title: string;
description: string;
buttons?: Array<ReactElement>;
children?: Array<ReactElement> | ReactElement;
cardBodyStyle?: CSSProperties
}
const Card: FunctionComponent<ComponentProps> = (
@ -27,7 +28,7 @@ const Card: FunctionComponent<ComponentProps> = (
<div>{props.buttons}</div>
</div>
{props.children && (
<div className="card-body">{props.children}</div>
<div className="card-body" style={props.cardBodyStyle || {}}>{props.children}</div>
)}
</div>
</div>

View File

@ -35,7 +35,7 @@ enum ModalType {
Create, Edit
}
const ModalTable: Function = <TBaseModel extends BaseModel>(
const ModelTable: Function = <TBaseModel extends BaseModel>(
props: ComponentProps<TBaseModel>
): ReactElement => {
@ -44,7 +44,7 @@ const ModalTable: Function = <TBaseModel extends BaseModel>(
const [data, setData] = useState<Array<TBaseModel>>([]);
const [currentPageNumber, setCurrentPageNumber] = useState<number>(1);
const [totalItemsCount, setTotalItemsCount] = useState<number>(1);
const [totalItemsCount, setTotalItemsCount] = useState<number>(0);
const [isLoading, setIsLaoding] = useState<boolean>(false);
const [error, setError] = useState<string>('');
const [showModel, setShowModal] = useState<boolean>(false);
@ -111,12 +111,15 @@ const ModalTable: Function = <TBaseModel extends BaseModel>(
}
fetchItems();
}, []);
return (
<>
<Card {...props.cardProps}>
<Card {...props.cardProps} cardBodyStyle={{"padding": "0px"}}>
<Table
singularLabel={model.singularName || 'Item'}
pluralLabel={model.pluralName || 'Items'}
error={error}
currentPageNumber={currentPageNumber}
isLoading={isLoading}
@ -129,6 +132,9 @@ const ModalTable: Function = <TBaseModel extends BaseModel>(
onNavigateToPage={(pageNumber: number) => {
setCurrentPageNumber(pageNumber);
}}
onRefreshClick={() => {
fetchItems();
}}
/>
</Card>
@ -148,6 +154,7 @@ const ModalTable: Function = <TBaseModel extends BaseModel>(
fields: props.createFormFields || [],
formType: ModalType.Create ? FormType.Create : FormType.Update,
}}
/>
) : (
<></>
@ -156,4 +163,4 @@ const ModalTable: Function = <TBaseModel extends BaseModel>(
);
};
export default ModalTable;
export default ModelTable;

View File

@ -7,22 +7,32 @@ export interface ComponentProps {
onNavigateToPage: (pageNumber: number) => void;
isLoading: boolean;
isError: boolean;
singularLabel: string;
pluralLabel: string;
}
const Pagination: FunctionComponent<ComponentProps> = (
props: ComponentProps
): ReactElement => {
const isPreviousDisabled: boolean = props.currentPageNumber === 1;
const isNextDisabled: boolean = props.currentPageNumber * props.itemsOnPage < props.totalItemsCount;
const isPreviousDisabled: boolean = (props.currentPageNumber === 1 || props.isLoading || props.isError);
const isNextDisabled: boolean = (
props.currentPageNumber * props.itemsOnPage < props.totalItemsCount
|| props.isLoading || props.isError
);
const isCurrentPageButtonDisabled: boolean = props.isLoading || props.isError;
return (
<div className='justify-space-between'>
<div>
<p
style={{"padding": "17px", "margin": "0px"}}
className='color-light-grey'>{props.totalItemsCount} {props.totalItemsCount > 1 ? props.pluralLabel : props.singularLabel}</p>
</div>
<div>
<nav className="" aria-label="Page navigation example">
<nav className="" aria-label="Page navigation example" style={{
"height": "54px"
}}>
<ul className="pagination">
<li onClick={() => {
if (props.onNavigateToPage && !isPreviousDisabled) {
@ -32,7 +42,7 @@ const Pagination: FunctionComponent<ComponentProps> = (
className={`page-item ${isPreviousDisabled ? "disabled" : ""}`} style={{ "padding": "0px" }}>
<a href="#" className="page-link">Previous</a>
</li>
<li className="page-item" style={{ "padding": "0px" }}>
<li className={`page-item ${isCurrentPageButtonDisabled ? "disabled" : ""}`} style={{ "padding": "0px" }}>
<a className="pointer page-link">{props.currentPageNumber}</a>
</li>
<li onClick={() => {

View File

@ -4,7 +4,8 @@ import TableBody from './TableBody';
import TableHeader from './TableHeader';
import Columns from './Types/Columns';
import Pagination from './Pagination';
import PageLoader from '../Loader/PageLoader';
import Loader, { LoaderType } from '../Loader/Loader';
import { VeryLightGrey } from '../../Utils/BrandColors';
export interface ComponentProps {
data: Array<JSONObject>;
@ -15,8 +16,11 @@ export interface ComponentProps {
currentPageNumber: number;
totalItemsCount: number;
itemsOnPage: number;
error: string;
error: string;
isLoading: boolean;
singularLabel: string;
pluralLabel: string;
onRefreshClick?: () => void;
}
const Table: FunctionComponent<ComponentProps> = (
@ -26,11 +30,54 @@ const Table: FunctionComponent<ComponentProps> = (
const getTablebody = (): ReactElement => {
if (props.isLoading) {
return (<PageLoader isVisible={true} />)
return (
<tbody>
<tr>
<td colSpan={props.columns.length}>
<div className="row text-center" style={{
marginTop: "50px",
marginBottom: "50px"
}}>
<Loader loaderType={LoaderType.Bar} color={VeryLightGrey} size={200} />
</div>
</td>
</tr>
</tbody>
)
}
if (props.error) {
return (<p>{props.error}</p>)
return (
<tbody>
<tr>
<td colSpan={props.columns.length}>
<p className='text-center color-light-grey' style={{
marginTop: "50px",
marginBottom: "50px"
}}>{props.error} <br /> {props.onRefreshClick ? <span onClick={() => {
if (props.onRefreshClick) {
props.onRefreshClick();
}
}} className="underline primary-on-hover">Refresh?</span> : <></>}</p>
</td>
</tr>
</tbody>
)
}
if (props.data.length === 0) {
return (
<tbody>
<tr>
<td colSpan={props.columns.length}>
<p className='text-center color-light-grey' style={{
marginTop: "50px",
marginBottom: "50px"
}}> No {props.singularLabel.toLocaleLowerCase()} </p>
</td>
</tr>
</tbody>
)
}
return (<TableBody
@ -49,6 +96,8 @@ const Table: FunctionComponent<ComponentProps> = (
/>
{getTablebody()}
<Pagination
singularLabel={props.singularLabel}
pluralLabel={props.pluralLabel}
currentPageNumber={props.currentPageNumber}
totalItemsCount={props.totalItemsCount}
itemsOnPage={props.itemsOnPage}

View File

@ -1,3 +1,5 @@
@import "../../BrandColors";
.underline-on-hover {
cursor: pointer;
@ -6,6 +8,14 @@
}
}
.underline{
text-decoration: underline !important;
}
.color-light-grey{
color: $color-light-grey;
}
.primary-on-hover {
cursor: pointer;

View File

@ -7,7 +7,7 @@ import PageComponentProps from '../PageComponentProps';
import DashboardSideMenu from './SideMenu';
import { IconProp } from 'CommonUI/src/Components/Icon/Icon';
import Button, { ButtonStyleType } from 'CommonUI/src/Components/Button/Button';
import ModelTable from 'CommonUI/src/Components/ModelTable/ModalTable';
import ModelTable from 'CommonUI/src/Components/ModelTable/ModelTable';
import Navigation from 'CommonUI/src/Utils/Navigation';
import ProjectAPIKey from 'Common/Models/ProjectAPIKey';
import TableColumnType from 'CommonUI/src/Components/Table/Types/TableColumnType';

View File

@ -5,7 +5,7 @@ import PageMap from '../../Utils/PageMap';
import RouteMap from '../../Utils/RouteMap';
import PageComponentProps from '../PageComponentProps';
import DashboardSideMenu from './SideMenu';
import ModelTable from 'CommonUI/src/Components/ModelTable/ModalTable';
import ModelTable from 'CommonUI/src/Components/ModelTable/ModelTable';
import Label from 'Common/Models/Label';
import TableColumnType from 'CommonUI/src/Components/Table/Types/TableColumnType';
@ -38,6 +38,7 @@ const APIKeys: FunctionComponent<PageComponentProps> = (
isDeleteable={true}
isEditable={true}
isCreateable={true}
itemsOnPage={10}
cardProps={{
title: 'Labels',
description:

View File

@ -26,6 +26,28 @@ import EmailVerificationTokenService, {
Service as EmailVerificationTokenServiceType,
} from 'CommonServer/Services/EmailVerificationTokenService';
import Team from 'Common/Models/Team';
import TeamService, {
Service as TeamServiceType,
} from 'CommonServer/Services/TeamService';
import TeamMember from 'Common/Models/TeamMember';
import TeamMemberService, {
Service as TeamMemberServiceType,
} from 'CommonServer/Services/TeamMemberService';
import TeamPermission from 'Common/Models/TeamPermission';
import TeamPermissionService, {
Service as TeamPermissionServiceType,
} from 'CommonServer/Services/TeamPermissionService';
import Label from 'Common/Models/Label';
import LabelService, {
Service as LabelServiceType,
} from 'CommonServer/Services/LabelService';
const app: ExpressApplication = Express.getExpressApp();
const APP_NAME: string = 'api';
@ -39,7 +61,14 @@ app.use(
).getRouter()
);
app.use(new BaseAPI<Probe, ProbeServiceType>(Probe, ProbeService).getRouter());
app.use(new BaseAPI<Probe, ProbeServiceType>(Probe, ProbeService).getRouter());
app.use(new BaseAPI<Team, TeamServiceType>(Team, TeamService).getRouter());
app.use(new BaseAPI<TeamMember, TeamMemberServiceType>(TeamMember, TeamMemberService).getRouter());
app.use(new BaseAPI<TeamPermission, TeamPermissionServiceType>(TeamPermission, TeamPermissionService).getRouter());
app.use(new BaseAPI<Label, LabelServiceType>(Label, LabelService).getRouter());
app.use(
new BaseAPI<EmailVerificationToken, EmailVerificationTokenServiceType>(
EmailVerificationToken,