mirror of
https://github.com/OneUptime/oneuptime
synced 2024-11-22 23:30:10 +00:00
add labels
This commit is contained in:
parent
2d9b696b6b
commit
d005541a81
10
CommonServer/Services/LabelService.ts
Normal file
10
CommonServer/Services/LabelService.ts
Normal 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();
|
@ -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();
|
||||
|
@ -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>
|
||||
|
@ -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;
|
@ -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={() => {
|
||||
|
@ -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}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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';
|
||||
|
@ -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:
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user