Add FieldType.Percent and ColorInput component

Update BaseAPI instantiation
Update TableRow component to handle FieldType.Percent and FieldType.Color
Update OverviewPageBranding component to use FieldType.Percent
This commit is contained in:
Simon Larsen 2024-01-26 10:41:21 +00:00
parent b27d5953c1
commit b1e299ecfd
No known key found for this signature in database
GPG Key ID: AB45983AA9C81CDE
5 changed files with 269 additions and 7 deletions

View File

@ -471,7 +471,10 @@ app.use(
app.use(
`/${APP_NAME.toLocaleLowerCase()}`,
new BaseAPI<StatusPageHistoryChartBarColorRule, StatusPageHistoryChartBarColorRuleServiceType>(
new BaseAPI<
StatusPageHistoryChartBarColorRule,
StatusPageHistoryChartBarColorRuleServiceType
>(
StatusPageHistoryChartBarColorRule,
StatusPageHistoryChartBarColorRuleService
).getRouter()

View File

@ -1,11 +1,250 @@
import PostgresDatabase from '../Infrastructure/PostgresDatabase';
import Model from 'Model/Models/StatusPageHistoryChartBarColorRule';
import DatabaseService from './DatabaseService';
import { OnCreate, OnDelete, OnUpdate } from '../Types/Database/Hooks';
import CreateBy from '../Types/Database/CreateBy';
import BadDataException from 'Common/Types/Exception/BadDataException';
import QueryHelper from '../Types/Database/QueryHelper';
import DeleteBy from '../Types/Database/DeleteBy';
import ObjectID from 'Common/Types/ObjectID';
import LIMIT_MAX from 'Common/Types/Database/LimitMax';
import SortOrder from 'Common/Types/BaseDatabase/SortOrder';
import UpdateBy from '../Types/Database/UpdateBy';
import Query from '../Types/Database/Query';
import PositiveNumber from 'Common/Types/PositiveNumber';
export class Service extends DatabaseService<Model> {
public constructor(postgresDatabase?: PostgresDatabase) {
super(Model, postgresDatabase);
}
protected override async onBeforeCreate(
createBy: CreateBy<Model>
): Promise<OnCreate<Model>> {
if (!createBy.data.statusPageId) {
throw new BadDataException(
'Status Page Resource statusPageId is required'
);
}
if (!createBy.data.order) {
const query: Query<Model> = {
statusPageId: createBy.data.statusPageId,
};
const count: PositiveNumber = await this.countBy({
query: query,
props: {
isRoot: true,
},
});
createBy.data.order = count.toNumber() + 1;
}
await this.rearrangeOrder(
createBy.data.order,
createBy.data.statusPageId,
true
);
return {
createBy: createBy,
carryForward: null,
};
}
protected override async onBeforeDelete(
deleteBy: DeleteBy<Model>
): Promise<OnDelete<Model>> {
if (!deleteBy.query._id && !deleteBy.props.isRoot) {
throw new BadDataException(
'_id should be present when deleting status page resource. Please try the delete with objectId'
);
}
let resource: Model | null = null;
if (!deleteBy.props.isRoot) {
resource = await this.findOneBy({
query: deleteBy.query,
props: {
isRoot: true,
},
select: {
order: true,
statusPageId: true,
},
});
}
return {
deleteBy,
carryForward: resource,
};
}
protected override async onDeleteSuccess(
onDelete: OnDelete<Model>,
_itemIdsBeforeDelete: ObjectID[]
): Promise<OnDelete<Model>> {
const deleteBy: DeleteBy<Model> = onDelete.deleteBy;
const resource: Model | null = onDelete.carryForward;
if (!deleteBy.props.isRoot && resource) {
if (resource && resource.order && resource.statusPageId) {
await this.rearrangeOrder(
resource.order,
resource.statusPageId,
false
);
}
}
return {
deleteBy: deleteBy,
carryForward: null,
};
}
protected override async onBeforeUpdate(
updateBy: UpdateBy<Model>
): Promise<OnUpdate<Model>> {
if (
updateBy.data.order &&
!updateBy.props.isRoot &&
updateBy.query._id
) {
const resource: Model | null = await this.findOneBy({
query: {
_id: updateBy.query._id!,
},
props: {
isRoot: true,
},
select: {
order: true,
statusPageId: true,
_id: true,
},
});
const currentOrder: number = resource?.order as number;
const newOrder: number = updateBy.data.order as number;
const resources: Array<Model> = await this.findBy({
query: {
statusPageId: resource?.statusPageId as ObjectID,
},
limit: LIMIT_MAX,
skip: 0,
props: {
isRoot: true,
},
select: {
order: true,
statusPageId: true,
_id: true,
},
});
if (currentOrder > newOrder) {
// moving up.
for (const resource of resources) {
if (
resource.order! >= newOrder &&
resource.order! < currentOrder
) {
// increment order.
await this.updateOneBy({
query: {
_id: resource._id!,
},
data: {
order: resource.order! + 1,
},
props: {
isRoot: true,
},
});
}
}
}
if (newOrder > currentOrder) {
// moving down.
for (const resource of resources) {
if (resource.order! <= newOrder) {
// increment order.
await this.updateOneBy({
query: {
_id: resource._id!,
},
data: {
order: resource.order! - 1,
},
props: {
isRoot: true,
},
});
}
}
}
}
return { updateBy, carryForward: null };
}
private async rearrangeOrder(
currentOrder: number,
statusPageId: ObjectID,
increaseOrder: boolean = true
): Promise<void> {
// get status page resource with this order.
const resources: Array<Model> = await this.findBy({
query: {
order: QueryHelper.greaterThanEqualTo(currentOrder),
statusPageId: statusPageId,
},
limit: LIMIT_MAX,
skip: 0,
props: {
isRoot: true,
},
select: {
_id: true,
order: true,
},
sort: {
order: SortOrder.Ascending,
},
});
let newOrder: number = currentOrder;
for (const resource of resources) {
if (increaseOrder) {
newOrder = resource.order! + 1;
} else {
newOrder = resource.order! - 1;
}
await this.updateOneBy({
query: {
_id: resource._id!,
},
data: {
order: newOrder,
},
props: {
isRoot: true,
},
});
}
}
}
export default new Service();

View File

@ -11,6 +11,8 @@ import FieldType from '../Types/FieldType';
import get from 'lodash/get';
import ConfirmModal from '../Modal/ConfirmModal';
import { Draggable, DraggableProvided } from 'react-beautiful-dnd';
import ColorInput from '../ColorViewer/ColorViewer';
import Color from 'Common/Types/Color';
export interface ComponentProps {
item: JSONObject;
@ -111,6 +113,25 @@ const TableRow: FunctionComponent<ComponentProps> = (
) : (
column.noValueMessage || '0 USD'
)
) : column.type ===
FieldType.Percent ? (
props.item[column.key] ? (
props.item[column.key] + '%'
) : (
column.noValueMessage || '0%'
)
) : column.type === FieldType.Color ? (
props.item[column.key] ? (
<ColorInput
value={
props.item[
column.key
] as Color
}
/>
) : (
column.noValueMessage || '0%'
)
) : column.type ===
FieldType.Boolean ? (
props.item[column.key] ? (

View File

@ -2,6 +2,7 @@ enum FieldType {
ObjectID = 'ObjectID',
Name = 'Name',
File = 'File',
Percent = 'Percent',
ImageFile = 'ImageFile',
Hostname = 'Hostname',
URL = 'URL',

View File

@ -57,7 +57,6 @@ const StatusPageDelete: FunctionComponent<PageComponentProps> = (
}}
/>
<ModelTable<StatusPageHistoryChartBarColorRule>
modelType={StatusPageHistoryChartBarColorRule}
id={`status-page-history-chart-bar-color-rules`}
@ -76,11 +75,10 @@ const StatusPageDelete: FunctionComponent<PageComponentProps> = (
enableDragAndDrop={true}
dragDropIndexField="order"
singularName="Rule"
pluralName='Rules'
pluralName="Rules"
onBeforeCreate={(
item: StatusPageHistoryChartBarColorRule
): Promise<StatusPageHistoryChartBarColorRule> => {
if (!props.currentProject || !props.currentProject._id) {
throw new BadDataException('Project ID cannot be null');
}
@ -89,7 +87,6 @@ const StatusPageDelete: FunctionComponent<PageComponentProps> = (
item.projectId = new ObjectID(props.currentProject._id);
return Promise.resolve(item);
}}
cardProps={{
title: `History Chart Bar Color Rules`,
@ -138,7 +135,8 @@ const StatusPageDelete: FunctionComponent<PageComponentProps> = (
},
required: true,
placeholder: 'Select monitor statuses',
}]}
},
]}
showRefreshButton={true}
showFilterButton={true}
viewPageRoute={Navigation.getCurrentRoute()}
@ -148,7 +146,7 @@ const StatusPageDelete: FunctionComponent<PageComponentProps> = (
uptimePercentGreaterThanOrEqualTo: true,
},
title: 'When Uptime Percent >=',
type: FieldType.Text,
type: FieldType.Percent,
isFilterable: false,
},
{