refactor: Update Select.ts and Project.ts for better code organization and readability

This commit is contained in:
Simon Larsen
2024-06-25 22:16:08 +01:00
parent a9778cf9d0
commit 2187edc158
11 changed files with 162 additions and 22 deletions

View File

@@ -21,6 +21,7 @@ import ProjectSSOService from "CommonServer/Services/ProjectSsoService";
import TeamMemberService from "CommonServer/Services/TeamMemberService";
import UserService from "CommonServer/Services/UserService";
import QueryHelper from "CommonServer/Types/Database/QueryHelper";
import Select from "CommonServer/Types/Database/Select";
import CookieUtil from "CommonServer/Utils/Cookie";
import Express, {
ExpressRequest,
@@ -30,6 +31,7 @@ import Express, {
} from "CommonServer/Utils/Express";
import logger from "CommonServer/Utils/Logger";
import Response from "CommonServer/Utils/Response";
import Project from "Model/Models/Project";
import ProjectSSO from "Model/Models/ProjectSso";
import TeamMember from "Model/Models/TeamMember";
import User from "Model/Models/User";
@@ -129,7 +131,7 @@ router.get(
projectId: true,
project: {
name: true,
},
} as Select<Project>,
},
props: {
isRoot: true,

View File

@@ -11,10 +11,13 @@ import { EVERY_MINUTE } from "Common/Utils/CronTime";
import IncidentService from "CommonServer/Services/IncidentService";
import ProjectService from "CommonServer/Services/ProjectService";
import UserNotificationSettingService from "CommonServer/Services/UserNotificationSettingService";
import Select from "CommonServer/Types/Database/Select";
import Markdown, { MarkdownContentType } from "CommonServer/Types/Markdown";
import logger from "CommonServer/Utils/Logger";
import Incident from "Model/Models/Incident";
import IncidentState from "Model/Models/IncidentState";
import Monitor from "Model/Models/Monitor";
import Project from "Model/Models/Project";
import User from "Model/Models/User";
RunCron(
@@ -38,11 +41,11 @@ RunCron(
projectId: true,
project: {
name: true,
},
} as Select<Project>,
remediationNotes: true,
currentIncidentState: {
name: true,
},
} as Select<IncidentState>,
incidentSeverity: {
name: true,
},

View File

@@ -1,9 +1,11 @@
import { IsBillingEnabled } from "../EnvironmentConfig";
import UserMiddleware from "../Middleware/UserAuthorization";
import ProjectService, {
Service as ProjectServiceType,
} from "../Services/ProjectService";
import ResellerService from "../Services/ResellerService";
import TeamMemberService from "../Services/TeamMemberService";
import Select from "../Types/Database/Select";
import {
ExpressRequest,
ExpressResponse,
@@ -38,6 +40,17 @@ export default class ProjectAPI extends BaseAPI<Project, ProjectServiceType> {
);
}
const projectSelect: Select<Project> = {
_id: true,
name: true,
trialEndsAt: true,
paymentProviderPlanId: true,
resellerId: true,
isFeatureFlagMonitorGroupsEnabled: true,
paymentProviderMeteredSubscriptionStatus: true,
paymentProviderSubscriptionStatus: true,
};
const teamMembers: Array<TeamMember> = await TeamMemberService.findBy(
{
query: {
@@ -45,16 +58,7 @@ export default class ProjectAPI extends BaseAPI<Project, ProjectServiceType> {
hasAcceptedInvitation: true,
},
select: {
project: {
_id: true,
name: true,
trialEndsAt: true,
paymentProviderPlanId: true,
resellerId: true,
isFeatureFlagMonitorGroupsEnabled: true,
paymentProviderMeteredSubscriptionStatus: true,
paymentProviderSubscriptionStatus: true,
},
project: projectSelect,
},
limit: LIMIT_PER_PROJECT,
skip: 0,
@@ -66,6 +70,47 @@ export default class ProjectAPI extends BaseAPI<Project, ProjectServiceType> {
const projects: Array<Project> = [];
// if billing enabled and is master admin then get all the projects with customer support enabled.
if (
IsBillingEnabled &&
(req as OneUptimeRequest).userAuthorization?.isMasterAdmin
) {
const customerSupportProjects: Array<Project> =
await ProjectService.findBy({
query: {
letCustomerSupportAccessProject: true,
},
select: projectSelect,
limit: LIMIT_PER_PROJECT,
skip: 0,
props: {
isRoot: true,
},
});
for (const customerSupportProject of customerSupportProjects) {
if (!customerSupportProject) {
continue;
}
if (!customerSupportProject._id) {
continue;
}
if (
projects.findIndex((project: Project) => {
return (
project._id?.toString() ===
customerSupportProject!._id?.toString()
);
}) === -1
) {
projects.push(customerSupportProject);
}
}
}
for (const teamMember of teamMembers) {
if (!teamMember.project) {
continue;

View File

@@ -0,0 +1,17 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MigrationName1719348009053 implements MigrationInterface {
public name = "MigrationName1719348009053";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "Project" ADD "letCustomerSupportAccessProject" boolean DEFAULT false`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "Project" DROP COLUMN "letCustomerSupportAccessProject"`,
);
}
}

View File

@@ -18,6 +18,7 @@ import { MigrationName1718879960254 } from "./1718879960254-MigrationName";
import { MigrationName1719227548476 } from "./1719227548476-MigrationName";
import { MigrationName1719228104620 } from "./1719228104620-MigrationName";
import { MigrationName1719247426296 } from "./1719247426296-MigrationName";
import { MigrationName1719348009053 } from "./1719348009053-MigrationName";
export default [
InitialMigration,
@@ -40,4 +41,5 @@ export default [
MigrationName1719227548476,
MigrationName1719228104620,
MigrationName1719247426296,
MigrationName1719348009053,
];

View File

@@ -39,6 +39,7 @@ import MonitorStatus from "Model/Models/MonitorStatus";
import MonitorStatusTimeline from "Model/Models/MonitorStatusTimeline";
import Probe from "Model/Models/Probe";
import User from "Model/Models/User";
import Select from "../Types/Database/Select";
export class Service extends DatabaseService<Model> {
public constructor(postgresDatabase?: PostgresDatabase) {
@@ -295,7 +296,7 @@ export class Service extends DatabaseService<Model> {
email: true,
name: true,
timezone: true,
},
} as Select<User>,
},
props: {
isRoot: true,

View File

@@ -1,3 +1,4 @@
import ResellerPlan from "Model/Models/ResellerPlan";
import { IsBillingEnabled, getAllEnvVars } from "../EnvironmentConfig";
import PostgresDatabase from "../Infrastructure/PostgresDatabase";
import AllMeteredPlans from "../Types/Billing/MeteredPlan/AllMeteredPlans";
@@ -49,6 +50,7 @@ import TeamMember from "Model/Models/TeamMember";
import TeamPermission from "Model/Models/TeamPermission";
import User from "Model/Models/User";
import { In } from "typeorm";
import Select from "../Types/Database/Select";
export interface CurrentPlan {
plan: PlanSelect | null;
@@ -134,7 +136,7 @@ export class Service extends DatabaseService<Model> {
planType: true,
monitorLimit: true,
teamMemberLimit: true,
},
} as Select<ResellerPlan>,
resellerId: true,
resellerLicenseId: true,
planType: true,

View File

@@ -5,6 +5,7 @@ import CreateBy from "../Types/Database/CreateBy";
import DeleteBy from "../Types/Database/DeleteBy";
import { OnCreate, OnDelete, OnUpdate } from "../Types/Database/Hooks";
import QueryHelper from "../Types/Database/QueryHelper";
import Select from "../Types/Database/Select";
import UpdateBy from "../Types/Database/UpdateBy";
import Errors from "../Utils/Errors";
import logger from "../Utils/Logger";
@@ -206,7 +207,7 @@ export class TeamMemberService extends DatabaseService<TeamMember> {
user: {
email: true,
isEmailVerified: true,
},
} as Select<User>,
projectId: true,
},
limit: LIMIT_MAX,
@@ -249,7 +250,7 @@ export class TeamMemberService extends DatabaseService<TeamMember> {
team: {
_id: true,
shouldHaveAtLeastOneMember: true,
},
} as Select<TeamMember>,
},
limit: LIMIT_MAX,
skip: 0,
@@ -351,7 +352,7 @@ export class TeamMemberService extends DatabaseService<TeamMember> {
email: true,
name: true,
timezone: true,
},
} as Select<User>,
},
skip: 0,
@@ -387,7 +388,7 @@ export class TeamMemberService extends DatabaseService<TeamMember> {
_id: true,
email: true,
name: true,
},
} as Select<User>,
},
skip: 0,

View File

@@ -1,14 +1,13 @@
import BaseModel from "Common/Models/BaseModel";
import Dictionary from "Common/Types/Dictionary";
export type SelectPropertyOptions = boolean | Dictionary<boolean>;
export type SelectPropertyOptions<T> = boolean | SelectOptions<T> | undefined;
/**
* Select find options.
*/
export declare type SelectOptions<Entity> = {
[P in keyof Entity]?: SelectPropertyOptions;
[P in keyof Entity]?: SelectPropertyOptions<any>;
};
type Select<TBaseModel extends BaseModel> = SelectOptions<TBaseModel>;

View File

@@ -2,9 +2,11 @@ import DashboardNavigation from "../../Utils/Navigation";
import PageComponentProps from "../PageComponentProps";
import FormFieldSchemaType from "CommonUI/src/Components/Forms/Types/FormFieldSchemaType";
import CardModelDetail from "CommonUI/src/Components/ModelDetail/CardModelDetail";
import FieldType from "CommonUI/src/Components/Types/FieldType";
import Navigation from "CommonUI/src/Utils/Navigation";
import Project from "Model/Models/Project";
import React, { Fragment, FunctionComponent, ReactElement } from "react";
import { BILLING_ENABLED } from "CommonUI/src/Config";
const Settings: FunctionComponent<PageComponentProps> = (): ReactElement => {
return (
@@ -54,6 +56,47 @@ const Settings: FunctionComponent<PageComponentProps> = (): ReactElement => {
modelId: DashboardNavigation.getProjectId()!,
}}
/>
{/* Project Settings View */}
{BILLING_ENABLED && (
<CardModelDetail
name="Enable Customer Support Access"
cardProps={{
title: "Enable Customer Support Access",
description:
"Enable Customer Support Access to this project. This will allow Customer Support to access this project for troubleshooting purposes.",
}}
isEditable={true}
formFields={[
{
field: {
letCustomerSupportAccessProject: true,
},
title: "Let Customer Support Access Project",
fieldType: FormFieldSchemaType.Toggle,
required: false,
},
]}
onSaveSuccess={() => {
Navigation.reload();
}}
modelDetailProps={{
modelType: Project,
id: "model-detail-project",
fields: [
{
field: {
letCustomerSupportAccessProject: true,
},
fieldType: FieldType.Boolean,
title: "Let Customer Support Access Project",
placeholder: "No",
},
],
modelId: DashboardNavigation.getProjectId()!,
}}
/>
)}
</Fragment>
);
};

View File

@@ -1140,4 +1140,29 @@ export default class Model extends TenantModel {
type: ColumnType.Number,
})
public enterpriseAnnualContractValue?: number = undefined;
@ColumnAccessControl({
create: [],
read: [
Permission.ProjectOwner,
Permission.ProjectAdmin,
Permission.ProjectMember,
Permission.ReadProject,
Permission.UnAuthorizedSsoUser,
],
update: [Permission.ProjectOwner, Permission.ProjectAdmin],
})
@TableColumn({
required: false,
type: TableColumnType.Boolean,
title: "Let Customer Support Access Project",
description:
"OneUptime customer support can access this project. This is used for debugging purposes.",
})
@Column({
nullable: true,
default: false,
type: ColumnType.Boolean,
})
public letCustomerSupportAccessProject?: boolean = undefined;
}