mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
Merge branch 'master' into telemetry
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -13,7 +13,7 @@ node_modules
|
||||
|
||||
.idea
|
||||
# testing
|
||||
/coverage
|
||||
**/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
@@ -187,6 +187,7 @@ const Settings: FunctionComponent = (): ReactElement => {
|
||||
<Statusbubble
|
||||
text={'Connected'}
|
||||
color={Green}
|
||||
shouldAnimate={true}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -195,6 +196,7 @@ const Settings: FunctionComponent = (): ReactElement => {
|
||||
<Statusbubble
|
||||
text={'Disconnected'}
|
||||
color={Red}
|
||||
shouldAnimate={false}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
||||
@@ -108,7 +108,7 @@ export default class MonitorCriteriaInstance extends DatabaseProperty {
|
||||
monitorCriteriaInstance.data = {
|
||||
id: ObjectID.generate().toString(),
|
||||
monitorStatusId: arg.monitorStatusId,
|
||||
filterCondition: FilterCondition.All,
|
||||
filterCondition: FilterCondition.Any,
|
||||
filters: [
|
||||
{
|
||||
checkOn: CheckOn.IsOnline,
|
||||
|
||||
@@ -280,11 +280,32 @@ export default class API {
|
||||
}
|
||||
|
||||
try {
|
||||
const finalHeaders: Dictionary<string> = {
|
||||
...apiHeaders,
|
||||
...headers,
|
||||
};
|
||||
|
||||
let finalBody:
|
||||
| JSONObject
|
||||
| JSONArray
|
||||
| URLSearchParams
|
||||
| undefined = data;
|
||||
|
||||
// if content-type is form-url-encoded, then stringify the data
|
||||
|
||||
if (
|
||||
finalHeaders['Content-Type'] ===
|
||||
'application/x-www-form-urlencoded' &&
|
||||
data
|
||||
) {
|
||||
finalBody = new URLSearchParams(data as Dictionary<string>);
|
||||
}
|
||||
|
||||
const result: AxiosResponse = await axios({
|
||||
method: method,
|
||||
url: url.toString(),
|
||||
headers: { ...apiHeaders, ...headers },
|
||||
data,
|
||||
headers: finalHeaders,
|
||||
data: finalBody,
|
||||
});
|
||||
|
||||
result.headers = await this.onResponseSuccessHeaders(
|
||||
|
||||
@@ -4,7 +4,6 @@ import OneUptimeDate from 'Common/Types/Date';
|
||||
import APIException from 'Common/Types/Exception/ApiException';
|
||||
import BadDataException from 'Common/Types/Exception/BadDataException';
|
||||
import ObjectID from 'Common/Types/ObjectID';
|
||||
import Typeof from 'Common/Types/Typeof';
|
||||
import logger from '../Utils/Logger';
|
||||
import Stripe from 'stripe';
|
||||
import { BillingPrivateKey, IsBillingEnabled } from '../EnvironmentConfig';
|
||||
@@ -15,6 +14,7 @@ import SubscriptionStatus, {
|
||||
import BaseService from './BaseService';
|
||||
import Email from 'Common/Types/Email';
|
||||
import Dictionary from 'Common/Types/Dictionary';
|
||||
import Errors from '../Utils/Errors';
|
||||
|
||||
export type SubscriptionItem = Stripe.SubscriptionItem;
|
||||
|
||||
@@ -54,10 +54,9 @@ export class BillingService extends BaseService {
|
||||
}): Promise<string> {
|
||||
if (!this.isBillingEnabled()) {
|
||||
throw new BadDataException(
|
||||
'Billing is not enabled for this server.'
|
||||
Errors.BillingService.BILLING_NOT_ENABLED
|
||||
);
|
||||
}
|
||||
|
||||
const customer: Stripe.Response<Stripe.Customer> =
|
||||
await this.stripe.customers.create({
|
||||
name: data.name,
|
||||
@@ -66,7 +65,6 @@ export class BillingService extends BaseService {
|
||||
id: data.id.toString(),
|
||||
},
|
||||
});
|
||||
|
||||
return customer.id;
|
||||
}
|
||||
|
||||
@@ -76,7 +74,7 @@ export class BillingService extends BaseService {
|
||||
): Promise<void> {
|
||||
if (!this.isBillingEnabled()) {
|
||||
throw new BadDataException(
|
||||
'Billing is not enabled for this server.'
|
||||
Errors.BillingService.BILLING_NOT_ENABLED
|
||||
);
|
||||
}
|
||||
|
||||
@@ -86,7 +84,7 @@ export class BillingService extends BaseService {
|
||||
public async deleteCustomer(id: string): Promise<void> {
|
||||
if (!this.isBillingEnabled()) {
|
||||
throw new BadDataException(
|
||||
'Billing is not enabled for this server.'
|
||||
Errors.BillingService.BILLING_NOT_ENABLED
|
||||
);
|
||||
}
|
||||
|
||||
@@ -191,19 +189,21 @@ export class BillingService extends BaseService {
|
||||
}> {
|
||||
if (!this.isBillingEnabled()) {
|
||||
throw new BadDataException(
|
||||
'Billing is not enabled for this server.'
|
||||
Errors.BillingService.BILLING_NOT_ENABLED
|
||||
);
|
||||
}
|
||||
|
||||
let trialDate: Date | null = null;
|
||||
|
||||
if (typeof data.trial === Typeof.Boolean) {
|
||||
trialDate = OneUptimeDate.getSomeDaysAfter(
|
||||
data.plan.getTrialPeriod()
|
||||
);
|
||||
}
|
||||
|
||||
if (data.trial instanceof Date) {
|
||||
if (typeof data.trial === 'boolean') {
|
||||
if (data.trial) {
|
||||
trialDate = OneUptimeDate.getSomeDaysAfter(
|
||||
data.plan.getTrialPeriod()
|
||||
);
|
||||
} else {
|
||||
trialDate = null;
|
||||
}
|
||||
} else if (data.trial instanceof Date) {
|
||||
trialDate = data.trial;
|
||||
}
|
||||
|
||||
@@ -260,7 +260,7 @@ export class BillingService extends BaseService {
|
||||
): Promise<void> {
|
||||
if (!this.isBillingEnabled()) {
|
||||
throw new BadDataException(
|
||||
'Billing is not enabled for this server.'
|
||||
Errors.BillingService.BILLING_NOT_ENABLED
|
||||
);
|
||||
}
|
||||
|
||||
@@ -268,9 +268,10 @@ export class BillingService extends BaseService {
|
||||
await this.stripe.subscriptions.retrieve(subscriptionId);
|
||||
|
||||
if (!subscription) {
|
||||
throw new BadDataException('Subscription not found');
|
||||
throw new BadDataException(
|
||||
Errors.BillingService.SUBSCRIPTION_NOT_FOUND
|
||||
);
|
||||
}
|
||||
|
||||
if (subscription.status === 'canceled') {
|
||||
// subscription is canceled.
|
||||
return;
|
||||
@@ -280,7 +281,9 @@ export class BillingService extends BaseService {
|
||||
subscription.items.data[0]?.id;
|
||||
|
||||
if (!subscriptionItemId) {
|
||||
throw new BadDataException('Subscription Item not found');
|
||||
throw new BadDataException(
|
||||
Errors.BillingService.SUBSCRIPTION_ITEM_NOT_FOUND
|
||||
);
|
||||
}
|
||||
|
||||
await this.stripe.subscriptionItems.update(subscriptionItemId, {
|
||||
@@ -295,7 +298,7 @@ export class BillingService extends BaseService {
|
||||
): Promise<void> {
|
||||
if (!this.isBillingEnabled()) {
|
||||
throw new BadDataException(
|
||||
'Billing is not enabled for this server.'
|
||||
Errors.BillingService.BILLING_NOT_ENABLED
|
||||
);
|
||||
}
|
||||
|
||||
@@ -305,7 +308,9 @@ export class BillingService extends BaseService {
|
||||
);
|
||||
|
||||
if (!subscription) {
|
||||
throw new BadDataException('Subscription not found');
|
||||
throw new BadDataException(
|
||||
Errors.BillingService.SUBSCRIPTION_NOT_FOUND
|
||||
);
|
||||
}
|
||||
|
||||
// check if this pricing exists
|
||||
@@ -324,7 +329,9 @@ export class BillingService extends BaseService {
|
||||
})?.id;
|
||||
|
||||
if (!subscriptionItemId) {
|
||||
throw new BadDataException('Subscription Item not found');
|
||||
throw new BadDataException(
|
||||
Errors.BillingService.SUBSCRIPTION_ITEM_NOT_FOUND
|
||||
);
|
||||
}
|
||||
|
||||
// use stripe usage based api to update the quantity.
|
||||
@@ -357,7 +364,7 @@ export class BillingService extends BaseService {
|
||||
public async isPromoCodeValid(promoCode: string): Promise<boolean> {
|
||||
if (!this.isBillingEnabled()) {
|
||||
throw new BadDataException(
|
||||
'Billing is not enabled for this server.'
|
||||
Errors.BillingService.BILLING_NOT_ENABLED
|
||||
);
|
||||
}
|
||||
try {
|
||||
@@ -365,13 +372,16 @@ export class BillingService extends BaseService {
|
||||
await this.stripe.coupons.retrieve(promoCode);
|
||||
|
||||
if (!promoCodeResponse) {
|
||||
throw new BadDataException('Promo code not found');
|
||||
throw new BadDataException(
|
||||
Errors.BillingService.PROMO_CODE_NOT_FOUND
|
||||
);
|
||||
}
|
||||
|
||||
return promoCodeResponse.valid;
|
||||
} catch (err) {
|
||||
throw new BadDataException(
|
||||
(err as Error).message || 'Invalid promo code'
|
||||
(err as Error).message ||
|
||||
Errors.BillingService.PROMO_CODE_INVALID
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -383,7 +393,7 @@ export class BillingService extends BaseService {
|
||||
): Promise<void> {
|
||||
if (!this.isBillingEnabled()) {
|
||||
throw new BadDataException(
|
||||
'Billing is not enabled for this server.'
|
||||
Errors.BillingService.BILLING_NOT_ENABLED
|
||||
);
|
||||
}
|
||||
|
||||
@@ -391,7 +401,9 @@ export class BillingService extends BaseService {
|
||||
await this.stripe.subscriptions.retrieve(subscriptionId);
|
||||
|
||||
if (!subscription) {
|
||||
throw new BadDataException('Subscription not found');
|
||||
throw new BadDataException(
|
||||
Errors.BillingService.SUBSCRIPTION_NOT_FOUND
|
||||
);
|
||||
}
|
||||
|
||||
if (subscription.status === 'canceled') {
|
||||
@@ -418,7 +430,7 @@ export class BillingService extends BaseService {
|
||||
): Promise<Array<SubscriptionItem>> {
|
||||
if (!this.isBillingEnabled()) {
|
||||
throw new BadDataException(
|
||||
'Billing is not enabled for this server.'
|
||||
Errors.BillingService.BILLING_NOT_ENABLED
|
||||
);
|
||||
}
|
||||
|
||||
@@ -426,7 +438,9 @@ export class BillingService extends BaseService {
|
||||
await this.stripe.subscriptions.retrieve(subscriptionId);
|
||||
|
||||
if (!subscription) {
|
||||
throw new BadDataException('Subscription not found');
|
||||
throw new BadDataException(
|
||||
Errors.BillingService.SUBSCRIPTION_NOT_FOUND
|
||||
);
|
||||
}
|
||||
|
||||
return subscription.items.data;
|
||||
@@ -450,10 +464,10 @@ export class BillingService extends BaseService {
|
||||
logger.info(data);
|
||||
|
||||
if (!this.isBillingEnabled()) {
|
||||
logger.info('Billing not enabled');
|
||||
logger.info(Errors.BillingService.BILLING_NOT_ENABLED);
|
||||
|
||||
throw new BadDataException(
|
||||
'Billing is not enabled for this server.'
|
||||
Errors.BillingService.BILLING_NOT_ENABLED
|
||||
);
|
||||
}
|
||||
|
||||
@@ -464,8 +478,10 @@ export class BillingService extends BaseService {
|
||||
logger.info(subscription);
|
||||
|
||||
if (!subscription) {
|
||||
logger.info('Subscription not found');
|
||||
throw new BadDataException('Subscription not found');
|
||||
logger.info(Errors.BillingService.SUBSCRIPTION_NOT_FOUND);
|
||||
throw new BadDataException(
|
||||
Errors.BillingService.SUBSCRIPTION_NOT_FOUND
|
||||
);
|
||||
}
|
||||
|
||||
logger.info('Subscription status');
|
||||
@@ -481,7 +497,7 @@ export class BillingService extends BaseService {
|
||||
logger.info('No payment methods');
|
||||
|
||||
throw new BadDataException(
|
||||
'No payment methods added. Please add your card to this project to change your plan'
|
||||
Errors.BillingService.NO_PAYMENTS_METHODS
|
||||
);
|
||||
}
|
||||
|
||||
@@ -536,7 +552,7 @@ export class BillingService extends BaseService {
|
||||
): Promise<void> {
|
||||
if (!this.isBillingEnabled()) {
|
||||
throw new BadDataException(
|
||||
'Billing is not enabled for this server.'
|
||||
Errors.BillingService.BILLING_NOT_ENABLED
|
||||
);
|
||||
}
|
||||
|
||||
@@ -545,7 +561,7 @@ export class BillingService extends BaseService {
|
||||
|
||||
if (paymentMethods.length === 1) {
|
||||
throw new BadDataException(
|
||||
"There's only one payment method associated with this account. It cannot be deleted. To delete this payment method please add more payment methods to your account."
|
||||
Errors.BillingService.MIN_REQUIRED_PAYMENT_METHOD_NOT_MET
|
||||
);
|
||||
}
|
||||
|
||||
@@ -576,7 +592,7 @@ export class BillingService extends BaseService {
|
||||
): Promise<Array<PaymentMethod>> {
|
||||
if (!this.isBillingEnabled()) {
|
||||
throw new BadDataException(
|
||||
'Billing is not enabled for this server.'
|
||||
Errors.BillingService.BILLING_NOT_ENABLED
|
||||
);
|
||||
}
|
||||
const paymentMethods: Array<PaymentMethod> = [];
|
||||
@@ -671,9 +687,7 @@ export class BillingService extends BaseService {
|
||||
});
|
||||
|
||||
if (!setupIntent.client_secret) {
|
||||
throw new APIException(
|
||||
'client_secret not returned by payment provider.'
|
||||
);
|
||||
throw new APIException(Errors.BillingService.CLIENT_SECRET_MISSING);
|
||||
}
|
||||
|
||||
return setupIntent.client_secret;
|
||||
@@ -682,7 +696,7 @@ export class BillingService extends BaseService {
|
||||
public async cancelSubscription(subscriptionId: string): Promise<void> {
|
||||
if (!this.isBillingEnabled()) {
|
||||
throw new BadDataException(
|
||||
'Billing is not enabled for this server.'
|
||||
Errors.BillingService.BILLING_NOT_ENABLED
|
||||
);
|
||||
}
|
||||
try {
|
||||
@@ -706,7 +720,7 @@ export class BillingService extends BaseService {
|
||||
): Promise<Stripe.Subscription> {
|
||||
if (!this.isBillingEnabled()) {
|
||||
throw new BadDataException(
|
||||
'Billing is not enabled for this server.'
|
||||
Errors.BillingService.BILLING_NOT_ENABLED
|
||||
);
|
||||
}
|
||||
|
||||
@@ -748,7 +762,7 @@ export class BillingService extends BaseService {
|
||||
});
|
||||
|
||||
if (!invoice || !invoice.id) {
|
||||
throw new APIException('Invoice not generated.');
|
||||
throw new APIException(Errors.BillingService.INVOICE_NOT_GENERATED);
|
||||
}
|
||||
|
||||
await this.stripe.invoiceItems.create({
|
||||
@@ -787,7 +801,7 @@ export class BillingService extends BaseService {
|
||||
|
||||
if (paymentMethods.length === 0) {
|
||||
throw new BadDataException(
|
||||
'Payment Method not added. Please go to Project Settings > Billing and add a payment method.'
|
||||
Errors.BillingService.NO_PAYMENTS_METHODS
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
1591
CommonServer/Tests/Services/BillingService.test.ts
Normal file
1591
CommonServer/Tests/Services/BillingService.test.ts
Normal file
File diff suppressed because it is too large
Load Diff
161
CommonServer/Tests/TestingUtils/Services/Helpers.ts
Normal file
161
CommonServer/Tests/TestingUtils/Services/Helpers.ts
Normal file
@@ -0,0 +1,161 @@
|
||||
import { Stripe } from 'stripe';
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
import Email from 'Common/Types/Email';
|
||||
import ObjectID from 'Common/Types/ObjectID';
|
||||
import SubscriptionPlan from 'Common/Types/Billing/SubscriptionPlan';
|
||||
|
||||
import { BillingService } from '../../../Services/BillingService';
|
||||
|
||||
import {
|
||||
CustomerData,
|
||||
Subscription,
|
||||
MeteredSubscription,
|
||||
ChangePlan,
|
||||
CouponData,
|
||||
} from '../../TestingUtils/Services/Types';
|
||||
|
||||
/// @dev consider modifyfing the EnvirontmentConfig to use functions instead of constants so that we can mock them
|
||||
const mockIsBillingEnabled: Function = (value: boolean): BillingService => {
|
||||
jest.resetModules();
|
||||
jest.doMock('../../../EnvironmentConfig', () => {
|
||||
return {
|
||||
IsBillingEnabled: value,
|
||||
};
|
||||
});
|
||||
const { BillingService } = require('../../../Services/BillingService');
|
||||
return new BillingService();
|
||||
};
|
||||
|
||||
const getStripeCustomer: Function = (id?: string): Stripe.Customer => {
|
||||
id = id || faker.datatype.uuid();
|
||||
return {
|
||||
id,
|
||||
object: 'customer',
|
||||
balance: faker.datatype.number(),
|
||||
created: 1,
|
||||
default_source: null,
|
||||
description: null,
|
||||
email: null,
|
||||
invoice_settings: {
|
||||
custom_fields: null,
|
||||
default_payment_method: null,
|
||||
footer: null,
|
||||
rendering_options: null,
|
||||
},
|
||||
livemode: true,
|
||||
metadata: {},
|
||||
shipping: null,
|
||||
};
|
||||
};
|
||||
|
||||
const getStripeSubscription: Function = (): Stripe.Subscription => {
|
||||
return {
|
||||
id: faker.datatype.uuid(),
|
||||
items: {
|
||||
data: [
|
||||
{
|
||||
id: faker.datatype.uuid(),
|
||||
// @ts-ignore
|
||||
price: { id: faker.datatype.uuid() },
|
||||
},
|
||||
],
|
||||
},
|
||||
status: 'active',
|
||||
customer: getStripeCustomer(),
|
||||
};
|
||||
};
|
||||
|
||||
const getSubscriptionPlanData: Function = (): SubscriptionPlan => {
|
||||
return new SubscriptionPlan(
|
||||
faker.datatype.uuid(), // monthlyPlanId
|
||||
faker.datatype.uuid(), // yearlyPlanId
|
||||
faker.commerce.productName(), // name
|
||||
faker.datatype.number(), // monthlySubscriptionAmountInUSD
|
||||
faker.datatype.number({ min: 1, max: 100 }), // yearlySubscriptionAmountInUSD
|
||||
faker.datatype.number({ min: 1, max: 100 }), // order
|
||||
faker.datatype.number({ min: 1, max: 100 }) // trial period days
|
||||
);
|
||||
};
|
||||
|
||||
const getStripeInvoice: Function = (): Stripe.Invoice => {
|
||||
// @ts-ignore
|
||||
return {
|
||||
id: faker.datatype.uuid(),
|
||||
amount_due: faker.datatype.number(),
|
||||
currency: 'usd',
|
||||
customer: faker.datatype.uuid(),
|
||||
subscription: faker.datatype.uuid(),
|
||||
status: 'paid',
|
||||
};
|
||||
};
|
||||
|
||||
const getCustomerData: Function = (id?: ObjectID): CustomerData => {
|
||||
return {
|
||||
id: id || new ObjectID('customer_id'),
|
||||
name: 'John Doe',
|
||||
email: new Email('test@example.com'),
|
||||
};
|
||||
};
|
||||
|
||||
const getSubscriptionData: Function = (id?: ObjectID): Subscription => {
|
||||
return {
|
||||
projectId: id || new ObjectID('project_id'),
|
||||
customerId: 'cust_123',
|
||||
serverMeteredPlans: [],
|
||||
trialDate: new Date(),
|
||||
};
|
||||
};
|
||||
|
||||
const getMeteredSubscription: Function = (
|
||||
subscriptionPlan: SubscriptionPlan,
|
||||
id?: ObjectID
|
||||
): MeteredSubscription => {
|
||||
return {
|
||||
projectId: id || new ObjectID('project_id'),
|
||||
customerId: 'cust_123',
|
||||
serverMeteredPlans: [],
|
||||
plan: subscriptionPlan,
|
||||
quantity: 1,
|
||||
isYearly: false,
|
||||
trial: true,
|
||||
};
|
||||
};
|
||||
|
||||
const getChangePlanData: Function = (
|
||||
subscriptionPlan: SubscriptionPlan,
|
||||
id?: ObjectID
|
||||
): ChangePlan => {
|
||||
return {
|
||||
projectId: id || new ObjectID('project_id'),
|
||||
subscriptionId: 'sub_123',
|
||||
meteredSubscriptionId: 'sub_456',
|
||||
serverMeteredPlans: [],
|
||||
newPlan: subscriptionPlan,
|
||||
quantity: 1,
|
||||
isYearly: false,
|
||||
};
|
||||
};
|
||||
|
||||
const getCouponData: Function = (): CouponData => {
|
||||
return {
|
||||
name: 'TESTCOUPON',
|
||||
metadata: { description: 'Test coupon' },
|
||||
percentOff: 10,
|
||||
durationInMonths: 3,
|
||||
maxRedemptions: 100,
|
||||
};
|
||||
};
|
||||
|
||||
export {
|
||||
mockIsBillingEnabled,
|
||||
getStripeCustomer,
|
||||
getStripeSubscription,
|
||||
getSubscriptionPlanData,
|
||||
getCustomerData,
|
||||
getSubscriptionData,
|
||||
getMeteredSubscription,
|
||||
getChangePlanData,
|
||||
getCouponData,
|
||||
getStripeInvoice,
|
||||
};
|
||||
57
CommonServer/Tests/TestingUtils/Services/Types.ts
Normal file
57
CommonServer/Tests/TestingUtils/Services/Types.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import Email from 'Common/Types/Email';
|
||||
import ObjectID from 'Common/Types/ObjectID';
|
||||
import ServerMeteredPlan from '../../../Types/Billing/MeteredPlan/ServerMeteredPlan';
|
||||
import SubscriptionPlan from 'Common/Types/Billing/SubscriptionPlan';
|
||||
import { PaymentMethod } from '../../../Services/BillingService';
|
||||
import Dictionary from 'Common/Types/Dictionary';
|
||||
|
||||
export type CustomerData = {
|
||||
id: ObjectID;
|
||||
name: string;
|
||||
email: Email;
|
||||
};
|
||||
|
||||
export type CouponData = {
|
||||
name: string;
|
||||
metadata?: Dictionary<string> | undefined;
|
||||
percentOff: number;
|
||||
durationInMonths: number;
|
||||
maxRedemptions: number;
|
||||
};
|
||||
|
||||
export type Subscription = {
|
||||
projectId: ObjectID;
|
||||
customerId: string;
|
||||
serverMeteredPlans: Array<typeof ServerMeteredPlan>;
|
||||
promoCode?: string;
|
||||
defaultPaymentMethodId?: string;
|
||||
trialDate: Date;
|
||||
};
|
||||
|
||||
export type MeteredSubscription = {
|
||||
projectId: ObjectID;
|
||||
customerId: string;
|
||||
serverMeteredPlans: Array<typeof ServerMeteredPlan>;
|
||||
plan: SubscriptionPlan;
|
||||
quantity: number;
|
||||
isYearly: boolean;
|
||||
trial: boolean | Date | undefined;
|
||||
defaultPaymentMethodId?: string | undefined;
|
||||
promoCode?: string | undefined;
|
||||
};
|
||||
|
||||
export type ChangePlan = {
|
||||
projectId: ObjectID;
|
||||
subscriptionId: string;
|
||||
meteredSubscriptionId: string;
|
||||
serverMeteredPlans: Array<typeof ServerMeteredPlan>;
|
||||
newPlan: SubscriptionPlan;
|
||||
quantity: number;
|
||||
isYearly: boolean;
|
||||
endTrialAt?: Date | undefined;
|
||||
};
|
||||
|
||||
export type PaymentMethodsResponse = {
|
||||
data: PaymentMethod[];
|
||||
defaultPaymentMethodId?: string | undefined;
|
||||
};
|
||||
16
CommonServer/Tests/TestingUtils/__mocks__/Stripe.mock.ts
Normal file
16
CommonServer/Tests/TestingUtils/__mocks__/Stripe.mock.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import * as mock from 'jest-mock-extended';
|
||||
|
||||
let mockStripe: jest.Mocked<Stripe>;
|
||||
|
||||
jest.mock('stripe', () => {
|
||||
mockStripe = mock.mockDeep<Stripe>();
|
||||
return jest.fn(() => {
|
||||
return mockStripe;
|
||||
});
|
||||
});
|
||||
|
||||
// import libraries to mock (we do it here because of hoisting)
|
||||
import Stripe from 'stripe';
|
||||
|
||||
// return the mocked library and the library itself
|
||||
export { mockStripe, Stripe };
|
||||
16
CommonServer/Utils/Errors.ts
Normal file
16
CommonServer/Utils/Errors.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
export default {
|
||||
BillingService: {
|
||||
BILLING_NOT_ENABLED: 'Billing is not enabled for this server.',
|
||||
CLIENT_SECRET_MISSING:
|
||||
'client_secret not returned by payment provider.',
|
||||
INVOICE_NOT_GENERATED: 'Invoice not generated.',
|
||||
MIN_REQUIRED_PAYMENT_METHOD_NOT_MET:
|
||||
"There's only one payment method associated with this account. It cannot be deleted. To delete this payment method please add more payment methods to your account.",
|
||||
NO_PAYMENTS_METHODS:
|
||||
'Payment Method not added. Please go to Project Settings > Billing and add a payment method.',
|
||||
PROMO_CODE_NOT_FOUND: 'Promo code not found',
|
||||
PROMO_CODE_INVALID: 'Invalid promo code',
|
||||
SUBSCRIPTION_ITEM_NOT_FOUND: 'Subscription item not found.',
|
||||
SUBSCRIPTION_NOT_FOUND: 'Subscription not found.',
|
||||
},
|
||||
};
|
||||
@@ -12,8 +12,11 @@
|
||||
".(ts|tsx)": "ts-jest"
|
||||
},
|
||||
"testEnvironment": "node",
|
||||
"collectCoverage": true,
|
||||
"coverageReporters": ["text"],
|
||||
"collectCoverage": false,
|
||||
"transformIgnorePatterns": [
|
||||
"/node_modules/(?!Common).+\\.js$"
|
||||
],
|
||||
"coverageReporters": ["text", "lcov"],
|
||||
"testRegex": "./Tests/(.*).test.ts",
|
||||
"collectCoverageFrom": ["./**/*.(tsx||ts)"],
|
||||
"coverageThreshold": {
|
||||
|
||||
3007
CommonServer/package-lock.json
generated
3007
CommonServer/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,7 @@
|
||||
"scripts": {
|
||||
"compile": "tsc",
|
||||
"test": "jest --detectOpenHandles",
|
||||
"coverage": "jest --detectOpenHandles --coverage",
|
||||
"debug:test": "cd .. && export $(grep -v '^#' config.env | xargs) && cd CommonServer && node --inspect node_modules/.bin/jest --runInBand ./Tests --detectOpenHandles"
|
||||
},
|
||||
"author": "",
|
||||
@@ -60,6 +61,7 @@
|
||||
"@types/jsonwebtoken": "^8.5.9",
|
||||
"@types/node": "^17.0.22",
|
||||
"jest": "^27.5.1",
|
||||
"ts-jest": "^27.1.4"
|
||||
"ts-jest": "^27.1.4",
|
||||
"jest-mock-extended": "^3.0.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,9 +11,12 @@
|
||||
"transform": {
|
||||
".(ts|tsx)": "ts-jest"
|
||||
},
|
||||
"transformIgnorePatterns": [
|
||||
"/node_modules/(?!Common).+\\.js$"
|
||||
],
|
||||
"testEnvironment": "jsdom",
|
||||
"collectCoverage": true,
|
||||
"coverageReporters": ["text", "html"],
|
||||
"collectCoverage": false,
|
||||
"coverageReporters": ["text", "lcov", "html"],
|
||||
"testRegex": "./src/Tests/(.*).test.(tsx||ts)",
|
||||
"collectCoverageFrom": ["./**/*.(tsx||ts)"],
|
||||
"coverageThreshold": {
|
||||
|
||||
@@ -143,7 +143,7 @@ const EventItem: FunctionComponent<ComponentProps> = (
|
||||
{props.eventResourcesAffected &&
|
||||
props.eventResourcesAffected?.length > 0 ? (
|
||||
<div key={0}>
|
||||
<div className="flex space-x-1">
|
||||
<div className="flex flex-wrap gap-y-4 space-x-1">
|
||||
<div className="text-sm text-gray-400 mr-3 mt-1">
|
||||
Affected resources
|
||||
</div>
|
||||
|
||||
@@ -35,6 +35,7 @@ export interface ComponentProps {
|
||||
onClick?: (() => void) | undefined;
|
||||
type?: IconType | undefined;
|
||||
style?: React.CSSProperties | undefined;
|
||||
'data-testid'?: string;
|
||||
}
|
||||
const Icon: FunctionComponent<ComponentProps> = ({
|
||||
size = SizeProp.Regular,
|
||||
@@ -45,6 +46,7 @@ const Icon: FunctionComponent<ComponentProps> = ({
|
||||
onClick,
|
||||
type,
|
||||
style,
|
||||
'data-testid': dataTestId,
|
||||
}: ComponentProps): ReactElement => {
|
||||
let sizeClassName: string = '';
|
||||
if (
|
||||
@@ -115,6 +117,7 @@ const Icon: FunctionComponent<ComponentProps> = ({
|
||||
strokeWidth="1.5"
|
||||
stroke="currentColor"
|
||||
aria-hidden="true"
|
||||
data-testid={dataTestId}
|
||||
>
|
||||
{children}
|
||||
</svg>
|
||||
|
||||
@@ -14,6 +14,7 @@ export interface ComponentProps {
|
||||
className?: string | undefined;
|
||||
alt?: string | undefined;
|
||||
style?: React.CSSProperties | undefined;
|
||||
'data-testid'?: string;
|
||||
}
|
||||
|
||||
export class ImageFunctions {
|
||||
@@ -36,6 +37,7 @@ const Image: FunctionComponent<ComponentProps> = (
|
||||
onClick={() => {
|
||||
props.onClick && props.onClick();
|
||||
}}
|
||||
data-testid={props['data-testid']}
|
||||
alt={props.alt}
|
||||
src={url}
|
||||
height={props.height}
|
||||
|
||||
@@ -26,7 +26,9 @@ const ProbeElement: FunctionComponent<ComponentProps> = (
|
||||
if (!probe) {
|
||||
return (
|
||||
<div className="flex">
|
||||
<div className="bold">No probe found.</div>
|
||||
<div className="bold" data-testid="probe-not-found">
|
||||
No probe found.
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -37,6 +39,7 @@ const ProbeElement: FunctionComponent<ComponentProps> = (
|
||||
{props.probe?.iconFileId && (
|
||||
<Image
|
||||
className="h-6 w-6 rounded-full"
|
||||
data-testid="probe-image"
|
||||
imageUrl={URL.fromString(FILE_URL.toString()).addRoute(
|
||||
'/image/' + props.probe?.iconFileId.toString()
|
||||
)}
|
||||
@@ -45,6 +48,7 @@ const ProbeElement: FunctionComponent<ComponentProps> = (
|
||||
)}
|
||||
{!props.probe?.iconFileId && (
|
||||
<Icon
|
||||
data-testid="probe-icon"
|
||||
icon={IconProp.Signal}
|
||||
className="text-gray-400 group-hover:text-gray-500 flex-shrink-0 -ml-0.5 mt-0.5 h-6 w-6"
|
||||
/>
|
||||
@@ -52,7 +56,7 @@ const ProbeElement: FunctionComponent<ComponentProps> = (
|
||||
</div>
|
||||
<div className="mt-1 mr-1 ml-3">
|
||||
<div>
|
||||
<span>{`${
|
||||
<span data-testid="probe-name">{`${
|
||||
(probe['name']?.toString() as string) || ''
|
||||
}`}</span>{' '}
|
||||
</div>
|
||||
|
||||
@@ -35,14 +35,15 @@ const ProgressBar: FunctionComponent<ComponentProps> = (
|
||||
return (
|
||||
<div className="w-full h-4 mb-4 bg-gray-200 rounded-full dark:bg-gray-700">
|
||||
<div
|
||||
data-testid="progress-bar"
|
||||
className="h-4 bg-indigo-600 rounded-full dark:bg-indigo-500"
|
||||
style={{ width: percent + '%' }}
|
||||
></div>
|
||||
<div className="text-sm text-gray-400 mt-1 flex justify-between">
|
||||
<div>
|
||||
<div data-testid="progress-bar-count">
|
||||
{props.count} {props.suffix}
|
||||
</div>
|
||||
<div>
|
||||
<div data-testid="progress-bar-total-count">
|
||||
{props.totalCount} {props.suffix}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,6 +6,7 @@ export interface ComponentProps {
|
||||
text: string;
|
||||
color: Color;
|
||||
style?: CSSProperties;
|
||||
shouldAnimate: boolean;
|
||||
}
|
||||
|
||||
const Statusbubble: FunctionComponent<ComponentProps> = (
|
||||
@@ -14,7 +15,9 @@ const Statusbubble: FunctionComponent<ComponentProps> = (
|
||||
return (
|
||||
<div className="flex" style={props.style}>
|
||||
<div
|
||||
className="animate-pulse flex h-5 w-5 flex-shrink-0 items-center justify-center rounded-full mr-2"
|
||||
className={`flex h-5 w-5 flex-shrink-0 items-center justify-center rounded-full mr-2 ${
|
||||
props.shouldAnimate ? 'animate-pulse' : ''
|
||||
}`}
|
||||
style={{
|
||||
backgroundColor: props.color
|
||||
? props.color.toString()
|
||||
|
||||
425
CommonUI/src/Tests/Components/ComponentsModal.test.tsx
Normal file
425
CommonUI/src/Tests/Components/ComponentsModal.test.tsx
Normal file
@@ -0,0 +1,425 @@
|
||||
import React from 'react';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import { render, fireEvent, screen } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
|
||||
import ComponentMetadata, {
|
||||
ComponentCategory,
|
||||
ComponentType,
|
||||
} from 'Common/Types/Workflow/Component';
|
||||
import IconProp from 'Common/Types/Icon/IconProp';
|
||||
|
||||
import ComponentsModal from '../../Components/Workflow/ComponentsModal';
|
||||
|
||||
/// @dev we use different UUID for (id & title), description, and category to ensure that the component is unique
|
||||
const getComponentMetadata: Function = (
|
||||
category?: string
|
||||
): ComponentMetadata => {
|
||||
const id: string = faker.datatype.uuid();
|
||||
return {
|
||||
id,
|
||||
title: id,
|
||||
description: faker.datatype.uuid(),
|
||||
category: category || faker.datatype.uuid(),
|
||||
iconProp: IconProp.Activity,
|
||||
componentType: ComponentType.Component,
|
||||
arguments: [],
|
||||
returnValues: [],
|
||||
inPorts: [],
|
||||
outPorts: [],
|
||||
};
|
||||
};
|
||||
|
||||
const getComponentCategory: Function = (name?: string): ComponentCategory => {
|
||||
return {
|
||||
name: name || faker.datatype.uuid(),
|
||||
description: `Description for ${name}`,
|
||||
icon: IconProp.Activity,
|
||||
};
|
||||
};
|
||||
|
||||
describe('ComponentsModal', () => {
|
||||
const mockedCategories: ComponentCategory[] = [
|
||||
getComponentCategory(),
|
||||
getComponentCategory(),
|
||||
getComponentCategory(),
|
||||
getComponentCategory(),
|
||||
];
|
||||
|
||||
const mockedComponents: ComponentMetadata[] = [
|
||||
getComponentMetadata(mockedCategories[0]?.name),
|
||||
getComponentMetadata(mockedCategories[1]?.name),
|
||||
getComponentMetadata(mockedCategories[2]?.name),
|
||||
getComponentMetadata(mockedCategories[3]?.name),
|
||||
];
|
||||
|
||||
const mockOnCloseModal: jest.Mock = jest.fn();
|
||||
const mockOnComponentClick: jest.Mock = jest.fn();
|
||||
|
||||
it('should render without crashing', () => {
|
||||
render(
|
||||
<ComponentsModal
|
||||
componentsType={ComponentType.Component}
|
||||
onCloseModal={mockOnCloseModal}
|
||||
onComponentClick={mockOnComponentClick}
|
||||
components={mockedComponents}
|
||||
categories={mockedCategories}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
it('should display search input', () => {
|
||||
render(
|
||||
<ComponentsModal
|
||||
componentsType={ComponentType.Component}
|
||||
onCloseModal={mockOnCloseModal}
|
||||
onComponentClick={mockOnComponentClick}
|
||||
components={mockedComponents}
|
||||
categories={mockedCategories}
|
||||
/>
|
||||
);
|
||||
expect(screen.getByPlaceholderText('Search...')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should display categories and components', () => {
|
||||
render(
|
||||
<ComponentsModal
|
||||
componentsType={ComponentType.Component}
|
||||
onCloseModal={mockOnCloseModal}
|
||||
onComponentClick={mockOnComponentClick}
|
||||
components={mockedComponents}
|
||||
categories={mockedCategories}
|
||||
/>
|
||||
);
|
||||
for (const cat of mockedCategories) {
|
||||
expect(screen.getByText(cat.name)).toBeInTheDocument();
|
||||
}
|
||||
for (const comp of mockedComponents) {
|
||||
expect(screen.getByText(comp.title)).toBeInTheDocument();
|
||||
}
|
||||
});
|
||||
|
||||
it('should call onCloseModal when the close button is clicked', () => {
|
||||
render(
|
||||
<ComponentsModal
|
||||
componentsType={ComponentType.Component}
|
||||
onCloseModal={mockOnCloseModal}
|
||||
onComponentClick={mockOnComponentClick}
|
||||
components={mockedComponents}
|
||||
categories={mockedCategories}
|
||||
/>
|
||||
);
|
||||
fireEvent.click(screen.getByText('Close panel'));
|
||||
expect(mockOnCloseModal).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call onComponentClick when a component is selected', () => {
|
||||
render(
|
||||
<ComponentsModal
|
||||
componentsType={ComponentType.Component}
|
||||
onCloseModal={mockOnCloseModal}
|
||||
onComponentClick={mockOnComponentClick}
|
||||
components={mockedComponents}
|
||||
categories={mockedCategories}
|
||||
/>
|
||||
);
|
||||
for (const [idx, comp] of mockedComponents.entries()) {
|
||||
// simulate selecting a component
|
||||
fireEvent.click(screen.getByText(comp.title));
|
||||
expect(screen.getByText('Create')).not.toBeDisabled();
|
||||
|
||||
// simulate submitting
|
||||
fireEvent.click(screen.getByText('Create'));
|
||||
|
||||
// check if onComponentClick was called with the selected component's metadata
|
||||
expect(mockOnComponentClick).toHaveBeenNthCalledWith(idx + 1, comp);
|
||||
}
|
||||
});
|
||||
|
||||
it('should display a message when no components are available', () => {
|
||||
render(
|
||||
<ComponentsModal
|
||||
componentsType={ComponentType.Component}
|
||||
onCloseModal={mockOnCloseModal}
|
||||
onComponentClick={mockOnComponentClick}
|
||||
components={[]}
|
||||
categories={mockedCategories}
|
||||
/>
|
||||
);
|
||||
expect(
|
||||
screen.getByText(
|
||||
'No components that match your search. If you are looking for an integration that does not exist currently - you can use Custom Code or API component to build anything you like. If you are an enterprise customer, feel free to talk to us and we will build it for you.'
|
||||
)
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should not display categories when there are no categories', () => {
|
||||
render(
|
||||
<ComponentsModal
|
||||
componentsType={ComponentType.Component}
|
||||
onCloseModal={mockOnCloseModal}
|
||||
onComponentClick={mockOnComponentClick}
|
||||
components={mockedComponents}
|
||||
categories={[]}
|
||||
/>
|
||||
);
|
||||
mockedCategories.forEach((category: ComponentCategory) => {
|
||||
expect(screen.queryByText(category.name)).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should display no components message when search yields no results', () => {
|
||||
render(
|
||||
<ComponentsModal
|
||||
componentsType={ComponentType.Component}
|
||||
onCloseModal={mockOnCloseModal}
|
||||
onComponentClick={mockOnComponentClick}
|
||||
components={mockedComponents}
|
||||
categories={mockedCategories}
|
||||
/>
|
||||
);
|
||||
fireEvent.change(screen.getByPlaceholderText('Search...'), {
|
||||
target: { value: 'Non-existent Ccmponent' },
|
||||
});
|
||||
expect(
|
||||
screen.getByText(
|
||||
'No components that match your search. If you are looking for an integration that does not exist currently - you can use Custom Code or API component to build anything you like. If you are an enterprise customer, feel free to talk to us and we will build it for you.'
|
||||
)
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should disable submit button prop when no component is selected', () => {
|
||||
render(
|
||||
<ComponentsModal
|
||||
componentsType={ComponentType.Component}
|
||||
onCloseModal={mockOnCloseModal}
|
||||
onComponentClick={mockOnComponentClick}
|
||||
components={mockedComponents}
|
||||
categories={mockedCategories}
|
||||
/>
|
||||
);
|
||||
const submitButton: HTMLElement = screen.getByText('Create');
|
||||
expect(submitButton).toBeDisabled();
|
||||
});
|
||||
|
||||
it('should change submitButtonDisabled to false when a component is selected', () => {
|
||||
render(
|
||||
<ComponentsModal
|
||||
componentsType={ComponentType.Component}
|
||||
onCloseModal={mockOnCloseModal}
|
||||
onComponentClick={mockOnComponentClick}
|
||||
components={mockedComponents}
|
||||
categories={mockedCategories}
|
||||
/>
|
||||
);
|
||||
for (const comp of mockedComponents) {
|
||||
fireEvent.click(screen.getByText(comp.title));
|
||||
const submitButton: HTMLElement = screen.getByText('Create');
|
||||
expect(submitButton).not.toBeDisabled();
|
||||
}
|
||||
});
|
||||
|
||||
// search tests
|
||||
|
||||
it('should filter components based on search input', () => {
|
||||
render(
|
||||
<ComponentsModal
|
||||
componentsType={ComponentType.Component}
|
||||
onCloseModal={mockOnCloseModal}
|
||||
onComponentClick={mockOnComponentClick}
|
||||
components={mockedComponents}
|
||||
categories={mockedCategories}
|
||||
/>
|
||||
);
|
||||
|
||||
mockedComponents.forEach((comp: ComponentMetadata) => {
|
||||
const partialTitle: string = comp.title.substring(
|
||||
0,
|
||||
comp.title.length - comp.title.length / 2
|
||||
);
|
||||
fireEvent.change(screen.getByPlaceholderText('Search...'), {
|
||||
target: { value: partialTitle },
|
||||
});
|
||||
expect(screen.getByText(comp.title)).toBeInTheDocument();
|
||||
|
||||
// check other components are not displayed
|
||||
mockedComponents
|
||||
.filter((c: ComponentMetadata) => {
|
||||
return c.title !== comp.title;
|
||||
})
|
||||
.forEach((c: ComponentMetadata) => {
|
||||
return expect(
|
||||
screen.queryByText(c.title)
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should filter components based on description when searching', () => {
|
||||
render(
|
||||
<ComponentsModal
|
||||
componentsType={ComponentType.Component}
|
||||
onCloseModal={mockOnCloseModal}
|
||||
onComponentClick={mockOnComponentClick}
|
||||
components={mockedComponents}
|
||||
categories={mockedCategories}
|
||||
/>
|
||||
);
|
||||
mockedComponents.forEach((comp: ComponentMetadata) => {
|
||||
fireEvent.change(screen.getByPlaceholderText('Search...'), {
|
||||
target: { value: comp.description },
|
||||
});
|
||||
expect(screen.getByText(comp.title)).toBeInTheDocument();
|
||||
|
||||
// check other components are not displayed
|
||||
mockedComponents
|
||||
.filter((c: ComponentMetadata) => {
|
||||
return c.title !== comp.title;
|
||||
})
|
||||
.forEach((c: ComponentMetadata) => {
|
||||
return expect(
|
||||
screen.queryByText(c.title)
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should filter components based on category when searching', () => {
|
||||
render(
|
||||
<ComponentsModal
|
||||
componentsType={ComponentType.Component}
|
||||
onCloseModal={mockOnCloseModal}
|
||||
onComponentClick={mockOnComponentClick}
|
||||
components={mockedComponents}
|
||||
categories={mockedCategories}
|
||||
/>
|
||||
);
|
||||
mockedComponents.forEach((comp: ComponentMetadata) => {
|
||||
fireEvent.change(screen.getByPlaceholderText('Search...'), {
|
||||
target: { value: comp.category },
|
||||
});
|
||||
expect(screen.getByText(comp.title)).toBeInTheDocument();
|
||||
|
||||
// check other components are not displayed
|
||||
mockedComponents
|
||||
.filter((c: ComponentMetadata) => {
|
||||
return c.category !== comp.category;
|
||||
})
|
||||
.forEach((c: ComponentMetadata) => {
|
||||
return expect(
|
||||
screen.queryByText(c.title)
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should show all components when search is cleared', () => {
|
||||
render(
|
||||
<ComponentsModal
|
||||
componentsType={ComponentType.Component}
|
||||
onCloseModal={mockOnCloseModal}
|
||||
onComponentClick={mockOnComponentClick}
|
||||
components={mockedComponents}
|
||||
categories={mockedCategories}
|
||||
/>
|
||||
);
|
||||
mockedComponents.forEach((comp: ComponentMetadata) => {
|
||||
const searchInput: HTMLElement =
|
||||
screen.getByPlaceholderText('Search...');
|
||||
fireEvent.change(searchInput, { target: { value: comp.title } });
|
||||
fireEvent.change(searchInput, { target: { value: '' } }); // clear search
|
||||
|
||||
mockedComponents.forEach((c: ComponentMetadata) => {
|
||||
return expect(screen.getByText(c.title)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should return multiple components when similar titles match', () => {
|
||||
// we add a new component where its title is a substring of another component's title
|
||||
const commonWord: string =
|
||||
mockedComponents[0]?.title.substring(0, 5) || '';
|
||||
const newComponent: ComponentMetadata = getComponentMetadata(
|
||||
mockedCategories[1]?.name
|
||||
);
|
||||
newComponent.title += commonWord;
|
||||
mockedComponents.push(newComponent);
|
||||
const componentsWithCommonWord: ComponentMetadata[] =
|
||||
mockedComponents.filter((comp: ComponentMetadata) => {
|
||||
return comp.title.includes(commonWord);
|
||||
});
|
||||
|
||||
render(
|
||||
<ComponentsModal
|
||||
componentsType={ComponentType.Component}
|
||||
onCloseModal={mockOnCloseModal}
|
||||
onComponentClick={mockOnComponentClick}
|
||||
components={mockedComponents}
|
||||
categories={mockedCategories}
|
||||
/>
|
||||
);
|
||||
|
||||
fireEvent.change(screen.getByPlaceholderText('Search...'), {
|
||||
target: { value: commonWord },
|
||||
});
|
||||
componentsWithCommonWord.forEach((comp: ComponentMetadata) => {
|
||||
expect(screen.getByText(comp.title)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return return components with similar descriptions', () => {
|
||||
// we add a new component where its title is a substring of another component's description
|
||||
const partialDescription: string =
|
||||
mockedComponents[0]?.description.substring(0, 10) || '';
|
||||
const newComponent: ComponentMetadata = getComponentMetadata(
|
||||
mockedCategories[1]?.name
|
||||
);
|
||||
newComponent.title = partialDescription || '';
|
||||
mockedComponents.push(newComponent);
|
||||
render(
|
||||
<ComponentsModal
|
||||
componentsType={ComponentType.Component}
|
||||
onCloseModal={mockOnCloseModal}
|
||||
onComponentClick={mockOnComponentClick}
|
||||
components={mockedComponents}
|
||||
categories={mockedCategories}
|
||||
/>
|
||||
);
|
||||
|
||||
fireEvent.change(screen.getByPlaceholderText('Search...'), {
|
||||
target: { value: partialDescription },
|
||||
});
|
||||
expect(
|
||||
screen.getAllByText(new RegExp(partialDescription, 'i'))
|
||||
).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('should return components with the same category', () => {
|
||||
// we add two components with the same category as the first component
|
||||
const commonCategory: string | undefined =
|
||||
mockedComponents[0]?.category;
|
||||
mockedComponents.push(getComponentMetadata(commonCategory));
|
||||
mockedComponents.push(getComponentMetadata(commonCategory));
|
||||
const componentsInCommonCategory: ComponentMetadata[] =
|
||||
mockedComponents.filter((comp: ComponentMetadata) => {
|
||||
return comp.category === commonCategory;
|
||||
});
|
||||
|
||||
render(
|
||||
<ComponentsModal
|
||||
componentsType={ComponentType.Component}
|
||||
onCloseModal={mockOnCloseModal}
|
||||
onComponentClick={mockOnComponentClick}
|
||||
components={mockedComponents}
|
||||
categories={mockedCategories}
|
||||
/>
|
||||
);
|
||||
|
||||
fireEvent.change(screen.getByPlaceholderText('Search...'), {
|
||||
target: { value: commonCategory },
|
||||
});
|
||||
componentsInCommonCategory.forEach((comp: ComponentMetadata) => {
|
||||
expect(screen.getByText(comp.title)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
386
CommonUI/src/Tests/Components/FilePicker.test.tsx
Normal file
386
CommonUI/src/Tests/Components/FilePicker.test.tsx
Normal file
@@ -0,0 +1,386 @@
|
||||
import React from 'react';
|
||||
import { act } from 'react-test-renderer';
|
||||
|
||||
import { faker } from '@faker-js/faker';
|
||||
import {
|
||||
render,
|
||||
fireEvent,
|
||||
screen,
|
||||
waitFor,
|
||||
queryByAttribute,
|
||||
queryAllByAttribute,
|
||||
queryByTestId,
|
||||
} from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
|
||||
import MimeType from 'Common/Types/File/MimeType';
|
||||
import FileModel from 'Model/Models/File';
|
||||
import ModelAPI from '../../Utils/ModelAPI/ModelAPI';
|
||||
import HTTPResponse from 'Common/Types/API/HTTPResponse';
|
||||
import ObjectID from 'Common/Types/ObjectID';
|
||||
|
||||
import FilePicker from '../../Components/FilePicker/FilePicker';
|
||||
|
||||
const mockOnChange: jest.Mock = jest.fn();
|
||||
const mockOnBlur: jest.Mock = jest.fn();
|
||||
|
||||
jest.mock('../../Utils/ModelAPI/ModelAPI', () => {
|
||||
return {
|
||||
create: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
interface DefaultProps {
|
||||
onBlur: () => void;
|
||||
onChange: (files: FileModel[]) => void;
|
||||
mimeTypes: MimeType[];
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
initialValue?: FileModel | FileModel[];
|
||||
value?: FileModel[] | undefined;
|
||||
isMultiFilePicker?: boolean;
|
||||
readOnly?: boolean;
|
||||
}
|
||||
|
||||
interface DataTransfer {
|
||||
dataTransfer: {
|
||||
files: File[];
|
||||
types: string[];
|
||||
};
|
||||
}
|
||||
|
||||
const mockCreateResponse: Function = async (
|
||||
file: File
|
||||
): Promise<HTTPResponse<FileModel>> => {
|
||||
return new HTTPResponse(
|
||||
200,
|
||||
{
|
||||
file: (await file.arrayBuffer()) as Buffer,
|
||||
name: file.name,
|
||||
type: file.type,
|
||||
slug: file.name,
|
||||
isPublic: true,
|
||||
},
|
||||
{}
|
||||
);
|
||||
};
|
||||
|
||||
const mockFileModel: Function = async (file: File): Promise<FileModel> => {
|
||||
const fileModel: FileModel = new FileModel(new ObjectID('123'));
|
||||
fileModel.name = file.name;
|
||||
fileModel.type = file.type as MimeType;
|
||||
fileModel.slug = file.name;
|
||||
fileModel.isPublic = true;
|
||||
fileModel.file = (await file.arrayBuffer()) as Buffer;
|
||||
return fileModel;
|
||||
};
|
||||
|
||||
const mockFile: Function = (): File => {
|
||||
const mockArrayBuffer: jest.Mock = jest.fn();
|
||||
mockArrayBuffer.mockResolvedValue(new ArrayBuffer(10)); // Mocked array buffer of size 10
|
||||
|
||||
const file: File = new File(
|
||||
[faker.datatype.string()],
|
||||
faker.system.commonFileName(MimeType.png),
|
||||
{ type: MimeType.png }
|
||||
);
|
||||
file.arrayBuffer = mockArrayBuffer;
|
||||
return file;
|
||||
};
|
||||
|
||||
const defaultProps: DefaultProps = {
|
||||
onBlur: mockOnBlur,
|
||||
onChange: mockOnChange,
|
||||
mimeTypes: [MimeType.png],
|
||||
isOpen: true,
|
||||
onClose: jest.fn(),
|
||||
};
|
||||
|
||||
describe('FilePicker', () => {
|
||||
const MOCK_FILE_URL: string = 'https://mock-file-url';
|
||||
|
||||
beforeAll(() => {
|
||||
global.URL.createObjectURL = jest.fn(() => {
|
||||
return MOCK_FILE_URL;
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
(
|
||||
global.URL.createObjectURL as jest.MockedFunction<
|
||||
typeof global.URL.createObjectURL
|
||||
>
|
||||
).mockRestore();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
delete defaultProps.isMultiFilePicker;
|
||||
delete defaultProps.initialValue;
|
||||
delete defaultProps.value;
|
||||
delete defaultProps.readOnly;
|
||||
});
|
||||
|
||||
it('should render without crashing', () => {
|
||||
render(<FilePicker {...defaultProps} />);
|
||||
expect(screen.getByText('Upload a file')).toBeInTheDocument();
|
||||
expect(screen.getByRole('complementary')).toBeInTheDocument(); // aside element
|
||||
});
|
||||
|
||||
it('should render with initial value', async () => {
|
||||
defaultProps.initialValue = await mockFileModel(mockFile());
|
||||
const { container } = render(<FilePicker {...defaultProps} />);
|
||||
expect(
|
||||
queryByAttribute('src', container, MOCK_FILE_URL)
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should not render if file is missing the `file` attribute', async () => {
|
||||
const file: FileModel = await mockFileModel(mockFile());
|
||||
delete file.file;
|
||||
defaultProps.initialValue = file;
|
||||
const { container } = render(<FilePicker {...defaultProps} />);
|
||||
expect(
|
||||
queryByAttribute('src', container, MOCK_FILE_URL)
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render with initial value as array', async () => {
|
||||
defaultProps.initialValue = [
|
||||
await mockFileModel(mockFile()),
|
||||
await mockFileModel(mockFile()),
|
||||
];
|
||||
render(<FilePicker {...defaultProps} />);
|
||||
const { container } = render(<FilePicker {...defaultProps} />);
|
||||
expect(
|
||||
queryAllByAttribute('src', container, MOCK_FILE_URL)
|
||||
).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('should render with value array with one element', async () => {
|
||||
defaultProps.value = [await mockFileModel(mockFile())];
|
||||
const { container } = render(<FilePicker {...defaultProps} />);
|
||||
expect(
|
||||
queryByAttribute('src', container, MOCK_FILE_URL)
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render with value array with more than one element', async () => {
|
||||
defaultProps.value = [
|
||||
await mockFileModel(mockFile()),
|
||||
await mockFileModel(mockFile()),
|
||||
];
|
||||
render(<FilePicker {...defaultProps} />);
|
||||
const { container } = render(<FilePicker {...defaultProps} />);
|
||||
expect(
|
||||
queryAllByAttribute('src', container, MOCK_FILE_URL)
|
||||
).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('should not upload file when dropped and readOnly is true', async () => {
|
||||
defaultProps.readOnly = true;
|
||||
|
||||
const file: File = mockFile();
|
||||
const data: DataTransfer = {
|
||||
dataTransfer: {
|
||||
files: [file],
|
||||
types: ['Files'],
|
||||
},
|
||||
};
|
||||
|
||||
const createResponse: HTTPResponse<FileModel> =
|
||||
await mockCreateResponse(file);
|
||||
(
|
||||
ModelAPI.create as jest.MockedFunction<typeof ModelAPI.create>
|
||||
).mockResolvedValue(createResponse);
|
||||
|
||||
const { container } = render(<FilePicker {...defaultProps} />);
|
||||
|
||||
const dropzone: HTMLElement = screen.getByLabelText('Upload a file');
|
||||
fireEvent.drop(dropzone, data);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
queryByAttribute('src', container, MOCK_FILE_URL)
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw an "File too large" when uploading a file that fails on arrayBuffer()', async () => {
|
||||
const file: File = mockFile();
|
||||
file.arrayBuffer = jest
|
||||
.fn()
|
||||
.mockRejectedValue(new Error('File too large'));
|
||||
const data: DataTransfer = {
|
||||
dataTransfer: {
|
||||
files: [file],
|
||||
types: ['Files'],
|
||||
},
|
||||
};
|
||||
|
||||
const { container } = render(<FilePicker {...defaultProps} />);
|
||||
|
||||
const dropzone: HTMLElement = screen.getByLabelText('Upload a file');
|
||||
fireEvent.drop(dropzone, data);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
queryByAttribute('src', container, MOCK_FILE_URL)
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should upload a file when dropped', async () => {
|
||||
const file: File = mockFile();
|
||||
const data: DataTransfer = {
|
||||
dataTransfer: {
|
||||
files: [file],
|
||||
types: ['Files'],
|
||||
},
|
||||
};
|
||||
|
||||
const createResponse: HTTPResponse<FileModel> =
|
||||
await mockCreateResponse(file);
|
||||
(
|
||||
ModelAPI.create as jest.MockedFunction<typeof ModelAPI.create>
|
||||
).mockResolvedValue(createResponse);
|
||||
|
||||
const { container } = render(<FilePicker {...defaultProps} />);
|
||||
|
||||
const dropzone: HTMLElement = screen.getByLabelText('Upload a file');
|
||||
await act(async () => {
|
||||
fireEvent.drop(dropzone, data);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockOnChange).toHaveBeenCalledWith([createResponse.data]);
|
||||
expect(mockOnBlur).toHaveBeenCalled();
|
||||
expect(mockOnBlur).toHaveBeenCalled();
|
||||
expect(
|
||||
queryByAttribute('src', container, MOCK_FILE_URL)
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should upload a file when dropped', async () => {
|
||||
const file: File = mockFile();
|
||||
const data: DataTransfer = {
|
||||
dataTransfer: {
|
||||
files: [file],
|
||||
types: ['Files'],
|
||||
},
|
||||
};
|
||||
|
||||
const createResponse: HTTPResponse<FileModel> =
|
||||
await mockCreateResponse(file);
|
||||
(
|
||||
ModelAPI.create as jest.MockedFunction<typeof ModelAPI.create>
|
||||
).mockResolvedValue(createResponse);
|
||||
|
||||
const { container } = render(<FilePicker {...defaultProps} />);
|
||||
|
||||
const dropzone: HTMLElement = screen.getByLabelText('Upload a file');
|
||||
await act(async () => {
|
||||
fireEvent.drop(dropzone, data);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockOnChange).toHaveBeenCalledWith([createResponse.data]);
|
||||
expect(mockOnBlur).toHaveBeenCalled();
|
||||
expect(mockOnBlur).toHaveBeenCalled();
|
||||
expect(
|
||||
queryByAttribute('src', container, MOCK_FILE_URL)
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should show loader a file when files are being uploaded', async () => {
|
||||
const uploadPromise: Promise<unknown> = new Promise((resolve: any) => {
|
||||
(global as any).mockUploadResolve = resolve; // Store resolve function globally or in a scope accessible outside the test
|
||||
});
|
||||
|
||||
(
|
||||
ModelAPI.create as jest.MockedFunction<typeof ModelAPI.create>
|
||||
).mockImplementation((): any => {
|
||||
return uploadPromise;
|
||||
});
|
||||
|
||||
const file: File = mockFile();
|
||||
const data: DataTransfer = {
|
||||
dataTransfer: {
|
||||
files: [file],
|
||||
types: ['Files'],
|
||||
},
|
||||
};
|
||||
|
||||
const createResponse: HTTPResponse<FileModel> =
|
||||
await mockCreateResponse(file);
|
||||
|
||||
const { container } = render(<FilePicker {...defaultProps} />);
|
||||
|
||||
const dropzone: HTMLElement = screen.getByLabelText('Upload a file');
|
||||
await act(async () => {
|
||||
fireEvent.drop(dropzone, data);
|
||||
});
|
||||
|
||||
expect(queryByTestId(container, 'loader')).toBeInTheDocument();
|
||||
|
||||
(global as any).mockUploadResolve(createResponse);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockOnChange).toHaveBeenCalledWith([createResponse.data]);
|
||||
expect(mockOnBlur).toHaveBeenCalled();
|
||||
expect(mockOnBlur).toHaveBeenCalled();
|
||||
expect(
|
||||
queryByAttribute('src', container, MOCK_FILE_URL)
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should delete an uploaded file when clicking on it', async () => {
|
||||
const file: File = mockFile();
|
||||
const data: DataTransfer = {
|
||||
dataTransfer: {
|
||||
files: [file],
|
||||
types: ['Files'],
|
||||
},
|
||||
};
|
||||
|
||||
const createResponse: HTTPResponse<FileModel> =
|
||||
await mockCreateResponse(file);
|
||||
(
|
||||
ModelAPI.create as jest.MockedFunction<typeof ModelAPI.create>
|
||||
).mockResolvedValue(createResponse);
|
||||
|
||||
const { container } = render(<FilePicker {...defaultProps} />);
|
||||
|
||||
const dropzone: HTMLElement = screen.getByLabelText('Upload a file');
|
||||
await act(async () => {
|
||||
fireEvent.drop(dropzone, data);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
// file should be in the dropzone
|
||||
expect(
|
||||
queryByAttribute('src', container, MOCK_FILE_URL)
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
const deleteIcon: ChildNode = screen
|
||||
.getByRole('icon')
|
||||
.childNodes.item(0); // svg item
|
||||
// remove file by clicking on it
|
||||
if (deleteIcon) {
|
||||
await act(async () => {
|
||||
fireEvent.click(deleteIcon.childNodes.item(0), data);
|
||||
});
|
||||
}
|
||||
|
||||
await waitFor(() => {
|
||||
// file should have been removed
|
||||
expect(mockOnChange).toHaveBeenCalledWith([createResponse.data]);
|
||||
expect(
|
||||
queryByAttribute('src', container, MOCK_FILE_URL)
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
65
CommonUI/src/Tests/Components/Probe.test.tsx
Normal file
65
CommonUI/src/Tests/Components/Probe.test.tsx
Normal file
@@ -0,0 +1,65 @@
|
||||
import * as React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import ProbeElement from '../../Components/Probe/Probe';
|
||||
import Probe from 'Model/Models/Probe';
|
||||
import ObjectID from 'Common/Types/ObjectID';
|
||||
|
||||
describe('ProbeElement Component', () => {
|
||||
const mockProbe: Probe = new Probe();
|
||||
mockProbe.name = 'Test Probe';
|
||||
mockProbe.iconFileId = new ObjectID('12345');
|
||||
|
||||
test('should display the probe name', () => {
|
||||
render(<ProbeElement probe={mockProbe} />);
|
||||
const probeName: HTMLElement = screen.getByTestId('probe-name');
|
||||
expect(probeName).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('should display the image when iconFileId is present', () => {
|
||||
render(<ProbeElement probe={mockProbe} />);
|
||||
const imageElement: HTMLImageElement =
|
||||
screen.getByTestId('probe-image');
|
||||
expect(imageElement).toBeInTheDocument();
|
||||
expect(imageElement).toHaveAttribute('alt', 'Test Probe');
|
||||
});
|
||||
|
||||
test('should display the default icon when iconFileId is not present', () => {
|
||||
const probeWithoutIcon: Probe = new Probe();
|
||||
probeWithoutIcon.name = 'Test Probe';
|
||||
|
||||
render(<ProbeElement probe={probeWithoutIcon} />);
|
||||
const iconElement: HTMLElement = screen.getByTestId('probe-icon');
|
||||
expect(iconElement).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('should display "No probe found" when no probe is provided', () => {
|
||||
render(<ProbeElement probe={null} />);
|
||||
const noProbeText: HTMLElement = screen.getByTestId('probe-not-found');
|
||||
expect(noProbeText).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('should display the image with correct src when iconFileId is present', () => {
|
||||
const probeWithIcon: Probe = new Probe();
|
||||
probeWithIcon.iconFileId = new ObjectID('icon123');
|
||||
probeWithIcon.name = 'Probe with Icon';
|
||||
|
||||
render(<ProbeElement probe={probeWithIcon} />);
|
||||
const imageElement: HTMLImageElement =
|
||||
screen.getByTestId('probe-image');
|
||||
expect(imageElement).toBeInTheDocument();
|
||||
expect(imageElement).toHaveAttribute(
|
||||
'src',
|
||||
expect.stringContaining('icon123')
|
||||
);
|
||||
});
|
||||
|
||||
test('should display the default icon when iconFileId is not present', () => {
|
||||
const probeWithoutIcon: Probe = new Probe();
|
||||
probeWithoutIcon.name = 'Probe without Icon';
|
||||
|
||||
render(<ProbeElement probe={probeWithoutIcon} />);
|
||||
const iconElement: HTMLElement = screen.getByTestId('probe-icon');
|
||||
expect(iconElement).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
51
CommonUI/src/Tests/Components/ProgressBar.test.tsx
Normal file
51
CommonUI/src/Tests/Components/ProgressBar.test.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
import * as React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import ProgressBar from '../../Components/ProgressBar/ProgressBar';
|
||||
|
||||
describe('ProgressBar Component', () => {
|
||||
function getProgressBar(): HTMLElement {
|
||||
const element: HTMLElement = screen.getByTestId('progress-bar');
|
||||
if (!element) {
|
||||
throw 'Not Found';
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
test('should calculate and display the correct percentage', () => {
|
||||
render(<ProgressBar count={0} totalCount={100} suffix="items" />);
|
||||
const progressBar: HTMLElement = getProgressBar();
|
||||
expect(progressBar).toHaveStyle({ width: '0%' });
|
||||
});
|
||||
|
||||
test('should display the correct count and total count with suffix', () => {
|
||||
render(<ProgressBar count={30} totalCount={99} suffix="items" />);
|
||||
const countText: HTMLElement = screen.getByTestId('progress-bar-count');
|
||||
const totalCountText: HTMLElement = screen.getByTestId(
|
||||
'progress-bar-total-count'
|
||||
);
|
||||
expect(countText).toBeInTheDocument();
|
||||
expect(totalCountText).toBeInTheDocument();
|
||||
|
||||
expect(countText.innerHTML).toEqual('30 items');
|
||||
expect(totalCountText.innerHTML).toEqual('99 items');
|
||||
});
|
||||
|
||||
test('should handle zero total count without crashing', () => {
|
||||
render(<ProgressBar count={30} totalCount={0} suffix="items" />);
|
||||
const progressBar: HTMLElement = getProgressBar();
|
||||
expect(progressBar).toHaveStyle({ width: '100%' });
|
||||
});
|
||||
|
||||
test('should round up the percentage to the nearest integer', () => {
|
||||
render(<ProgressBar count={33} totalCount={100} suffix="items" />);
|
||||
const progressBar: HTMLElement = getProgressBar();
|
||||
expect(progressBar).toHaveStyle({ width: '33%' });
|
||||
});
|
||||
|
||||
test('should cap the percentage at 100 if count exceeds total count', () => {
|
||||
render(<ProgressBar count={150} totalCount={100} suffix="items" />);
|
||||
const progressBar: HTMLElement = getProgressBar();
|
||||
expect(progressBar).toHaveStyle({ width: '100%' });
|
||||
});
|
||||
});
|
||||
@@ -175,7 +175,8 @@ const DashboardHeader: FunctionComponent<ComponentProps> = (
|
||||
getAllEnvVars()
|
||||
) &&
|
||||
props.paymentMethodsCount !== undefined &&
|
||||
props.paymentMethodsCount === 0 ? (
|
||||
props.paymentMethodsCount === 0 &&
|
||||
!props.selectedProject.resellerId ? (
|
||||
<Button
|
||||
title="Add Card Details"
|
||||
onClick={() => {
|
||||
|
||||
@@ -90,6 +90,7 @@ const MonitorCriteriaInstanceElement: FunctionComponent<ComponentProps> = (
|
||||
}
|
||||
)?.color as Color) || Black
|
||||
}
|
||||
shouldAnimate={false}
|
||||
text={
|
||||
(props.monitorStatusOptions.find(
|
||||
(option: IncidentSeverity) => {
|
||||
|
||||
@@ -173,6 +173,7 @@ const MonitorStepsElement: FunctionComponent<ComponentProps> = (
|
||||
}
|
||||
)?.color as Color) || Black
|
||||
}
|
||||
shouldAnimate={false}
|
||||
text={
|
||||
(monitorStatusOptions.find(
|
||||
(option: IncidentSeverity) => {
|
||||
@@ -191,6 +192,7 @@ const MonitorStepsElement: FunctionComponent<ComponentProps> = (
|
||||
<Statusbubble
|
||||
color={defaultMonitorStatus.color!}
|
||||
text={defaultMonitorStatus.name!}
|
||||
shouldAnimate={false}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -214,7 +214,11 @@ const MonitorsTable: FunctionComponent<ComponentProps> = (
|
||||
|
||||
if (item && item['disableActiveMonitoring']) {
|
||||
return (
|
||||
<Statusbubble color={Grey} text={'Disabled'} />
|
||||
<Statusbubble
|
||||
shouldAnimate={false}
|
||||
color={Grey}
|
||||
text={'Disabled'}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -227,6 +231,7 @@ const MonitorsTable: FunctionComponent<ComponentProps> = (
|
||||
] as JSONObject
|
||||
)['color'] as Color
|
||||
}
|
||||
shouldAnimate={true}
|
||||
text={
|
||||
(
|
||||
item[
|
||||
|
||||
@@ -67,6 +67,7 @@ const CurrentStatusElement: FunctionComponent<ComponentProps> = (
|
||||
<Statusbubble
|
||||
color={currentGroupStatus.color! as Color}
|
||||
text={currentGroupStatus.name! as string}
|
||||
shouldAnimate={true}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -10,6 +10,7 @@ import Incident from 'Model/Models/Incident';
|
||||
import Project from 'Model/Models/Project';
|
||||
import Monitor from 'Model/Models/Monitor';
|
||||
import ScheduledMaintenance from 'Model/Models/ScheduledMaintenance';
|
||||
import SideMenuSection from 'CommonUI/src/Components/SideMenu/SideMenuSection';
|
||||
|
||||
export interface ComponentProps {
|
||||
project?: Project | undefined;
|
||||
@@ -20,61 +21,70 @@ const DashboardSideMenu: FunctionComponent<ComponentProps> = (
|
||||
): ReactElement => {
|
||||
return (
|
||||
<SideMenu>
|
||||
<SideMenuItem<Incident>
|
||||
link={{
|
||||
title: 'Active Incidents',
|
||||
to: RouteUtil.populateRouteParams(
|
||||
RouteMap[PageMap.HOME] as Route
|
||||
),
|
||||
}}
|
||||
icon={IconProp.Alert}
|
||||
badgeType={BadgeType.DANGER}
|
||||
modelType={Incident}
|
||||
countQuery={{
|
||||
projectId: props.project?._id,
|
||||
currentIncidentState: {
|
||||
isResolvedState: false,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<SideMenuSection title="Incidents">
|
||||
<SideMenuItem<Incident>
|
||||
link={{
|
||||
title: 'Active',
|
||||
to: RouteUtil.populateRouteParams(
|
||||
RouteMap[PageMap.HOME] as Route
|
||||
),
|
||||
}}
|
||||
icon={IconProp.Alert}
|
||||
badgeType={BadgeType.DANGER}
|
||||
modelType={Incident}
|
||||
countQuery={{
|
||||
projectId: props.project?._id,
|
||||
currentIncidentState: {
|
||||
isResolvedState: false,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</SideMenuSection>
|
||||
|
||||
<SideMenuItem<Monitor>
|
||||
link={{
|
||||
title: 'Inoperational Monitors',
|
||||
to: RouteUtil.populateRouteParams(
|
||||
RouteMap[PageMap.HOME_NOT_OPERATIONAL_MONITORS] as Route
|
||||
),
|
||||
}}
|
||||
icon={IconProp.AltGlobe}
|
||||
countQuery={{
|
||||
projectId: props.project?._id,
|
||||
currentMonitorStatus: {
|
||||
isOperationalState: false,
|
||||
},
|
||||
}}
|
||||
modelType={Monitor}
|
||||
badgeType={BadgeType.DANGER}
|
||||
/>
|
||||
<SideMenuSection title="Monitors">
|
||||
<SideMenuItem<Monitor>
|
||||
link={{
|
||||
title: 'Inoperational',
|
||||
to: RouteUtil.populateRouteParams(
|
||||
RouteMap[
|
||||
PageMap.HOME_NOT_OPERATIONAL_MONITORS
|
||||
] as Route
|
||||
),
|
||||
}}
|
||||
icon={IconProp.AltGlobe}
|
||||
countQuery={{
|
||||
projectId: props.project?._id,
|
||||
currentMonitorStatus: {
|
||||
isOperationalState: false,
|
||||
},
|
||||
}}
|
||||
modelType={Monitor}
|
||||
badgeType={BadgeType.DANGER}
|
||||
/>
|
||||
</SideMenuSection>
|
||||
|
||||
<SideMenuItem<ScheduledMaintenance>
|
||||
link={{
|
||||
title: 'Ongoing Events',
|
||||
to: RouteUtil.populateRouteParams(
|
||||
RouteMap[
|
||||
PageMap.HOME_ONGOING_SCHEDULED_MAINTENANCE_EVENTS
|
||||
] as Route
|
||||
),
|
||||
}}
|
||||
icon={IconProp.Clock}
|
||||
countQuery={{
|
||||
projectId: props.project?._id,
|
||||
currentScheduledMaintenanceState: {
|
||||
isOngoingState: true,
|
||||
},
|
||||
}}
|
||||
modelType={ScheduledMaintenance}
|
||||
badgeType={BadgeType.WARNING}
|
||||
/>
|
||||
<SideMenuSection title="Scheduled Events">
|
||||
<SideMenuItem<ScheduledMaintenance>
|
||||
link={{
|
||||
title: 'Ongoing',
|
||||
to: RouteUtil.populateRouteParams(
|
||||
RouteMap[
|
||||
PageMap
|
||||
.HOME_ONGOING_SCHEDULED_MAINTENANCE_EVENTS
|
||||
] as Route
|
||||
),
|
||||
}}
|
||||
icon={IconProp.Clock}
|
||||
countQuery={{
|
||||
projectId: props.project?._id,
|
||||
currentScheduledMaintenanceState: {
|
||||
isOngoingState: true,
|
||||
},
|
||||
}}
|
||||
modelType={ScheduledMaintenance}
|
||||
badgeType={BadgeType.WARNING}
|
||||
/>
|
||||
</SideMenuSection>
|
||||
</SideMenu>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -304,6 +304,7 @@ const MonitorView: FunctionComponent<PageComponentProps> = (
|
||||
<Statusbubble
|
||||
color={Grey}
|
||||
text={'Disabled'}
|
||||
shouldAnimate={false}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -317,6 +318,7 @@ const MonitorView: FunctionComponent<PageComponentProps> = (
|
||||
] as JSONObject
|
||||
)['color'] as Color
|
||||
}
|
||||
shouldAnimate={true}
|
||||
text={
|
||||
(
|
||||
item[
|
||||
|
||||
@@ -193,6 +193,7 @@ const StatusTimeline: FunctionComponent<PageComponentProps> = (
|
||||
'color'
|
||||
] as Color
|
||||
}
|
||||
shouldAnimate={false}
|
||||
text={
|
||||
(item['monitorStatus'] as JSONObject)[
|
||||
'name'
|
||||
|
||||
@@ -87,6 +87,7 @@ const MonitorGroupView: FunctionComponent<PageComponentProps> = (
|
||||
<Statusbubble
|
||||
text={currentGroupStatus?.name || 'Operational'}
|
||||
color={currentGroupStatus?.color || Green}
|
||||
shouldAnimate={true}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -263,6 +263,7 @@ const MonitorGroupResources: FunctionComponent<PageComponentProps> = (
|
||||
<Statusbubble
|
||||
color={monitorStatus.color! as Color}
|
||||
text={monitorStatus.name! as string}
|
||||
shouldAnimate={true}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
||||
@@ -153,6 +153,7 @@ const Monitors: FunctionComponent<PageComponentProps> = (
|
||||
<StatusBubble
|
||||
color={item['color'] as Color}
|
||||
text={item['name'] as string}
|
||||
shouldAnimate={false}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
||||
@@ -117,6 +117,7 @@ const ProbePage: FunctionComponent<PageComponentProps> = (
|
||||
<Statusbubble
|
||||
text={'Connected'}
|
||||
color={Green}
|
||||
shouldAnimate={true}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -125,6 +126,7 @@ const ProbePage: FunctionComponent<PageComponentProps> = (
|
||||
<Statusbubble
|
||||
text={'Disconnected'}
|
||||
color={Red}
|
||||
shouldAnimate={false}
|
||||
/>
|
||||
);
|
||||
},
|
||||
@@ -279,6 +281,7 @@ const ProbePage: FunctionComponent<PageComponentProps> = (
|
||||
<Statusbubble
|
||||
text={'Connected'}
|
||||
color={Green}
|
||||
shouldAnimate={true}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -287,6 +290,7 @@ const ProbePage: FunctionComponent<PageComponentProps> = (
|
||||
<Statusbubble
|
||||
text={'Disconnected'}
|
||||
color={Red}
|
||||
shouldAnimate={false}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
# IP Address of Probes in OneUptime.com
|
||||
|
||||
US: 51.159.99.250
|
||||
|
||||
EU: 62.210.173.51
|
||||
|
||||
These IP's can change, we will let you know in advance if this happens.
|
||||
|
||||
@@ -25,6 +25,7 @@ import Team from './Team';
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -36,11 +37,13 @@ import Team from './Team';
|
||||
delete: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanDeleteIncidentOwnerTeam,
|
||||
],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanEditIncidentOwnerTeam,
|
||||
],
|
||||
})
|
||||
@@ -66,6 +69,7 @@ export default class IncidentOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -102,6 +106,7 @@ export default class IncidentOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -132,6 +137,7 @@ export default class IncidentOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -168,6 +174,7 @@ export default class IncidentOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -197,6 +204,7 @@ export default class IncidentOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -233,6 +241,7 @@ export default class IncidentOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -263,6 +272,7 @@ export default class IncidentOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -299,6 +309,7 @@ export default class IncidentOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -381,6 +392,7 @@ export default class IncidentOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
|
||||
@@ -24,6 +24,7 @@ import Incident from './Incident';
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -35,11 +36,13 @@ import Incident from './Incident';
|
||||
delete: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanDeleteIncidentOwnerUser,
|
||||
],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanEditIncidentOwnerUser,
|
||||
],
|
||||
})
|
||||
@@ -65,6 +68,7 @@ export default class IncidentOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -101,6 +105,7 @@ export default class IncidentOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -131,6 +136,7 @@ export default class IncidentOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -167,6 +173,7 @@ export default class IncidentOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -196,6 +203,7 @@ export default class IncidentOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -232,6 +240,7 @@ export default class IncidentOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -262,6 +271,7 @@ export default class IncidentOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -298,6 +308,7 @@ export default class IncidentOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -380,6 +391,7 @@ export default class IncidentOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentOwnerUser,
|
||||
],
|
||||
read: [
|
||||
|
||||
@@ -25,6 +25,7 @@ import Team from './Team';
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentTemplateOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -36,11 +37,13 @@ import Team from './Team';
|
||||
delete: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanDeleteIncidentTemplateOwnerTeam,
|
||||
],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanEditIncidentTemplateOwnerTeam,
|
||||
],
|
||||
})
|
||||
@@ -66,6 +69,7 @@ export default class IncidentTemplateOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentTemplateOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -102,6 +106,7 @@ export default class IncidentTemplateOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentTemplateOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -132,6 +137,7 @@ export default class IncidentTemplateOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentTemplateOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -168,6 +174,7 @@ export default class IncidentTemplateOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentTemplateOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -197,6 +204,7 @@ export default class IncidentTemplateOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentTemplateOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -233,6 +241,7 @@ export default class IncidentTemplateOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentTemplateOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -263,6 +272,7 @@ export default class IncidentTemplateOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentTemplateOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -299,6 +309,7 @@ export default class IncidentTemplateOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentTemplateOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -381,6 +392,7 @@ export default class IncidentTemplateOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentTemplateOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
|
||||
@@ -24,22 +24,26 @@ import IncidentTemplate from './IncidentTemplate';
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentTemplateOwnerUser,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadIncidentTemplateOwnerUser,
|
||||
],
|
||||
delete: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanDeleteIncidentTemplateOwnerUser,
|
||||
],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanEditIncidentTemplateOwnerUser,
|
||||
],
|
||||
})
|
||||
@@ -65,12 +69,14 @@ export default class IncidentTemplateOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentTemplateOwnerUser,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadIncidentTemplateOwnerUser,
|
||||
],
|
||||
update: [],
|
||||
@@ -101,12 +107,14 @@ export default class IncidentTemplateOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentTemplateOwnerUser,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadIncidentTemplateOwnerUser,
|
||||
],
|
||||
update: [],
|
||||
@@ -131,12 +139,14 @@ export default class IncidentTemplateOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentTemplateOwnerUser,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadIncidentTemplateOwnerUser,
|
||||
],
|
||||
update: [],
|
||||
@@ -167,12 +177,14 @@ export default class IncidentTemplateOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentTemplateOwnerUser,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadIncidentTemplateOwnerUser,
|
||||
],
|
||||
update: [],
|
||||
@@ -196,12 +208,14 @@ export default class IncidentTemplateOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentTemplateOwnerUser,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadIncidentTemplateOwnerUser,
|
||||
],
|
||||
update: [],
|
||||
@@ -232,12 +246,14 @@ export default class IncidentTemplateOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentTemplateOwnerUser,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadIncidentTemplateOwnerUser,
|
||||
],
|
||||
update: [],
|
||||
@@ -262,12 +278,14 @@ export default class IncidentTemplateOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentTemplateOwnerUser,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadIncidentTemplateOwnerUser,
|
||||
],
|
||||
update: [],
|
||||
@@ -298,12 +316,14 @@ export default class IncidentTemplateOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentTemplateOwnerUser,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadIncidentTemplateOwnerUser,
|
||||
],
|
||||
update: [],
|
||||
@@ -327,6 +347,7 @@ export default class IncidentTemplateOwnerUser extends AccessControlModel {
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadIncidentTemplateOwnerUser,
|
||||
],
|
||||
update: [],
|
||||
@@ -359,6 +380,7 @@ export default class IncidentTemplateOwnerUser extends AccessControlModel {
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadIncidentTemplateOwnerUser,
|
||||
],
|
||||
update: [],
|
||||
@@ -380,12 +402,14 @@ export default class IncidentTemplateOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateIncidentTemplateOwnerUser,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadIncidentTemplateOwnerUser,
|
||||
],
|
||||
update: [],
|
||||
|
||||
@@ -35,6 +35,7 @@ import { PlanSelect } from 'Common/Types/Billing/SubscriptionPlan';
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateProjectLabel,
|
||||
],
|
||||
read: [
|
||||
@@ -46,11 +47,13 @@ import { PlanSelect } from 'Common/Types/Billing/SubscriptionPlan';
|
||||
delete: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanDeleteProjectLabel,
|
||||
],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanEditProjectLabel,
|
||||
],
|
||||
})
|
||||
@@ -78,6 +81,7 @@ export default class Label extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateProjectLabel,
|
||||
],
|
||||
read: [
|
||||
@@ -114,6 +118,7 @@ export default class Label extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateProjectLabel,
|
||||
],
|
||||
read: [
|
||||
@@ -144,6 +149,7 @@ export default class Label extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateProjectLabel,
|
||||
],
|
||||
read: [
|
||||
@@ -155,6 +161,7 @@ export default class Label extends AccessControlModel {
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanEditProjectLabel,
|
||||
],
|
||||
})
|
||||
@@ -201,6 +208,7 @@ export default class Label extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateProjectLabel,
|
||||
],
|
||||
read: [
|
||||
@@ -212,6 +220,7 @@ export default class Label extends AccessControlModel {
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanEditProjectLabel,
|
||||
],
|
||||
})
|
||||
@@ -232,6 +241,7 @@ export default class Label extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateProjectLabel,
|
||||
],
|
||||
read: [
|
||||
@@ -268,6 +278,7 @@ export default class Label extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateProjectLabel,
|
||||
],
|
||||
read: [
|
||||
@@ -350,6 +361,7 @@ export default class Label extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateProjectLabel,
|
||||
],
|
||||
read: [
|
||||
@@ -361,6 +373,7 @@ export default class Label extends AccessControlModel {
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanEditProjectLabel,
|
||||
],
|
||||
})
|
||||
|
||||
@@ -25,6 +25,7 @@ import Team from './Team';
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorGroupOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -36,11 +37,13 @@ import Team from './Team';
|
||||
delete: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanDeleteMonitorGroupOwnerTeam,
|
||||
],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanEditMonitorGroupOwnerTeam,
|
||||
],
|
||||
})
|
||||
@@ -66,6 +69,7 @@ export default class MonitorGroupOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorGroupOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -102,6 +106,7 @@ export default class MonitorGroupOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorGroupOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -132,6 +137,7 @@ export default class MonitorGroupOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorGroupOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -168,6 +174,7 @@ export default class MonitorGroupOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorGroupOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -197,6 +204,7 @@ export default class MonitorGroupOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorGroupOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -233,6 +241,7 @@ export default class MonitorGroupOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorGroupOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -263,6 +272,7 @@ export default class MonitorGroupOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorGroupOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -299,6 +309,7 @@ export default class MonitorGroupOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorGroupOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -381,6 +392,7 @@ export default class MonitorGroupOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorGroupOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
|
||||
@@ -24,6 +24,7 @@ import MonitorGroup from './MonitorGroup';
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorGroupOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -35,11 +36,13 @@ import MonitorGroup from './MonitorGroup';
|
||||
delete: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanDeleteMonitorGroupOwnerUser,
|
||||
],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanEditMonitorGroupOwnerUser,
|
||||
],
|
||||
})
|
||||
@@ -65,6 +68,7 @@ export default class MonitorGroupOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorGroupOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -101,6 +105,7 @@ export default class MonitorGroupOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorGroupOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -131,6 +136,7 @@ export default class MonitorGroupOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorGroupOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -167,6 +173,7 @@ export default class MonitorGroupOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorGroupOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -196,6 +203,7 @@ export default class MonitorGroupOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorGroupOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -232,6 +240,7 @@ export default class MonitorGroupOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorGroupOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -262,6 +271,7 @@ export default class MonitorGroupOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorGroupOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -298,6 +308,7 @@ export default class MonitorGroupOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorGroupOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -380,6 +391,7 @@ export default class MonitorGroupOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorGroupOwnerUser,
|
||||
],
|
||||
read: [
|
||||
|
||||
@@ -25,6 +25,7 @@ import Team from './Team';
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -36,11 +37,13 @@ import Team from './Team';
|
||||
delete: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanDeleteMonitorOwnerTeam,
|
||||
],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanEditMonitorOwnerTeam,
|
||||
],
|
||||
})
|
||||
@@ -66,6 +69,7 @@ export default class MonitorOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -102,6 +106,7 @@ export default class MonitorOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -132,6 +137,7 @@ export default class MonitorOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -168,6 +174,7 @@ export default class MonitorOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -197,6 +204,7 @@ export default class MonitorOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -233,6 +241,7 @@ export default class MonitorOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -263,6 +272,7 @@ export default class MonitorOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -299,6 +309,7 @@ export default class MonitorOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -381,6 +392,7 @@ export default class MonitorOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
|
||||
@@ -24,6 +24,7 @@ import Monitor from './Monitor';
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -35,11 +36,13 @@ import Monitor from './Monitor';
|
||||
delete: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanDeleteMonitorOwnerUser,
|
||||
],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanEditMonitorOwnerUser,
|
||||
],
|
||||
})
|
||||
@@ -65,6 +68,7 @@ export default class MonitorOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -101,6 +105,7 @@ export default class MonitorOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -131,6 +136,7 @@ export default class MonitorOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -167,6 +173,7 @@ export default class MonitorOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -196,6 +203,7 @@ export default class MonitorOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -232,6 +240,7 @@ export default class MonitorOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -262,6 +271,7 @@ export default class MonitorOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -298,6 +308,7 @@ export default class MonitorOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -380,6 +391,7 @@ export default class MonitorOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateMonitorOwnerUser,
|
||||
],
|
||||
read: [
|
||||
|
||||
@@ -40,6 +40,7 @@ import { PlanSelect } from 'Common/Types/Billing/SubscriptionPlan';
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectSMTPConfig,
|
||||
],
|
||||
delete: [
|
||||
@@ -75,6 +76,7 @@ export default class ProjectSmtpConfig extends BaseModel {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectSMTPConfig,
|
||||
],
|
||||
update: [],
|
||||
@@ -110,6 +112,7 @@ export default class ProjectSmtpConfig extends BaseModel {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectSMTPConfig,
|
||||
],
|
||||
update: [],
|
||||
@@ -139,6 +142,7 @@ export default class ProjectSmtpConfig extends BaseModel {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectSMTPConfig,
|
||||
],
|
||||
update: [
|
||||
@@ -165,6 +169,7 @@ export default class ProjectSmtpConfig extends BaseModel {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectSMTPConfig,
|
||||
],
|
||||
update: [],
|
||||
@@ -192,6 +197,7 @@ export default class ProjectSmtpConfig extends BaseModel {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectSMTPConfig,
|
||||
],
|
||||
update: [
|
||||
@@ -222,6 +228,7 @@ export default class ProjectSmtpConfig extends BaseModel {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectSMTPConfig,
|
||||
],
|
||||
update: [],
|
||||
@@ -257,6 +264,7 @@ export default class ProjectSmtpConfig extends BaseModel {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectSMTPConfig,
|
||||
],
|
||||
update: [],
|
||||
@@ -279,6 +287,7 @@ export default class ProjectSmtpConfig extends BaseModel {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectSMTPConfig,
|
||||
],
|
||||
update: [],
|
||||
@@ -310,6 +319,7 @@ export default class ProjectSmtpConfig extends BaseModel {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectSMTPConfig,
|
||||
],
|
||||
update: [],
|
||||
@@ -338,6 +348,7 @@ export default class ProjectSmtpConfig extends BaseModel {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectSMTPConfig,
|
||||
],
|
||||
update: [
|
||||
@@ -388,6 +399,7 @@ export default class ProjectSmtpConfig extends BaseModel {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectSMTPConfig,
|
||||
],
|
||||
update: [
|
||||
@@ -414,6 +426,7 @@ export default class ProjectSmtpConfig extends BaseModel {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectSMTPConfig,
|
||||
],
|
||||
update: [
|
||||
@@ -439,6 +452,7 @@ export default class ProjectSmtpConfig extends BaseModel {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectSMTPConfig,
|
||||
],
|
||||
update: [
|
||||
@@ -465,6 +479,7 @@ export default class ProjectSmtpConfig extends BaseModel {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectSMTPConfig,
|
||||
],
|
||||
update: [
|
||||
@@ -490,6 +505,7 @@ export default class ProjectSmtpConfig extends BaseModel {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectSMTPConfig,
|
||||
],
|
||||
update: [
|
||||
|
||||
@@ -48,9 +48,7 @@ import Team from './Team';
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectUser,
|
||||
Permission.UnAuthorizedSsoUser,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectUser,
|
||||
Permission.UnAuthorizedSsoUser,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectSSO,
|
||||
],
|
||||
delete: [
|
||||
@@ -88,8 +86,7 @@ export default class ProjectSSO extends BaseModel {
|
||||
Permission.ProjectUser,
|
||||
Permission.Public,
|
||||
Permission.UnAuthorizedSsoUser,
|
||||
Permission.ProjectUser,
|
||||
Permission.UnAuthorizedSsoUser,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectSSO,
|
||||
],
|
||||
update: [],
|
||||
@@ -128,6 +125,7 @@ export default class ProjectSSO extends BaseModel {
|
||||
Permission.ProjectUser,
|
||||
Permission.Public,
|
||||
Permission.UnAuthorizedSsoUser,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectSSO,
|
||||
Permission.ProjectUser,
|
||||
Permission.UnAuthorizedSsoUser,
|
||||
@@ -162,6 +160,7 @@ export default class ProjectSSO extends BaseModel {
|
||||
Permission.ProjectUser,
|
||||
Permission.Public,
|
||||
Permission.UnAuthorizedSsoUser,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectSSO,
|
||||
Permission.ProjectUser,
|
||||
Permission.UnAuthorizedSsoUser,
|
||||
@@ -199,6 +198,7 @@ export default class ProjectSSO extends BaseModel {
|
||||
Permission.ProjectUser,
|
||||
Permission.Public,
|
||||
Permission.UnAuthorizedSsoUser,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectSSO,
|
||||
],
|
||||
update: [
|
||||
@@ -227,7 +227,6 @@ export default class ProjectSSO extends BaseModel {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
|
||||
Permission.CanReadProjectSSO,
|
||||
],
|
||||
update: [
|
||||
@@ -257,7 +256,6 @@ export default class ProjectSSO extends BaseModel {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
|
||||
Permission.CanReadProjectSSO,
|
||||
],
|
||||
update: [
|
||||
@@ -287,6 +285,7 @@ export default class ProjectSSO extends BaseModel {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectSSO,
|
||||
Permission.Public,
|
||||
Permission.ProjectUser,
|
||||
@@ -320,6 +319,7 @@ export default class ProjectSSO extends BaseModel {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectSSO,
|
||||
],
|
||||
update: [
|
||||
@@ -391,7 +391,6 @@ export default class ProjectSSO extends BaseModel {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
|
||||
Permission.CanReadProjectSSO,
|
||||
],
|
||||
update: [
|
||||
@@ -421,6 +420,7 @@ export default class ProjectSSO extends BaseModel {
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectSSO,
|
||||
],
|
||||
update: [],
|
||||
@@ -457,6 +457,7 @@ export default class ProjectSSO extends BaseModel {
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectSSO,
|
||||
],
|
||||
update: [],
|
||||
@@ -480,6 +481,7 @@ export default class ProjectSSO extends BaseModel {
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectSSO,
|
||||
],
|
||||
update: [],
|
||||
@@ -512,6 +514,7 @@ export default class ProjectSSO extends BaseModel {
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectSSO,
|
||||
],
|
||||
update: [],
|
||||
@@ -540,6 +543,7 @@ export default class ProjectSSO extends BaseModel {
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectUser,
|
||||
Permission.UnAuthorizedSsoUser,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectSSO,
|
||||
],
|
||||
update: [
|
||||
@@ -566,6 +570,7 @@ export default class ProjectSSO extends BaseModel {
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectSSO,
|
||||
],
|
||||
update: [],
|
||||
|
||||
@@ -25,6 +25,7 @@ import Team from './Team';
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateScheduledMaintenanceOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -36,11 +37,13 @@ import Team from './Team';
|
||||
delete: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanDeleteScheduledMaintenanceOwnerTeam,
|
||||
],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanEditScheduledMaintenanceOwnerTeam,
|
||||
],
|
||||
})
|
||||
@@ -67,6 +70,7 @@ export default class ScheduledMaintenanceOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateScheduledMaintenanceOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -103,6 +107,7 @@ export default class ScheduledMaintenanceOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateScheduledMaintenanceOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -133,6 +138,7 @@ export default class ScheduledMaintenanceOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateScheduledMaintenanceOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -169,6 +175,7 @@ export default class ScheduledMaintenanceOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateScheduledMaintenanceOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -198,6 +205,7 @@ export default class ScheduledMaintenanceOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateScheduledMaintenanceOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -234,6 +242,7 @@ export default class ScheduledMaintenanceOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateScheduledMaintenanceOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -264,6 +273,7 @@ export default class ScheduledMaintenanceOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateScheduledMaintenanceOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -300,6 +310,7 @@ export default class ScheduledMaintenanceOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateScheduledMaintenanceOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -382,6 +393,7 @@ export default class ScheduledMaintenanceOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateScheduledMaintenanceOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
|
||||
@@ -24,6 +24,7 @@ import ScheduledMaintenance from './ScheduledMaintenance';
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateScheduledMaintenanceOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -35,11 +36,13 @@ import ScheduledMaintenance from './ScheduledMaintenance';
|
||||
delete: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanDeleteScheduledMaintenanceOwnerUser,
|
||||
],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanEditScheduledMaintenanceOwnerUser,
|
||||
],
|
||||
})
|
||||
@@ -66,6 +69,7 @@ export default class ScheduledMaintenanceOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateScheduledMaintenanceOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -102,6 +106,7 @@ export default class ScheduledMaintenanceOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateScheduledMaintenanceOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -132,6 +137,7 @@ export default class ScheduledMaintenanceOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateScheduledMaintenanceOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -168,6 +174,7 @@ export default class ScheduledMaintenanceOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateScheduledMaintenanceOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -197,6 +204,7 @@ export default class ScheduledMaintenanceOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateScheduledMaintenanceOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -233,6 +241,7 @@ export default class ScheduledMaintenanceOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateScheduledMaintenanceOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -263,6 +272,7 @@ export default class ScheduledMaintenanceOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateScheduledMaintenanceOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -299,6 +309,7 @@ export default class ScheduledMaintenanceOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateScheduledMaintenanceOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -381,6 +392,7 @@ export default class ScheduledMaintenanceOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateScheduledMaintenanceOwnerUser,
|
||||
],
|
||||
read: [
|
||||
|
||||
@@ -28,10 +28,18 @@ import EnableWorkflow from 'Common/Types/Database/EnableWorkflow';
|
||||
import IconProp from 'Common/Types/Icon/IconProp';
|
||||
import StatusPage from './StatusPage';
|
||||
import EnableDocumentation from 'Common/Types/Database/EnableDocumentation';
|
||||
import TableBillingAccessControl from 'Common/Types/Database/AccessControl/TableBillingAccessControl';
|
||||
import { PlanSelect } from 'Common/Types/Billing/SubscriptionPlan';
|
||||
|
||||
@EnableDocumentation()
|
||||
@TenantColumn('projectId')
|
||||
@CanAccessIfCanReadOn('statusPages')
|
||||
@TableBillingAccessControl({
|
||||
create: PlanSelect.Growth,
|
||||
read: PlanSelect.Free,
|
||||
update: PlanSelect.Growth,
|
||||
delete: PlanSelect.Growth,
|
||||
})
|
||||
@TableAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
|
||||
@@ -21,8 +21,16 @@ import IconProp from 'Common/Types/Icon/IconProp';
|
||||
import StatusPage from './StatusPage';
|
||||
import CanAccessIfCanReadOn from 'Common/Types/Database/CanAccessIfCanReadOn';
|
||||
import EnableDocumentation from 'Common/Types/Database/EnableDocumentation';
|
||||
import TableBillingAccessControl from 'Common/Types/Database/AccessControl/TableBillingAccessControl';
|
||||
import { PlanSelect } from 'Common/Types/Billing/SubscriptionPlan';
|
||||
|
||||
@EnableDocumentation()
|
||||
@TableBillingAccessControl({
|
||||
create: PlanSelect.Growth,
|
||||
read: PlanSelect.Free,
|
||||
update: PlanSelect.Growth,
|
||||
delete: PlanSelect.Growth,
|
||||
})
|
||||
@CanAccessIfCanReadOn('statusPage')
|
||||
@TenantColumn('projectId')
|
||||
@TableAccessControl({
|
||||
|
||||
@@ -25,6 +25,7 @@ import Team from './Team';
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateStatusPageOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -66,6 +67,7 @@ export default class StatusPageOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateStatusPageOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -102,6 +104,7 @@ export default class StatusPageOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateStatusPageOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -132,6 +135,7 @@ export default class StatusPageOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateStatusPageOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -168,6 +172,7 @@ export default class StatusPageOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateStatusPageOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -197,6 +202,7 @@ export default class StatusPageOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateStatusPageOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -233,6 +239,7 @@ export default class StatusPageOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateStatusPageOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -263,6 +270,7 @@ export default class StatusPageOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateStatusPageOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -299,6 +307,7 @@ export default class StatusPageOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateStatusPageOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
@@ -381,6 +390,7 @@ export default class StatusPageOwnerTeam extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateStatusPageOwnerTeam,
|
||||
],
|
||||
read: [
|
||||
|
||||
@@ -24,6 +24,7 @@ import StatusPage from './StatusPage';
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateStatusPageOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -65,6 +66,7 @@ export default class StatusPageOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateStatusPageOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -101,6 +103,7 @@ export default class StatusPageOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateStatusPageOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -131,6 +134,7 @@ export default class StatusPageOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateStatusPageOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -167,6 +171,7 @@ export default class StatusPageOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateStatusPageOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -196,6 +201,7 @@ export default class StatusPageOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateStatusPageOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -232,6 +238,7 @@ export default class StatusPageOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateStatusPageOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -262,6 +269,7 @@ export default class StatusPageOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateStatusPageOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -298,6 +306,7 @@ export default class StatusPageOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateStatusPageOwnerUser,
|
||||
],
|
||||
read: [
|
||||
@@ -380,6 +389,7 @@ export default class StatusPageOwnerUser extends AccessControlModel {
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanCreateStatusPageOwnerUser,
|
||||
],
|
||||
read: [
|
||||
|
||||
@@ -47,6 +47,7 @@ import { PlanSelect } from 'Common/Types/Billing/SubscriptionPlan';
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectTeam,
|
||||
],
|
||||
delete: [
|
||||
@@ -92,6 +93,7 @@ export default class TeamPermission extends BaseModel {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectTeam,
|
||||
],
|
||||
update: [],
|
||||
@@ -128,6 +130,7 @@ export default class TeamPermission extends BaseModel {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectTeam,
|
||||
],
|
||||
update: [],
|
||||
@@ -158,6 +161,7 @@ export default class TeamPermission extends BaseModel {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectTeam,
|
||||
],
|
||||
update: [],
|
||||
@@ -193,6 +197,7 @@ export default class TeamPermission extends BaseModel {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectTeam,
|
||||
],
|
||||
update: [],
|
||||
@@ -219,6 +224,7 @@ export default class TeamPermission extends BaseModel {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectTeam,
|
||||
],
|
||||
update: [],
|
||||
@@ -254,6 +260,7 @@ export default class TeamPermission extends BaseModel {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectTeam,
|
||||
],
|
||||
update: [],
|
||||
@@ -280,6 +287,7 @@ export default class TeamPermission extends BaseModel {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectTeam,
|
||||
],
|
||||
update: [],
|
||||
@@ -334,6 +342,7 @@ export default class TeamPermission extends BaseModel {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectTeam,
|
||||
],
|
||||
update: [
|
||||
@@ -368,6 +377,7 @@ export default class TeamPermission extends BaseModel {
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.CanReadProjectTeam,
|
||||
],
|
||||
update: [
|
||||
|
||||
@@ -46,6 +46,7 @@ import EnableDocumentation from 'Common/Types/Database/EnableDocumentation';
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CanCreateWorkflow,
|
||||
Permission.ProjectMember,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
@@ -57,10 +58,12 @@ import EnableDocumentation from 'Common/Types/Database/EnableDocumentation';
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CanDeleteWorkflow,
|
||||
Permission.ProjectMember,
|
||||
],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CanDeleteWorkflow,
|
||||
Permission.CanEditWorkflow,
|
||||
],
|
||||
})
|
||||
@@ -83,6 +86,7 @@ export default class Workflow extends BaseModel {
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CanCreateWorkflow,
|
||||
Permission.ProjectMember,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
@@ -119,6 +123,7 @@ export default class Workflow extends BaseModel {
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CanCreateWorkflow,
|
||||
Permission.ProjectMember,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
@@ -149,6 +154,7 @@ export default class Workflow extends BaseModel {
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CanCreateWorkflow,
|
||||
Permission.ProjectMember,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
@@ -159,6 +165,7 @@ export default class Workflow extends BaseModel {
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CanDeleteWorkflow,
|
||||
Permission.CanEditWorkflow,
|
||||
],
|
||||
})
|
||||
@@ -206,6 +213,7 @@ export default class Workflow extends BaseModel {
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CanCreateWorkflow,
|
||||
Permission.ProjectMember,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
@@ -216,6 +224,7 @@ export default class Workflow extends BaseModel {
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CanDeleteWorkflow,
|
||||
Permission.CanEditWorkflow,
|
||||
],
|
||||
})
|
||||
@@ -237,6 +246,7 @@ export default class Workflow extends BaseModel {
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CanCreateWorkflow,
|
||||
Permission.ProjectMember,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
@@ -273,6 +283,7 @@ export default class Workflow extends BaseModel {
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CanCreateWorkflow,
|
||||
Permission.ProjectMember,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
@@ -355,6 +366,7 @@ export default class Workflow extends BaseModel {
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CanCreateWorkflow,
|
||||
Permission.ProjectMember,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
@@ -365,6 +377,7 @@ export default class Workflow extends BaseModel {
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CanDeleteWorkflow,
|
||||
Permission.CanEditWorkflow,
|
||||
],
|
||||
})
|
||||
@@ -385,6 +398,7 @@ export default class Workflow extends BaseModel {
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CanCreateWorkflow,
|
||||
Permission.ProjectMember,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
@@ -395,6 +409,7 @@ export default class Workflow extends BaseModel {
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CanDeleteWorkflow,
|
||||
Permission.CanEditWorkflow,
|
||||
],
|
||||
})
|
||||
@@ -417,6 +432,7 @@ export default class Workflow extends BaseModel {
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CanCreateWorkflow,
|
||||
Permission.ProjectMember,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
@@ -427,6 +443,7 @@ export default class Workflow extends BaseModel {
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CanDeleteWorkflow,
|
||||
Permission.CanEditWorkflow,
|
||||
],
|
||||
})
|
||||
|
||||
@@ -20,49 +20,68 @@ router.get(
|
||||
res: ExpressResponse,
|
||||
next: NextFunction
|
||||
): Promise<void> => {
|
||||
try {
|
||||
logger.info('Request Headers: ');
|
||||
logger.info(req.headers);
|
||||
logger.info('Request Body: ');
|
||||
logger.info(req.body);
|
||||
|
||||
const responseCode: number | undefined =
|
||||
LocalCache.getNumber('TestServer', 'responseCode') || 200;
|
||||
const responseTime: number | undefined =
|
||||
LocalCache.getNumber('TestServer', 'responseTime') || 0;
|
||||
const responseBody: string | undefined =
|
||||
LocalCache.getString('TestServer', 'responseBody') || '';
|
||||
let responseHeaders: JSONValue | undefined =
|
||||
LocalCache.getJSON('TestServer', 'responseHeaders') || {};
|
||||
|
||||
logger.info('Response Code: ' + responseCode);
|
||||
logger.info('Response Time: ' + responseTime);
|
||||
logger.info('Response Body: ');
|
||||
logger.info(responseBody);
|
||||
logger.info('Response Headers: ');
|
||||
logger.info(responseHeaders);
|
||||
|
||||
if (responseHeaders && typeof responseHeaders === Typeof.String) {
|
||||
responseHeaders = JSON.parse(responseHeaders.toString());
|
||||
}
|
||||
|
||||
if (responseTime > 0) {
|
||||
await Sleep.sleep(responseTime);
|
||||
}
|
||||
|
||||
// middleware marks the probe as alive.
|
||||
// so we don't need to do anything here.
|
||||
return Response.sendCustomResponse(
|
||||
req,
|
||||
res,
|
||||
responseCode,
|
||||
responseBody,
|
||||
responseHeaders ? (responseHeaders as any) : {}
|
||||
);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
await returnResponse(req, res, next);
|
||||
}
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/',
|
||||
async (
|
||||
req: ExpressRequest,
|
||||
res: ExpressResponse,
|
||||
next: NextFunction
|
||||
): Promise<void> => {
|
||||
await returnResponse(req, res, next);
|
||||
}
|
||||
);
|
||||
|
||||
const returnResponse: Function = async (
|
||||
req: ExpressRequest,
|
||||
res: ExpressResponse,
|
||||
next: NextFunction
|
||||
): Promise<void> => {
|
||||
try {
|
||||
logger.info('Request Headers: ');
|
||||
logger.info(req.headers);
|
||||
logger.info('Request Body: ');
|
||||
logger.info(req.body);
|
||||
|
||||
const responseCode: number | undefined =
|
||||
LocalCache.getNumber('TestServer', 'responseCode') || 200;
|
||||
const responseTime: number | undefined =
|
||||
LocalCache.getNumber('TestServer', 'responseTime') || 0;
|
||||
const responseBody: string | undefined =
|
||||
LocalCache.getString('TestServer', 'responseBody') || '';
|
||||
let responseHeaders: JSONValue | undefined =
|
||||
LocalCache.getJSON('TestServer', 'responseHeaders') || {};
|
||||
|
||||
logger.info('Response Code: ' + responseCode);
|
||||
logger.info('Response Time: ' + responseTime);
|
||||
logger.info('Response Body: ');
|
||||
logger.info(responseBody);
|
||||
logger.info('Response Headers: ');
|
||||
logger.info(responseHeaders);
|
||||
|
||||
if (responseHeaders && typeof responseHeaders === Typeof.String) {
|
||||
responseHeaders = JSON.parse(responseHeaders.toString());
|
||||
}
|
||||
|
||||
if (responseTime > 0) {
|
||||
await Sleep.sleep(responseTime);
|
||||
}
|
||||
|
||||
// middleware marks the probe as alive.
|
||||
// so we don't need to do anything here.
|
||||
return Response.sendCustomResponse(
|
||||
req,
|
||||
res,
|
||||
responseCode,
|
||||
responseBody,
|
||||
responseHeaders ? (responseHeaders as any) : {}
|
||||
);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
};
|
||||
|
||||
export default router;
|
||||
|
||||
Reference in New Issue
Block a user