mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 08:42:13 +02:00
Compare commits
63 Commits
mult-slack
...
dash-chunk
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b198dc0ec8 | ||
|
|
b0a3f8d60f | ||
|
|
83a13635cf | ||
|
|
a2c1744e8c | ||
|
|
4271ddbdcb | ||
|
|
6ffb081a02 | ||
|
|
16a9edbfcd | ||
|
|
b8cd3ce1c1 | ||
|
|
b86aee7f2a | ||
|
|
2cde167445 | ||
|
|
9bd6b011fe | ||
|
|
538eef5660 | ||
|
|
e1a343ae38 | ||
|
|
8b42af35c1 | ||
|
|
fc9026a8d8 | ||
|
|
86edee35c1 | ||
|
|
109c276bc5 | ||
|
|
8040dd0f56 | ||
|
|
00d4148b6b | ||
|
|
dec03bc3a8 | ||
|
|
46a9f95fc0 | ||
|
|
8b2f9bc778 | ||
|
|
fcc6223850 | ||
|
|
c9bc214e86 | ||
|
|
2897a937ba | ||
|
|
f3cd7be143 | ||
|
|
f324a4e864 | ||
|
|
f6a8cef649 | ||
|
|
770ef007a4 | ||
|
|
dafa0cc5d9 | ||
|
|
196e9cae10 | ||
|
|
d0d26d20b2 | ||
|
|
6a90ee97bf | ||
|
|
f2a2644b0e | ||
|
|
5cb2ac8c8b | ||
|
|
6751d59b2f | ||
|
|
aefc649743 | ||
|
|
cfba73665c | ||
|
|
049c5d003c | ||
|
|
fd8998952d | ||
|
|
5ca85e4915 | ||
|
|
aa401291b6 | ||
|
|
bf3d90871d | ||
|
|
4a4dff9264 | ||
|
|
fd3f75e4e2 | ||
|
|
43fc5acdda | ||
|
|
c7ca6138f3 | ||
|
|
87475b00c4 | ||
|
|
d5613cc4bd | ||
|
|
b1c9d9a645 | ||
|
|
01c6101ae9 | ||
|
|
ec56609bf4 | ||
|
|
e5f652a950 | ||
|
|
749bd2e41d | ||
|
|
cc23416ad8 | ||
|
|
86fda9ba16 | ||
|
|
969983043b | ||
|
|
2b64dd0b1d | ||
|
|
3a514969dc | ||
|
|
10d006890c | ||
|
|
2cb719d53a | ||
|
|
eafb543371 | ||
|
|
5800fe4f7a |
98
.github/workflows/release.yml
vendored
98
.github/workflows/release.yml
vendored
@@ -1913,12 +1913,51 @@ jobs:
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
# Docker compose needs a lot of space to build images, so we need to free up some space first in the GitHub Actions runner
|
||||
# Aggressively free disk space before anything else
|
||||
- name: Aggressive Disk Cleanup
|
||||
run: |
|
||||
echo "=== Disk space BEFORE cleanup ==="
|
||||
df -h /
|
||||
# Remove pre-installed software not needed for this job
|
||||
sudo rm -rf /usr/share/dotnet || true
|
||||
sudo rm -rf /usr/local/lib/android || true
|
||||
sudo rm -rf /opt/ghc || true
|
||||
sudo rm -rf /opt/hostedtoolcache || true
|
||||
sudo rm -rf /usr/local/share/boost || true
|
||||
sudo rm -rf /usr/local/graalvm/ || true
|
||||
sudo rm -rf /usr/local/share/powershell || true
|
||||
sudo rm -rf /usr/local/share/chromium || true
|
||||
sudo rm -rf /usr/local/lib/node_modules || true
|
||||
sudo rm -rf /usr/share/swift || true
|
||||
sudo rm -rf /usr/share/miniconda || true
|
||||
sudo rm -rf /usr/lib/google-cloud-sdk || true
|
||||
sudo rm -rf /usr/lib/jvm || true
|
||||
sudo rm -rf /usr/lib/firefox || true
|
||||
sudo rm -rf /usr/lib/heroku || true
|
||||
sudo rm -rf /usr/local/julia* || true
|
||||
sudo rm -rf /opt/az || true
|
||||
sudo rm -rf /opt/microsoft || true
|
||||
sudo rm -rf /opt/pipx || true
|
||||
sudo rm -rf /opt/actionarchivecache || true
|
||||
sudo rm -rf /imagegeneration || true
|
||||
sudo rm -rf /usr/share/az_* || true
|
||||
sudo rm -rf /usr/share/sbt || true
|
||||
sudo rm -rf /usr/share/gradle* || true
|
||||
sudo rm -rf /usr/share/kotlinc || true
|
||||
sudo rm -rf /usr/share/ri || true
|
||||
sudo rm -rf /usr/local/.ghcup || true
|
||||
# Clean apt cache
|
||||
sudo apt-get clean || true
|
||||
sudo rm -rf /var/lib/apt/lists/* || true
|
||||
# Clean temp files
|
||||
sudo rm -rf /tmp/* || true
|
||||
# Docker cleanup
|
||||
docker system prune -af --volumes || true
|
||||
echo "=== Disk space AFTER aggressive cleanup ==="
|
||||
df -h /
|
||||
- name: Free Disk Space (Ubuntu)
|
||||
uses: jlumbroso/free-disk-space@main
|
||||
with:
|
||||
# this might remove tools that are actually needed,
|
||||
# if set to "true" but frees about 6 GB
|
||||
tool-cache: true
|
||||
android: true
|
||||
dotnet: true
|
||||
@@ -1926,6 +1965,10 @@ jobs:
|
||||
large-packages: true
|
||||
docker-images: true
|
||||
swap-storage: true
|
||||
- name: Final Disk Space Check
|
||||
run: |
|
||||
echo "=== Disk space after all cleanup ==="
|
||||
df -h /
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
@@ -2001,12 +2044,51 @@ jobs:
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
# Docker compose needs a lot of space to build images, so we need to free up some space first in the GitHub Actions runner
|
||||
# Aggressively free disk space before anything else
|
||||
- name: Aggressive Disk Cleanup
|
||||
run: |
|
||||
echo "=== Disk space BEFORE cleanup ==="
|
||||
df -h /
|
||||
# Remove pre-installed software not needed for this job
|
||||
sudo rm -rf /usr/share/dotnet || true
|
||||
sudo rm -rf /usr/local/lib/android || true
|
||||
sudo rm -rf /opt/ghc || true
|
||||
sudo rm -rf /opt/hostedtoolcache || true
|
||||
sudo rm -rf /usr/local/share/boost || true
|
||||
sudo rm -rf /usr/local/graalvm/ || true
|
||||
sudo rm -rf /usr/local/share/powershell || true
|
||||
sudo rm -rf /usr/local/share/chromium || true
|
||||
sudo rm -rf /usr/local/lib/node_modules || true
|
||||
sudo rm -rf /usr/share/swift || true
|
||||
sudo rm -rf /usr/share/miniconda || true
|
||||
sudo rm -rf /usr/lib/google-cloud-sdk || true
|
||||
sudo rm -rf /usr/lib/jvm || true
|
||||
sudo rm -rf /usr/lib/firefox || true
|
||||
sudo rm -rf /usr/lib/heroku || true
|
||||
sudo rm -rf /usr/local/julia* || true
|
||||
sudo rm -rf /opt/az || true
|
||||
sudo rm -rf /opt/microsoft || true
|
||||
sudo rm -rf /opt/pipx || true
|
||||
sudo rm -rf /opt/actionarchivecache || true
|
||||
sudo rm -rf /imagegeneration || true
|
||||
sudo rm -rf /usr/share/az_* || true
|
||||
sudo rm -rf /usr/share/sbt || true
|
||||
sudo rm -rf /usr/share/gradle* || true
|
||||
sudo rm -rf /usr/share/kotlinc || true
|
||||
sudo rm -rf /usr/share/ri || true
|
||||
sudo rm -rf /usr/local/.ghcup || true
|
||||
# Clean apt cache
|
||||
sudo apt-get clean || true
|
||||
sudo rm -rf /var/lib/apt/lists/* || true
|
||||
# Clean temp files
|
||||
sudo rm -rf /tmp/* || true
|
||||
# Docker cleanup
|
||||
docker system prune -af --volumes || true
|
||||
echo "=== Disk space AFTER aggressive cleanup ==="
|
||||
df -h /
|
||||
- name: Free Disk Space (Ubuntu)
|
||||
uses: jlumbroso/free-disk-space@main
|
||||
with:
|
||||
# this might remove tools that are actually needed,
|
||||
# if set to "true" but frees about 6 GB
|
||||
tool-cache: true
|
||||
android: true
|
||||
dotnet: true
|
||||
@@ -2014,6 +2096,10 @@ jobs:
|
||||
large-packages: true
|
||||
docker-images: true
|
||||
swap-storage: true
|
||||
- name: Final Disk Space Check
|
||||
run: |
|
||||
echo "=== Disk space after all cleanup ==="
|
||||
df -h /
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
|
||||
@@ -521,6 +521,19 @@ const dataTypeDetails: Dictionary<DataTypePageData> = {
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "dnsMonitor",
|
||||
type: "MonitorStepDnsMonitor",
|
||||
required: false,
|
||||
description:
|
||||
"Configuration for DNS monitoring. Required for DNS monitor type. Defines query name (domain), record type, optional DNS server, port, timeout, and retry settings. See MonitorStepDnsMonitor.",
|
||||
typeLinks: [
|
||||
{
|
||||
label: "MonitorStepDnsMonitor",
|
||||
path: "monitor-step-dns-monitor",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
values: [],
|
||||
jsonExample: JSON.stringify(
|
||||
@@ -2560,6 +2573,31 @@ const dataTypeDetails: Dictionary<DataTypePageData> = {
|
||||
description:
|
||||
"Whether the SNMP device is reachable. Use with 'True' or 'False'. Applies to: SNMP monitors.",
|
||||
},
|
||||
{
|
||||
value: "DNS Response Time (in ms)",
|
||||
description:
|
||||
"The DNS query response time in milliseconds. Use with numeric FilterTypes. Applies to: DNS monitors.",
|
||||
},
|
||||
{
|
||||
value: "DNS Is Online",
|
||||
description:
|
||||
"Whether the DNS resolution succeeded. Use with 'True' or 'False'. Applies to: DNS monitors.",
|
||||
},
|
||||
{
|
||||
value: "DNS Record Value",
|
||||
description:
|
||||
"The value of a DNS record returned by the query. Use with string FilterTypes (Contains, EqualTo, etc.). Applies to: DNS monitors.",
|
||||
},
|
||||
{
|
||||
value: "DNSSEC Is Valid",
|
||||
description:
|
||||
"Whether DNSSEC validation passed (AD flag present). Use with 'True' or 'False'. Applies to: DNS monitors.",
|
||||
},
|
||||
{
|
||||
value: "DNS Record Exists",
|
||||
description:
|
||||
"Whether any DNS records were returned for the query. Use with 'True' or 'False'. Applies to: DNS monitors.",
|
||||
},
|
||||
{
|
||||
value: "JavaScript Expression",
|
||||
description:
|
||||
@@ -3112,6 +3150,93 @@ const dataTypeDetails: Dictionary<DataTypePageData> = {
|
||||
2,
|
||||
),
|
||||
},
|
||||
"monitor-step-dns-monitor": {
|
||||
title: "MonitorStepDnsMonitor",
|
||||
description:
|
||||
"Configuration for a DNS monitor step. Defines the domain to query, record type, optional custom DNS server, and timeout settings. Used as the 'dnsMonitor' property on a MonitorStep when the monitor type is 'DNS'. The criteria filters can then use 'DNS Is Online', 'DNS Response Time (in ms)', 'DNS Record Value', 'DNSSEC Is Valid', and 'DNS Record Exists' as CheckOn values.",
|
||||
isEnum: false,
|
||||
relatedTypes: [
|
||||
{
|
||||
name: "MonitorStep",
|
||||
path: "monitor-step",
|
||||
relationship: "Parent that holds this as dnsMonitor property",
|
||||
},
|
||||
{
|
||||
name: "CheckOn",
|
||||
path: "check-on",
|
||||
relationship: "Use DNS-specific CheckOn values with DNS monitors",
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
name: "queryName",
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "The domain name to query (e.g., 'example.com').",
|
||||
},
|
||||
{
|
||||
name: "recordType",
|
||||
type: "string (enum)",
|
||||
required: true,
|
||||
description:
|
||||
"The DNS record type to query. Possible values: 'A', 'AAAA', 'CNAME', 'MX', 'NS', 'TXT', 'SOA', 'PTR', 'SRV', 'CAA'.",
|
||||
},
|
||||
{
|
||||
name: "hostname",
|
||||
type: "string",
|
||||
required: false,
|
||||
description:
|
||||
"Custom DNS server to use for the query (e.g., '8.8.8.8'). Leave empty to use system default DNS resolver.",
|
||||
},
|
||||
{
|
||||
name: "port",
|
||||
type: "number",
|
||||
required: false,
|
||||
description: "DNS port. Default is 53.",
|
||||
},
|
||||
{
|
||||
name: "timeout",
|
||||
type: "number",
|
||||
required: false,
|
||||
description:
|
||||
"Timeout for DNS queries in milliseconds. Default is 5000 (5 seconds).",
|
||||
},
|
||||
{
|
||||
name: "retries",
|
||||
type: "number",
|
||||
required: false,
|
||||
description: "Number of retries for failed DNS queries. Default is 3.",
|
||||
},
|
||||
],
|
||||
values: [],
|
||||
jsonExample: JSON.stringify(
|
||||
{
|
||||
"// Example 1: Basic A record lookup": {
|
||||
queryName: "example.com",
|
||||
recordType: "A",
|
||||
timeout: 5000,
|
||||
retries: 3,
|
||||
},
|
||||
"// Example 2: MX record with custom DNS server": {
|
||||
queryName: "example.com",
|
||||
recordType: "MX",
|
||||
hostname: "8.8.8.8",
|
||||
port: 53,
|
||||
timeout: 5000,
|
||||
retries: 3,
|
||||
},
|
||||
"// Example 3: TXT record for SPF verification": {
|
||||
queryName: "example.com",
|
||||
recordType: "TXT",
|
||||
hostname: "1.1.1.1",
|
||||
timeout: 5000,
|
||||
retries: 3,
|
||||
},
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
export default class ServiceHandler {
|
||||
|
||||
6
App/package-lock.json
generated
6
App/package-lock.json
generated
@@ -4192,9 +4192,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.14.1",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz",
|
||||
"integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==",
|
||||
"version": "6.14.2",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz",
|
||||
"integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"side-channel": "^1.1.0"
|
||||
|
||||
@@ -39,6 +39,14 @@ export default class OpenSourceDeploymentAPI extends BaseAPI<
|
||||
(body["oneuptimeVersion"] as string) || "unknown";
|
||||
deployment.instanceUrl = (body["instanceUrl"] as string) || "";
|
||||
|
||||
// Skip localhost instances - these are default/unconfigured deployments.
|
||||
if (
|
||||
deployment.instanceUrl === "http://localhost/" ||
|
||||
deployment.instanceUrl === "http://localhost"
|
||||
) {
|
||||
return Response.sendEmptySuccessResponse(req, res);
|
||||
}
|
||||
|
||||
await OpenSourceDeploymentService.create({
|
||||
data: deployment,
|
||||
props: {
|
||||
|
||||
@@ -177,10 +177,15 @@ export default class UserMiddleware {
|
||||
try {
|
||||
oneuptimeRequest.userAuthorization = JSONWebToken.decode(accessToken);
|
||||
} catch (err) {
|
||||
// if the token is invalid or expired, it'll throw this error.
|
||||
// if the token is invalid or expired, return 401 so clients can refresh the token.
|
||||
logger.error(err);
|
||||
oneuptimeRequest.userType = UserType.Public;
|
||||
return next();
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new NotAuthenticatedException(
|
||||
"AccessToken is invalid or expired. Please refresh your token.",
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (oneuptimeRequest.userAuthorization.isMasterAdmin) {
|
||||
|
||||
@@ -127,6 +127,14 @@ export class Service extends DatabaseService<Model> {
|
||||
monitorDestination = `${monitorDestination}:${port}`;
|
||||
}
|
||||
}
|
||||
|
||||
// For DNS monitors, use the queryName from dnsMonitor config
|
||||
if (monitorType === MonitorType.DNS && firstStep?.data?.dnsMonitor) {
|
||||
monitorDestination = firstStep.data.dnsMonitor.queryName || "";
|
||||
if (firstStep.data.dnsMonitor.hostname) {
|
||||
monitorDestination = `${monitorDestination} @${firstStep.data.dnsMonitor.hostname}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1805,9 +1805,18 @@ export class Service extends DatabaseService<WorkspaceNotificationRule> {
|
||||
logger.debug("New channel template name:");
|
||||
logger.debug(notificationChannels);
|
||||
|
||||
/*
|
||||
* Sanitize the suffix for workspace channel names.
|
||||
* When no custom prefix is set, the default "#" prefix (e.g. "#42") produces
|
||||
* invalid Slack channel names (e.g. "oneuptime-alert-#42"). Strip characters
|
||||
* that are not valid in Slack/Teams channel names.
|
||||
*/
|
||||
const sanitizedSuffix: string = data.channelNameSiffix
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9\-_]/g, "");
|
||||
|
||||
// add suffix and then check if it is already added or not.
|
||||
const channelName: string =
|
||||
notificationChannels + data.channelNameSiffix;
|
||||
const channelName: string = notificationChannels + sanitizedSuffix;
|
||||
|
||||
logger.debug("Final channel name with suffix:");
|
||||
logger.debug(channelName);
|
||||
|
||||
183
Common/Server/Utils/Monitor/Criteria/DnsMonitorCriteria.ts
Normal file
183
Common/Server/Utils/Monitor/Criteria/DnsMonitorCriteria.ts
Normal file
@@ -0,0 +1,183 @@
|
||||
import DataToProcess from "../DataToProcess";
|
||||
import CompareCriteria from "./CompareCriteria";
|
||||
import {
|
||||
CheckOn,
|
||||
CriteriaFilter,
|
||||
FilterType,
|
||||
} from "../../../../Types/Monitor/CriteriaFilter";
|
||||
import DnsMonitorResponse from "../../../../Types/Monitor/DnsMonitor/DnsMonitorResponse";
|
||||
import ProbeMonitorResponse from "../../../../Types/Probe/ProbeMonitorResponse";
|
||||
import EvaluateOverTime from "./EvaluateOverTime";
|
||||
import CaptureSpan from "../../Telemetry/CaptureSpan";
|
||||
import logger from "../../Logger";
|
||||
|
||||
export default class DnsMonitorCriteria {
|
||||
@CaptureSpan()
|
||||
public static async isMonitorInstanceCriteriaFilterMet(input: {
|
||||
dataToProcess: DataToProcess;
|
||||
criteriaFilter: CriteriaFilter;
|
||||
}): Promise<string | null> {
|
||||
let threshold: number | string | undefined | null =
|
||||
input.criteriaFilter.value;
|
||||
|
||||
const dataToProcess: ProbeMonitorResponse =
|
||||
input.dataToProcess as ProbeMonitorResponse;
|
||||
|
||||
const dnsResponse: DnsMonitorResponse | undefined =
|
||||
dataToProcess.dnsResponse;
|
||||
|
||||
let overTimeValue: Array<number | boolean> | number | boolean | undefined =
|
||||
undefined;
|
||||
|
||||
if (
|
||||
input.criteriaFilter.evaluateOverTime &&
|
||||
input.criteriaFilter.evaluateOverTimeOptions
|
||||
) {
|
||||
try {
|
||||
overTimeValue = await EvaluateOverTime.getValueOverTime({
|
||||
projectId: (input.dataToProcess as ProbeMonitorResponse).projectId,
|
||||
monitorId: input.dataToProcess.monitorId!,
|
||||
evaluateOverTimeOptions: input.criteriaFilter.evaluateOverTimeOptions,
|
||||
metricType: input.criteriaFilter.checkOn,
|
||||
});
|
||||
|
||||
if (Array.isArray(overTimeValue) && overTimeValue.length === 0) {
|
||||
overTimeValue = undefined;
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error(
|
||||
`Error in getting over time value for ${input.criteriaFilter.checkOn}`,
|
||||
);
|
||||
logger.error(err);
|
||||
overTimeValue = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if DNS is online
|
||||
if (input.criteriaFilter.checkOn === CheckOn.DnsIsOnline) {
|
||||
const currentIsOnline: boolean | Array<boolean> =
|
||||
(overTimeValue as Array<boolean>) ||
|
||||
(input.dataToProcess as ProbeMonitorResponse).isOnline;
|
||||
|
||||
return CompareCriteria.compareCriteriaBoolean({
|
||||
value: currentIsOnline,
|
||||
criteriaFilter: input.criteriaFilter,
|
||||
});
|
||||
}
|
||||
|
||||
// Check DNS response time
|
||||
if (input.criteriaFilter.checkOn === CheckOn.DnsResponseTime) {
|
||||
threshold = CompareCriteria.convertToNumber(threshold);
|
||||
|
||||
if (threshold === null || threshold === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const currentResponseTime: number | Array<number> =
|
||||
(overTimeValue as Array<number>) ||
|
||||
dnsResponse?.responseTimeInMs ||
|
||||
(input.dataToProcess as ProbeMonitorResponse).responseTimeInMs;
|
||||
|
||||
if (currentResponseTime === null || currentResponseTime === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return CompareCriteria.compareCriteriaNumbers({
|
||||
value: currentResponseTime,
|
||||
threshold: threshold as number,
|
||||
criteriaFilter: input.criteriaFilter,
|
||||
});
|
||||
}
|
||||
|
||||
// Check if DNS record exists
|
||||
if (input.criteriaFilter.checkOn === CheckOn.DnsRecordExists) {
|
||||
const exists: boolean = Boolean(
|
||||
dnsResponse?.records && dnsResponse.records.length > 0,
|
||||
);
|
||||
|
||||
const isTrue: boolean =
|
||||
input.criteriaFilter.filterType === FilterType.True;
|
||||
const isFalse: boolean =
|
||||
input.criteriaFilter.filterType === FilterType.False;
|
||||
|
||||
if (exists && isTrue) {
|
||||
return `DNS records exist for the query.`;
|
||||
}
|
||||
|
||||
if (!exists && isFalse) {
|
||||
return `No DNS records found for the query.`;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check DNSSEC validity
|
||||
if (input.criteriaFilter.checkOn === CheckOn.DnssecIsValid) {
|
||||
const isTrue: boolean =
|
||||
input.criteriaFilter.filterType === FilterType.True;
|
||||
const isFalse: boolean =
|
||||
input.criteriaFilter.filterType === FilterType.False;
|
||||
|
||||
if (dnsResponse?.isDnssecValid === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (dnsResponse.isDnssecValid && isTrue) {
|
||||
return `DNSSEC is valid.`;
|
||||
}
|
||||
|
||||
if (!dnsResponse.isDnssecValid && isFalse) {
|
||||
return `DNSSEC is not valid.`;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check DNS record value
|
||||
if (input.criteriaFilter.checkOn === CheckOn.DnsRecordValue) {
|
||||
if (!dnsResponse?.records || dnsResponse.records.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check if any record value matches the criteria
|
||||
for (const record of dnsResponse.records) {
|
||||
const recordValue: string = record.value;
|
||||
|
||||
// Try numeric comparison first
|
||||
if (
|
||||
typeof threshold === "number" ||
|
||||
(typeof threshold === "string" && !isNaN(Number(threshold)))
|
||||
) {
|
||||
const numericThreshold: number | null =
|
||||
CompareCriteria.convertToNumber(threshold);
|
||||
|
||||
if (numericThreshold !== null && !isNaN(Number(recordValue))) {
|
||||
const result: string | null =
|
||||
CompareCriteria.compareCriteriaNumbers({
|
||||
value: Number(recordValue),
|
||||
threshold: numericThreshold,
|
||||
criteriaFilter: input.criteriaFilter,
|
||||
});
|
||||
|
||||
if (result) {
|
||||
return `DNS record (${record.type}): ${result}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// String comparison
|
||||
const result: string | null = CompareCriteria.compareCriteriaStrings({
|
||||
value: recordValue,
|
||||
threshold: String(threshold),
|
||||
criteriaFilter: input.criteriaFilter,
|
||||
});
|
||||
|
||||
if (result) {
|
||||
return `DNS record (${record.type}): ${result}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import MetricMonitorCriteria from "./Criteria/MetricMonitorCriteria";
|
||||
import TraceMonitorCriteria from "./Criteria/TraceMonitorCriteria";
|
||||
import ExceptionMonitorCriteria from "./Criteria/ExceptionMonitorCriteria";
|
||||
import SnmpMonitorCriteria from "./Criteria/SnmpMonitorCriteria";
|
||||
import DnsMonitorCriteria from "./Criteria/DnsMonitorCriteria";
|
||||
import MonitorCriteriaMessageBuilder from "./MonitorCriteriaMessageBuilder";
|
||||
import MonitorCriteriaDataExtractor from "./MonitorCriteriaDataExtractor";
|
||||
import MonitorCriteriaMessageFormatter from "./MonitorCriteriaMessageFormatter";
|
||||
@@ -493,6 +494,18 @@ ${contextBlock}
|
||||
}
|
||||
}
|
||||
|
||||
if (input.monitor.monitorType === MonitorType.DNS) {
|
||||
const dnsMonitorResult: string | null =
|
||||
await DnsMonitorCriteria.isMonitorInstanceCriteriaFilterMet({
|
||||
dataToProcess: input.dataToProcess,
|
||||
criteriaFilter: input.criteriaFilter,
|
||||
});
|
||||
|
||||
if (dnsMonitorResult) {
|
||||
return dnsMonitorResult;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,9 @@ import SyntheticMonitorResponse from "../../../Types/Monitor/SyntheticMonitors/S
|
||||
import SnmpMonitorResponse, {
|
||||
SnmpOidResponse,
|
||||
} from "../../../Types/Monitor/SnmpMonitor/SnmpMonitorResponse";
|
||||
import DnsMonitorResponse, {
|
||||
DnsRecordResponse,
|
||||
} from "../../../Types/Monitor/DnsMonitor/DnsMonitorResponse";
|
||||
import Typeof from "../../../Types/Typeof";
|
||||
import VMUtil from "../VM/VMAPI";
|
||||
import DataToProcess from "./DataToProcess";
|
||||
@@ -240,6 +243,40 @@ export default class MonitorTemplateUtil {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (data.monitorType === MonitorType.DNS) {
|
||||
const dnsResponse: DnsMonitorResponse | undefined = (
|
||||
data.dataToProcess as ProbeMonitorResponse
|
||||
).dnsResponse;
|
||||
|
||||
storageMap = {
|
||||
isOnline: (data.dataToProcess as ProbeMonitorResponse).isOnline,
|
||||
responseTimeInMs: dnsResponse?.responseTimeInMs,
|
||||
failureCause: dnsResponse?.failureCause,
|
||||
isTimeout: dnsResponse?.isTimeout,
|
||||
isDnssecValid: dnsResponse?.isDnssecValid,
|
||||
} as JSONObject;
|
||||
|
||||
// Add DNS records
|
||||
if (dnsResponse?.records) {
|
||||
storageMap["records"] = dnsResponse.records.map(
|
||||
(record: DnsRecordResponse) => {
|
||||
return {
|
||||
type: record.type,
|
||||
value: record.value,
|
||||
ttl: record.ttl,
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
// Add record values as a flat array for easier templating
|
||||
storageMap["recordValues"] = dnsResponse.records.map(
|
||||
(record: DnsRecordResponse) => {
|
||||
return record.value;
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error(err);
|
||||
}
|
||||
|
||||
@@ -780,13 +780,14 @@ export default class MicrosoftTeamsUtil extends WorkspaceBase {
|
||||
|
||||
const workspaceChannels: Array<WorkspaceChannel> = [];
|
||||
|
||||
for (let channelName of data.channelNames) {
|
||||
// Normalize channel name - Teams has different naming requirements
|
||||
if (channelName && channelName.startsWith("#")) {
|
||||
channelName = channelName.substring(1);
|
||||
}
|
||||
// Teams channels cannot have spaces in the name for some operations
|
||||
const normalizedChannelName: string = channelName.replace(/\s+/g, "-");
|
||||
for (const channelName of data.channelNames) {
|
||||
/*
|
||||
* Normalize channel name: replace spaces with hyphens, then strip
|
||||
* characters not valid in Teams channel names (e.g. #, %, &, *, etc.).
|
||||
*/
|
||||
const normalizedChannelName: string = channelName
|
||||
.replace(/\s+/g, "-")
|
||||
.replace(/[^a-zA-Z0-9\-_]/g, "");
|
||||
|
||||
// Check if channel exists
|
||||
const existingChannel: WorkspaceChannel | null =
|
||||
@@ -839,6 +840,9 @@ export default class MicrosoftTeamsUtil extends WorkspaceBase {
|
||||
}): Promise<WorkspaceChannel> {
|
||||
const teamId: string = data.teamId;
|
||||
|
||||
// Sanitize channel name: strip characters not valid in Teams channel names.
|
||||
data.channelName = data.channelName.replace(/[^a-zA-Z0-9\-_\s]/g, "");
|
||||
|
||||
// Get valid access token
|
||||
const accessToken: string = await this.getValidAccessToken({
|
||||
authToken: data.authToken,
|
||||
|
||||
@@ -442,12 +442,14 @@ export default class SlackUtil extends WorkspaceBase {
|
||||
const workspaceChannels: Array<WorkspaceChannel> = [];
|
||||
|
||||
for (let channelName of data.channelNames) {
|
||||
// Normalize channel name
|
||||
if (channelName && channelName.startsWith("#")) {
|
||||
channelName = channelName.substring(1);
|
||||
}
|
||||
channelName = channelName.toLowerCase();
|
||||
channelName = channelName.replace(/\s+/g, "-");
|
||||
/*
|
||||
* Normalize channel name: replace spaces with hyphens, then strip
|
||||
* any characters not valid in Slack channel names.
|
||||
*/
|
||||
channelName = channelName
|
||||
.toLowerCase()
|
||||
.replace(/\s+/g, "-")
|
||||
.replace(/[^a-z0-9\-_]/g, "");
|
||||
|
||||
// Check if channel exists using optimized method
|
||||
const existingChannel: WorkspaceChannel | null =
|
||||
@@ -1345,12 +1347,13 @@ export default class SlackUtil extends WorkspaceBase {
|
||||
channelName: string;
|
||||
projectId: ObjectID;
|
||||
}): Promise<WorkspaceChannel> {
|
||||
if (data.channelName && data.channelName.startsWith("#")) {
|
||||
data.channelName = data.channelName.substring(1);
|
||||
}
|
||||
|
||||
// lower case channel name
|
||||
data.channelName = data.channelName.toLowerCase();
|
||||
/*
|
||||
* Sanitize channel name: Slack only allows lowercase letters, numbers,
|
||||
* hyphens, and underscores. Remove all other characters (including #).
|
||||
*/
|
||||
data.channelName = data.channelName
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9\-_]/g, "");
|
||||
|
||||
logger.debug("Creating channel with data:");
|
||||
logger.debug(data);
|
||||
|
||||
@@ -14,6 +14,7 @@ import Response from "../../../Server/Utils/Response";
|
||||
import Dictionary from "../../../Types/Dictionary";
|
||||
import Email from "../../../Types/Email";
|
||||
import BadDataException from "../../../Types/Exception/BadDataException";
|
||||
import NotAuthenticatedException from "../../../Types/Exception/NotAuthenticatedException";
|
||||
import SsoAuthorizationException from "../../../Types/Exception/SsoAuthorizationException";
|
||||
import HashedString from "../../../Types/HashedString";
|
||||
import JSONFunctions from "../../../Types/JSONFunctions";
|
||||
@@ -330,7 +331,7 @@ describe("UserMiddleware", () => {
|
||||
expect(JSONWebToken.decode).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("should call function 'next' and return, when accessToken can not be decoded", async () => {
|
||||
test("should call Response.sendErrorResponse with NotAuthenticatedException, when accessToken can not be decoded", async () => {
|
||||
const error: Error = new Error("Invalid access token");
|
||||
|
||||
const spyJWTDecode: jest.SpyInstance = getJestSpyOn(
|
||||
@@ -342,7 +343,14 @@ describe("UserMiddleware", () => {
|
||||
|
||||
await UserMiddleware.getUserMiddleware(req, res, next);
|
||||
|
||||
expect(next).toHaveBeenCalled();
|
||||
expect(Response.sendErrorResponse).toHaveBeenCalledWith(
|
||||
req,
|
||||
res,
|
||||
new NotAuthenticatedException(
|
||||
"AccessToken is invalid or expired. Please refresh your token.",
|
||||
),
|
||||
);
|
||||
expect(next).not.toHaveBeenCalled();
|
||||
expect(spyJWTDecode).toHaveBeenCalledWith(mockedAccessToken);
|
||||
expect(UserService.updateOneBy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -60,6 +60,13 @@ export enum CheckOn {
|
||||
SnmpOidExists = "SNMP OID Exists",
|
||||
SnmpResponseTime = "SNMP Response Time (in ms)",
|
||||
SnmpIsOnline = "SNMP Device Is Online",
|
||||
|
||||
// DNS monitors.
|
||||
DnsResponseTime = "DNS Response Time (in ms)",
|
||||
DnsIsOnline = "DNS Is Online",
|
||||
DnsRecordValue = "DNS Record Value",
|
||||
DnssecIsValid = "DNSSEC Is Valid",
|
||||
DnsRecordExists = "DNS Record Exists",
|
||||
}
|
||||
|
||||
export interface ServerMonitorOptions {
|
||||
@@ -141,7 +148,11 @@ export class CriteriaFilterUtil {
|
||||
}): boolean {
|
||||
const { checkOn } = data;
|
||||
|
||||
if (checkOn === CheckOn.IsOnline || checkOn === CheckOn.SnmpIsOnline) {
|
||||
if (
|
||||
checkOn === CheckOn.IsOnline ||
|
||||
checkOn === CheckOn.SnmpIsOnline ||
|
||||
checkOn === CheckOn.DnsIsOnline
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -149,7 +160,11 @@ export class CriteriaFilterUtil {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (checkOn === CheckOn.SnmpOidExists) {
|
||||
if (
|
||||
checkOn === CheckOn.SnmpOidExists ||
|
||||
checkOn === CheckOn.DnssecIsValid ||
|
||||
checkOn === CheckOn.DnsRecordExists
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -204,7 +219,9 @@ export class CriteriaFilterUtil {
|
||||
checkOn === CheckOn.MemoryUsagePercent ||
|
||||
checkOn === CheckOn.IsOnline ||
|
||||
checkOn === CheckOn.SnmpResponseTime ||
|
||||
checkOn === CheckOn.SnmpIsOnline
|
||||
checkOn === CheckOn.SnmpIsOnline ||
|
||||
checkOn === CheckOn.DnsResponseTime ||
|
||||
checkOn === CheckOn.DnsIsOnline
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
16
Common/Types/Monitor/DnsMonitor/DnsMonitorResponse.ts
Normal file
16
Common/Types/Monitor/DnsMonitor/DnsMonitorResponse.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import DnsRecordType from "./DnsRecordType";
|
||||
|
||||
export interface DnsRecordResponse {
|
||||
type: DnsRecordType;
|
||||
value: string;
|
||||
ttl?: number | undefined;
|
||||
}
|
||||
|
||||
export default interface DnsMonitorResponse {
|
||||
isOnline: boolean;
|
||||
responseTimeInMs: number;
|
||||
failureCause: string;
|
||||
records: Array<DnsRecordResponse>;
|
||||
isDnssecValid?: boolean | undefined;
|
||||
isTimeout?: boolean | undefined;
|
||||
}
|
||||
14
Common/Types/Monitor/DnsMonitor/DnsRecordType.ts
Normal file
14
Common/Types/Monitor/DnsMonitor/DnsRecordType.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
enum DnsRecordType {
|
||||
A = "A",
|
||||
AAAA = "AAAA",
|
||||
CNAME = "CNAME",
|
||||
MX = "MX",
|
||||
NS = "NS",
|
||||
TXT = "TXT",
|
||||
SOA = "SOA",
|
||||
PTR = "PTR",
|
||||
SRV = "SRV",
|
||||
CAA = "CAA",
|
||||
}
|
||||
|
||||
export default DnsRecordType;
|
||||
@@ -394,6 +394,33 @@ export default class MonitorCriteriaInstance extends DatabaseProperty {
|
||||
return monitorCriteriaInstance;
|
||||
}
|
||||
|
||||
if (arg.monitorType === MonitorType.DNS) {
|
||||
const monitorCriteriaInstance: MonitorCriteriaInstance =
|
||||
new MonitorCriteriaInstance();
|
||||
|
||||
monitorCriteriaInstance.data = {
|
||||
id: ObjectID.generate().toString(),
|
||||
monitorStatusId: arg.monitorStatusId,
|
||||
filterCondition: FilterCondition.All,
|
||||
filters: [
|
||||
{
|
||||
checkOn: CheckOn.DnsIsOnline,
|
||||
filterType: FilterType.True,
|
||||
value: undefined,
|
||||
},
|
||||
],
|
||||
incidents: [],
|
||||
alerts: [],
|
||||
createAlerts: false,
|
||||
changeMonitorStatus: true,
|
||||
createIncidents: false,
|
||||
name: `Check if ${arg.monitorName} is online`,
|
||||
description: `This criteria checks if the ${arg.monitorName} DNS resolution is online`,
|
||||
};
|
||||
|
||||
return monitorCriteriaInstance;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -495,6 +522,46 @@ export default class MonitorCriteriaInstance extends DatabaseProperty {
|
||||
};
|
||||
}
|
||||
|
||||
if (arg.monitorType === MonitorType.DNS) {
|
||||
monitorCriteriaInstance.data = {
|
||||
id: ObjectID.generate().toString(),
|
||||
monitorStatusId: arg.monitorStatusId,
|
||||
filterCondition: FilterCondition.Any,
|
||||
filters: [
|
||||
{
|
||||
checkOn: CheckOn.DnsIsOnline,
|
||||
filterType: FilterType.False,
|
||||
value: undefined,
|
||||
},
|
||||
],
|
||||
incidents: [
|
||||
{
|
||||
title: `${arg.monitorName} is offline`,
|
||||
description: `${arg.monitorName} DNS resolution is currently failing.`,
|
||||
incidentSeverityId: arg.incidentSeverityId,
|
||||
autoResolveIncident: true,
|
||||
id: ObjectID.generate().toString(),
|
||||
onCallPolicyIds: [],
|
||||
},
|
||||
],
|
||||
changeMonitorStatus: true,
|
||||
createIncidents: true,
|
||||
createAlerts: false,
|
||||
alerts: [
|
||||
{
|
||||
title: `${arg.monitorName} is offline`,
|
||||
description: `${arg.monitorName} DNS resolution is currently failing.`,
|
||||
alertSeverityId: arg.alertSeverityId,
|
||||
autoResolveAlert: true,
|
||||
id: ObjectID.generate().toString(),
|
||||
onCallPolicyIds: [],
|
||||
},
|
||||
],
|
||||
name: `Check if ${arg.monitorName} is offline`,
|
||||
description: `This criteria checks if the ${arg.monitorName} DNS resolution is failing`,
|
||||
};
|
||||
}
|
||||
|
||||
if (
|
||||
arg.monitorType === MonitorType.API ||
|
||||
arg.monitorType === MonitorType.Website
|
||||
|
||||
@@ -29,6 +29,9 @@ import MonitorStepExceptionMonitor, {
|
||||
import MonitorStepSnmpMonitor, {
|
||||
MonitorStepSnmpMonitorUtil,
|
||||
} from "./MonitorStepSnmpMonitor";
|
||||
import MonitorStepDnsMonitor, {
|
||||
MonitorStepDnsMonitorUtil,
|
||||
} from "./MonitorStepDnsMonitor";
|
||||
import Zod, { ZodSchema } from "../../Utils/Schema/Zod";
|
||||
|
||||
export interface MonitorStepType {
|
||||
@@ -72,6 +75,9 @@ export interface MonitorStepType {
|
||||
|
||||
// SNMP monitor
|
||||
snmpMonitor?: MonitorStepSnmpMonitor | undefined;
|
||||
|
||||
// DNS monitor
|
||||
dnsMonitor?: MonitorStepDnsMonitor | undefined;
|
||||
}
|
||||
|
||||
export default class MonitorStep extends DatabaseProperty {
|
||||
@@ -98,6 +104,7 @@ export default class MonitorStep extends DatabaseProperty {
|
||||
metricMonitor: undefined,
|
||||
exceptionMonitor: undefined,
|
||||
snmpMonitor: undefined,
|
||||
dnsMonitor: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -129,6 +136,7 @@ export default class MonitorStep extends DatabaseProperty {
|
||||
metricMonitor: undefined,
|
||||
exceptionMonitor: undefined,
|
||||
snmpMonitor: undefined,
|
||||
dnsMonitor: undefined,
|
||||
};
|
||||
|
||||
return monitorStep;
|
||||
@@ -224,6 +232,11 @@ export default class MonitorStep extends DatabaseProperty {
|
||||
return this;
|
||||
}
|
||||
|
||||
public setDnsMonitor(dnsMonitor: MonitorStepDnsMonitor): MonitorStep {
|
||||
this.data!.dnsMonitor = dnsMonitor;
|
||||
return this;
|
||||
}
|
||||
|
||||
public setCustomCode(customCode: string): MonitorStep {
|
||||
this.data!.customCode = customCode;
|
||||
return this;
|
||||
@@ -332,6 +345,16 @@ export default class MonitorStep extends DatabaseProperty {
|
||||
}
|
||||
}
|
||||
|
||||
if (monitorType === MonitorType.DNS) {
|
||||
if (!value.data.dnsMonitor) {
|
||||
return "DNS configuration is required";
|
||||
}
|
||||
|
||||
if (!value.data.dnsMonitor.queryName) {
|
||||
return "DNS query name (domain) is required";
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -377,6 +400,9 @@ export default class MonitorStep extends DatabaseProperty {
|
||||
snmpMonitor: this.data.snmpMonitor
|
||||
? MonitorStepSnmpMonitorUtil.toJSON(this.data.snmpMonitor)
|
||||
: undefined,
|
||||
dnsMonitor: this.data.dnsMonitor
|
||||
? MonitorStepDnsMonitorUtil.toJSON(this.data.dnsMonitor)
|
||||
: undefined,
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -482,6 +508,9 @@ export default class MonitorStep extends DatabaseProperty {
|
||||
snmpMonitor: json["snmpMonitor"]
|
||||
? (json["snmpMonitor"] as JSONObject)
|
||||
: undefined,
|
||||
dnsMonitor: json["dnsMonitor"]
|
||||
? (json["dnsMonitor"] as JSONObject)
|
||||
: undefined,
|
||||
}) as any;
|
||||
|
||||
return monitorStep;
|
||||
@@ -507,6 +536,7 @@ export default class MonitorStep extends DatabaseProperty {
|
||||
traceMonitor: Zod.any().optional(),
|
||||
metricMonitor: Zod.any().optional(),
|
||||
snmpMonitor: Zod.any().optional(),
|
||||
dnsMonitor: Zod.any().optional(),
|
||||
}).openapi({
|
||||
type: "object",
|
||||
example: {
|
||||
|
||||
46
Common/Types/Monitor/MonitorStepDnsMonitor.ts
Normal file
46
Common/Types/Monitor/MonitorStepDnsMonitor.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { JSONObject } from "../JSON";
|
||||
import DnsRecordType from "./DnsMonitor/DnsRecordType";
|
||||
|
||||
export default interface MonitorStepDnsMonitor {
|
||||
queryName: string;
|
||||
recordType: DnsRecordType;
|
||||
hostname?: string | undefined; // DNS server (e.g. "8.8.8.8"), empty = system default
|
||||
port: number;
|
||||
timeout: number;
|
||||
retries: number;
|
||||
}
|
||||
|
||||
export class MonitorStepDnsMonitorUtil {
|
||||
public static getDefault(): MonitorStepDnsMonitor {
|
||||
return {
|
||||
queryName: "",
|
||||
recordType: DnsRecordType.A,
|
||||
hostname: "",
|
||||
port: 53,
|
||||
timeout: 5000,
|
||||
retries: 3,
|
||||
};
|
||||
}
|
||||
|
||||
public static fromJSON(json: JSONObject): MonitorStepDnsMonitor {
|
||||
return {
|
||||
queryName: (json["queryName"] as string) || "",
|
||||
recordType: (json["recordType"] as DnsRecordType) || DnsRecordType.A,
|
||||
hostname: (json["hostname"] as string) || undefined,
|
||||
port: (json["port"] as number) || 53,
|
||||
timeout: (json["timeout"] as number) || 5000,
|
||||
retries: (json["retries"] as number) || 3,
|
||||
};
|
||||
}
|
||||
|
||||
public static toJSON(monitor: MonitorStepDnsMonitor): JSONObject {
|
||||
return {
|
||||
queryName: monitor.queryName,
|
||||
recordType: monitor.recordType,
|
||||
hostname: monitor.hostname,
|
||||
port: monitor.port,
|
||||
timeout: monitor.timeout,
|
||||
retries: monitor.retries,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,9 @@ enum MonitorType {
|
||||
|
||||
// Network device monitoring
|
||||
SNMP = "SNMP",
|
||||
|
||||
// DNS monitoring
|
||||
DNS = "DNS",
|
||||
}
|
||||
|
||||
export default MonitorType;
|
||||
@@ -179,6 +182,13 @@ export class MonitorTypeHelper {
|
||||
"This monitor type lets you monitor network devices like switches, routers, and firewalls via SNMP.",
|
||||
icon: IconProp.Signal,
|
||||
},
|
||||
{
|
||||
monitorType: MonitorType.DNS,
|
||||
title: "DNS",
|
||||
description:
|
||||
"This monitor type lets you monitor DNS resolution for your domains, verify record values, and check DNSSEC validity.",
|
||||
icon: IconProp.GlobeAlt,
|
||||
},
|
||||
];
|
||||
|
||||
return monitorTypeProps;
|
||||
@@ -224,7 +234,8 @@ export class MonitorTypeHelper {
|
||||
monitorType === MonitorType.SSLCertificate ||
|
||||
monitorType === MonitorType.SyntheticMonitor ||
|
||||
monitorType === MonitorType.CustomJavaScriptCode ||
|
||||
monitorType === MonitorType.SNMP;
|
||||
monitorType === MonitorType.SNMP ||
|
||||
monitorType === MonitorType.DNS;
|
||||
return isProbeableMonitor;
|
||||
}
|
||||
|
||||
@@ -246,6 +257,7 @@ export class MonitorTypeHelper {
|
||||
MonitorType.Traces,
|
||||
MonitorType.Exceptions,
|
||||
MonitorType.SNMP,
|
||||
MonitorType.DNS,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -278,7 +290,8 @@ export class MonitorTypeHelper {
|
||||
monitorType === MonitorType.SSLCertificate ||
|
||||
monitorType === MonitorType.SyntheticMonitor ||
|
||||
monitorType === MonitorType.CustomJavaScriptCode ||
|
||||
monitorType === MonitorType.SNMP
|
||||
monitorType === MonitorType.SNMP ||
|
||||
monitorType === MonitorType.DNS
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import CustomCodeMonitorResponse from "../Monitor/CustomCodeMonitor/CustomCodeMo
|
||||
import SslMonitorResponse from "../Monitor/SSLMonitor/SslMonitorResponse";
|
||||
import SyntheticMonitorResponse from "../Monitor/SyntheticMonitors/SyntheticMonitorResponse";
|
||||
import SnmpMonitorResponse from "../Monitor/SnmpMonitor/SnmpMonitorResponse";
|
||||
import DnsMonitorResponse from "../Monitor/DnsMonitor/DnsMonitorResponse";
|
||||
import MonitorEvaluationSummary from "../Monitor/MonitorEvaluationSummary";
|
||||
import ObjectID from "../ObjectID";
|
||||
import Port from "../Port";
|
||||
@@ -30,6 +31,7 @@ export default interface ProbeMonitorResponse {
|
||||
syntheticMonitorResponse?: Array<SyntheticMonitorResponse> | undefined;
|
||||
customCodeMonitorResponse?: CustomCodeMonitorResponse | undefined;
|
||||
snmpResponse?: SnmpMonitorResponse | undefined;
|
||||
dnsResponse?: DnsMonitorResponse | undefined;
|
||||
monitoredAt: Date;
|
||||
isTimeout?: boolean | undefined;
|
||||
ingestedAt?: Date | undefined;
|
||||
|
||||
@@ -8,8 +8,63 @@ import React, {
|
||||
import ReactMarkdown from "react-markdown";
|
||||
// https://github.com/remarkjs/remark-gfm
|
||||
import remarkGfm from "remark-gfm";
|
||||
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
|
||||
import SyntaxHighlighter from "react-syntax-highlighter/dist/esm/prism-light";
|
||||
import { a11yDark } from "react-syntax-highlighter/dist/esm/styles/prism";
|
||||
import javascript from "react-syntax-highlighter/dist/esm/languages/prism/javascript";
|
||||
import typescript from "react-syntax-highlighter/dist/esm/languages/prism/typescript";
|
||||
import jsx from "react-syntax-highlighter/dist/esm/languages/prism/jsx";
|
||||
import tsx from "react-syntax-highlighter/dist/esm/languages/prism/tsx";
|
||||
import python from "react-syntax-highlighter/dist/esm/languages/prism/python";
|
||||
import bash from "react-syntax-highlighter/dist/esm/languages/prism/bash";
|
||||
import json from "react-syntax-highlighter/dist/esm/languages/prism/json";
|
||||
import yaml from "react-syntax-highlighter/dist/esm/languages/prism/yaml";
|
||||
import sql from "react-syntax-highlighter/dist/esm/languages/prism/sql";
|
||||
import go from "react-syntax-highlighter/dist/esm/languages/prism/go";
|
||||
import java from "react-syntax-highlighter/dist/esm/languages/prism/java";
|
||||
import css from "react-syntax-highlighter/dist/esm/languages/prism/css";
|
||||
import markup from "react-syntax-highlighter/dist/esm/languages/prism/markup";
|
||||
import markdown from "react-syntax-highlighter/dist/esm/languages/prism/markdown";
|
||||
import docker from "react-syntax-highlighter/dist/esm/languages/prism/docker";
|
||||
import rust from "react-syntax-highlighter/dist/esm/languages/prism/rust";
|
||||
import c from "react-syntax-highlighter/dist/esm/languages/prism/c";
|
||||
import cpp from "react-syntax-highlighter/dist/esm/languages/prism/cpp";
|
||||
import csharp from "react-syntax-highlighter/dist/esm/languages/prism/csharp";
|
||||
import ruby from "react-syntax-highlighter/dist/esm/languages/prism/ruby";
|
||||
import php from "react-syntax-highlighter/dist/esm/languages/prism/php";
|
||||
import graphql from "react-syntax-highlighter/dist/esm/languages/prism/graphql";
|
||||
import http from "react-syntax-highlighter/dist/esm/languages/prism/http";
|
||||
|
||||
SyntaxHighlighter.registerLanguage("javascript", javascript);
|
||||
SyntaxHighlighter.registerLanguage("js", javascript);
|
||||
SyntaxHighlighter.registerLanguage("typescript", typescript);
|
||||
SyntaxHighlighter.registerLanguage("ts", typescript);
|
||||
SyntaxHighlighter.registerLanguage("jsx", jsx);
|
||||
SyntaxHighlighter.registerLanguage("tsx", tsx);
|
||||
SyntaxHighlighter.registerLanguage("python", python);
|
||||
SyntaxHighlighter.registerLanguage("bash", bash);
|
||||
SyntaxHighlighter.registerLanguage("shell", bash);
|
||||
SyntaxHighlighter.registerLanguage("json", json);
|
||||
SyntaxHighlighter.registerLanguage("yaml", yaml);
|
||||
SyntaxHighlighter.registerLanguage("yml", yaml);
|
||||
SyntaxHighlighter.registerLanguage("sql", sql);
|
||||
SyntaxHighlighter.registerLanguage("go", go);
|
||||
SyntaxHighlighter.registerLanguage("java", java);
|
||||
SyntaxHighlighter.registerLanguage("css", css);
|
||||
SyntaxHighlighter.registerLanguage("markup", markup);
|
||||
SyntaxHighlighter.registerLanguage("html", markup);
|
||||
SyntaxHighlighter.registerLanguage("xml", markup);
|
||||
SyntaxHighlighter.registerLanguage("markdown", markdown);
|
||||
SyntaxHighlighter.registerLanguage("md", markdown);
|
||||
SyntaxHighlighter.registerLanguage("docker", docker);
|
||||
SyntaxHighlighter.registerLanguage("dockerfile", docker);
|
||||
SyntaxHighlighter.registerLanguage("rust", rust);
|
||||
SyntaxHighlighter.registerLanguage("c", c);
|
||||
SyntaxHighlighter.registerLanguage("cpp", cpp);
|
||||
SyntaxHighlighter.registerLanguage("csharp", csharp);
|
||||
SyntaxHighlighter.registerLanguage("ruby", ruby);
|
||||
SyntaxHighlighter.registerLanguage("php", php);
|
||||
SyntaxHighlighter.registerLanguage("graphql", graphql);
|
||||
SyntaxHighlighter.registerLanguage("http", http);
|
||||
import mermaid from "mermaid";
|
||||
|
||||
// Initialize mermaid
|
||||
|
||||
@@ -39,6 +39,54 @@ function createRefractorCompatibilityPlugin() {
|
||||
};
|
||||
}
|
||||
|
||||
// Plugin to force mermaid to use its pre-bundled CJS build (no dynamic imports)
|
||||
function createMermaidPlugin() {
|
||||
const candidateRoots = [
|
||||
path.resolve(__dirname, '../node_modules/mermaid'),
|
||||
path.resolve(__dirname, '../../node_modules/mermaid'),
|
||||
];
|
||||
const mermaidRoot = candidateRoots.find((p) => fs.existsSync(p));
|
||||
|
||||
return {
|
||||
name: 'mermaid-prebundled',
|
||||
setup(build) {
|
||||
if (!mermaidRoot) return;
|
||||
const bundlePath = path.join(mermaidRoot, 'dist', 'mermaid.min.js');
|
||||
|
||||
// Intercept bare "mermaid" imports and serve the pre-bundled CJS file
|
||||
// with an ESM export appended. The CJS file declares a local var
|
||||
// __esbuild_esm_mermaid_nm and assigns .mermaid on it, so we inline
|
||||
// the file contents and export from the same scope.
|
||||
build.onResolve({ filter: /^mermaid$/ }, () => {
|
||||
return { path: 'mermaid-wrapper', namespace: 'mermaid-ns' };
|
||||
});
|
||||
|
||||
build.onLoad({ filter: /^mermaid-wrapper$/, namespace: 'mermaid-ns' }, () => {
|
||||
let cjsSource = fs.readFileSync(bundlePath, 'utf8');
|
||||
// The CJS bundle ends with a line that tries globalThis.__esbuild_esm_mermaid_nm
|
||||
// which fails because the var is local-scoped when bundled. Strip it and
|
||||
// expose the local var on globalThis ourselves before that line.
|
||||
cjsSource = cjsSource.replace(
|
||||
/globalThis\["mermaid"\]\s*=\s*globalThis\.__esbuild_esm_mermaid_nm\["mermaid"\]\.default;?\s*$/,
|
||||
''
|
||||
);
|
||||
const contents = cjsSource + `
|
||||
;globalThis.__esbuild_esm_mermaid_nm = typeof __esbuild_esm_mermaid_nm !== "undefined" ? __esbuild_esm_mermaid_nm : {};
|
||||
var _mermaid_export = __esbuild_esm_mermaid_nm.mermaid;
|
||||
if (_mermaid_export && _mermaid_export.default) { _mermaid_export = _mermaid_export.default; }
|
||||
export default _mermaid_export;
|
||||
export { _mermaid_export as mermaid };
|
||||
`;
|
||||
return {
|
||||
contents,
|
||||
loader: 'js',
|
||||
resolveDir: path.dirname(bundlePath),
|
||||
};
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// CSS Plugin to handle CSS/SCSS files
|
||||
function createCSSPlugin() {
|
||||
return {
|
||||
@@ -161,12 +209,13 @@ function createConfig(options) {
|
||||
entryPoints: [entryPoint],
|
||||
bundle: true,
|
||||
outdir,
|
||||
format: 'esm', // Changed from 'iife' to 'esm' to support splitting
|
||||
format: 'esm',
|
||||
platform: 'browser',
|
||||
target: 'es2017',
|
||||
sourcemap: isDev ? 'inline' : false,
|
||||
minify: false,
|
||||
splitting: true, // Now supported with ESM format
|
||||
treeShaking: true,
|
||||
splitting: true,
|
||||
publicPath,
|
||||
define: {
|
||||
'process.env.NODE_ENV': JSON.stringify(isDev ? 'development' : 'production'),
|
||||
@@ -177,7 +226,7 @@ function createConfig(options) {
|
||||
'react': path.resolve('./node_modules/react'),
|
||||
...additionalAlias,
|
||||
},
|
||||
plugins: [createRefractorCompatibilityPlugin(), createCSSPlugin(), createFileLoaderPlugin()],
|
||||
plugins: [createMermaidPlugin(), createRefractorCompatibilityPlugin(), createCSSPlugin(), createFileLoaderPlugin()],
|
||||
loader: {
|
||||
'.tsx': 'tsx',
|
||||
'.ts': 'ts',
|
||||
|
||||
@@ -85,7 +85,8 @@ class MonitorMetricTypeUtil {
|
||||
monitorType === MonitorType.Ping ||
|
||||
monitorType === MonitorType.IP ||
|
||||
monitorType === MonitorType.Port ||
|
||||
monitorType === MonitorType.SNMP
|
||||
monitorType === MonitorType.SNMP ||
|
||||
monitorType === MonitorType.DNS
|
||||
) {
|
||||
return [MonitorMetricType.IsOnline, MonitorMetricType.ResponseTime];
|
||||
}
|
||||
|
||||
29
Common/package-lock.json
generated
29
Common/package-lock.json
generated
@@ -423,7 +423,6 @@
|
||||
"integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@ampproject/remapping": "^2.2.0",
|
||||
"@babel/code-frame": "^7.26.0",
|
||||
@@ -926,7 +925,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@bull-board/ui/-/ui-5.23.0.tgz",
|
||||
"integrity": "sha512-iI/Ssl8T5ZEn9s899Qz67m92M6RU8thf/aqD7cUHB2yHmkCjqbw7s7NaODTsyArAsnyu7DGJMWm7EhbfFXDNgQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@bull-board/api": "5.23.0"
|
||||
}
|
||||
@@ -2366,7 +2364,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz",
|
||||
"integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
@@ -5516,7 +5513,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz",
|
||||
"integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
"csstype": "^3.0.2"
|
||||
@@ -5692,7 +5688,8 @@
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-1.0.6.tgz",
|
||||
"integrity": "sha512-230RC8sFeHoT6sSUlRO6a8cAnclO06eeiq1QDfiv2FGCLWFvvERWgwIQD4FWqD9A69BN7Lzee4OXwoMVnnsWDw==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@types/unist": {
|
||||
"version": "2.0.11",
|
||||
@@ -5862,7 +5859,6 @@
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@@ -6755,7 +6751,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"caniuse-lite": "^1.0.30001669",
|
||||
"electron-to-chromium": "^1.5.41",
|
||||
@@ -7593,7 +7588,6 @@
|
||||
"resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz",
|
||||
"integrity": "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
@@ -8015,7 +8009,6 @@
|
||||
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
|
||||
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
|
||||
"license": "ISC",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
@@ -10795,7 +10788,6 @@
|
||||
"integrity": "sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@jest/core": "^28.1.3",
|
||||
"@jest/types": "^28.1.3",
|
||||
@@ -14511,7 +14503,6 @@
|
||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz",
|
||||
"integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"pg-connection-string": "^2.9.1",
|
||||
"pg-pool": "^3.10.1",
|
||||
@@ -14894,7 +14885,6 @@
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.4.0",
|
||||
"object-assign": "^4.1.1",
|
||||
@@ -15085,9 +15075,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.14.1",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz",
|
||||
"integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==",
|
||||
"version": "6.14.2",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz",
|
||||
"integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"side-channel": "^1.1.0"
|
||||
@@ -15198,7 +15188,6 @@
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
||||
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
},
|
||||
@@ -15283,7 +15272,6 @@
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
||||
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"scheduler": "^0.23.2"
|
||||
@@ -15804,8 +15792,7 @@
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz",
|
||||
"integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/refractor": {
|
||||
"version": "5.0.0",
|
||||
@@ -19102,7 +19089,6 @@
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
|
||||
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
@@ -19111,8 +19097,7 @@
|
||||
"version": "0.14.10",
|
||||
"resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.14.10.tgz",
|
||||
"integrity": "sha512-YGAhaO7J5ywOXW6InXNlLmfU194F8lVgu7bRntUF3TiG8Y3nBK0x1UJJuHUP/e8IyihkjCYqhCScpSwnlaSRkQ==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/zustand": {
|
||||
"version": "4.5.5",
|
||||
|
||||
12
Dashboard/package-lock.json
generated
12
Dashboard/package-lock.json
generated
@@ -16051,9 +16051,9 @@
|
||||
}
|
||||
},
|
||||
"../Common/node_modules/qs": {
|
||||
"version": "6.14.1",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz",
|
||||
"integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==",
|
||||
"version": "6.14.2",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz",
|
||||
"integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"side-channel": "^1.1.0"
|
||||
@@ -21660,9 +21660,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.14.1",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz",
|
||||
"integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==",
|
||||
"version": "6.14.2",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz",
|
||||
"integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"side-channel": "^1.1.0"
|
||||
|
||||
@@ -27,211 +27,195 @@ import useAsyncEffect from "use-async-effect";
|
||||
import PageComponentProps from "./Pages/PageComponentProps";
|
||||
import PageLoader from "Common/UI/Components/Loader/PageLoader";
|
||||
import { RoutesProps } from "./Types/RoutesProps";
|
||||
// Lazy load route components
|
||||
|
||||
// Static page imports
|
||||
import Welcome from "./Pages/Onboarding/Welcome";
|
||||
import Home from "./Pages/Home/Home";
|
||||
import Sso from "./Pages/Onboarding/SSO";
|
||||
import NotOperationalMonitors from "./Pages/Home/NotOperationalMonitors";
|
||||
import HomeActiveAlerts from "./Pages/Home/ActiveAlerts";
|
||||
import OngoingScheduledEvents from "./Pages/Home/OngoingScheduledMaintenance";
|
||||
import HomeActiveEpisodes from "./Pages/Home/ActiveEpisodes";
|
||||
import HomeActiveIncidentEpisodes from "./Pages/Home/ActiveIncidentEpisodes";
|
||||
import SettingsDangerZone from "./Pages/Settings/DangerZone";
|
||||
import Logout from "./Pages/Logout/Logout";
|
||||
import UserProfilePicture from "./Pages/Global/UserProfile/Picture";
|
||||
import UserProfileOverview from "./Pages/Global/UserProfile/Index";
|
||||
import UserProfilePassword from "./Pages/Global/UserProfile/Password";
|
||||
import UseTwoFactorAuth from "./Pages/Global/UserProfile/TwoFactorAuth";
|
||||
import UserProfileDelete from "./Pages/Global/UserProfile/DeleteAccount";
|
||||
import ProjectInvitations from "./Pages/Global/ProjectInvitations";
|
||||
import ActiveIncidents from "./Pages/Global/ActiveIncidents";
|
||||
import ActiveAlerts from "./Pages/Global/ActiveAlerts";
|
||||
import ActiveAlertEpisodes from "./Pages/Global/ActiveAlertEpisodes";
|
||||
import ActiveIncidentEpisodes from "./Pages/Global/ActiveIncidentEpisodes";
|
||||
import MyOnCallPolicies from "./Pages/Global/MyOnCallPolicies";
|
||||
import PageNotFound from "./Pages/PageNotFound/PageNotFound";
|
||||
|
||||
// Lazy-loaded route bundles (all routes in one bundle to minimize chunk count)
|
||||
type AllRoutesModule = typeof import("./Routes/AllRoutes");
|
||||
const InitRoutes: React.LazyExoticComponent<
|
||||
React.FunctionComponent<RoutesProps>
|
||||
> = lazy(() => {
|
||||
return import("./Routes/InitRoutes");
|
||||
});
|
||||
const Welcome: React.LazyExoticComponent<React.FunctionComponent<any>> = lazy(
|
||||
() => {
|
||||
return import("./Pages/Onboarding/Welcome");
|
||||
},
|
||||
);
|
||||
const Home: React.LazyExoticComponent<React.FunctionComponent<any>> = lazy(
|
||||
() => {
|
||||
return import("./Pages/Home/Home");
|
||||
},
|
||||
);
|
||||
const Sso: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("./Pages/Onboarding/SSO");
|
||||
});
|
||||
const NotOperationalMonitors: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("./Pages/Home/NotOperationalMonitors");
|
||||
});
|
||||
const HomeActiveAlerts: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("./Pages/Home/ActiveAlerts");
|
||||
});
|
||||
const OngoingScheduledEvents: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("./Pages/Home/OngoingScheduledMaintenance");
|
||||
});
|
||||
const HomeActiveEpisodes: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("./Pages/Home/ActiveEpisodes");
|
||||
});
|
||||
const HomeActiveIncidentEpisodes: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("./Pages/Home/ActiveIncidentEpisodes");
|
||||
});
|
||||
const LogsRoutes: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("./Routes/LogsRoutes");
|
||||
});
|
||||
|
||||
const LogsRoutes: React.LazyExoticComponent<AllRoutesModule["LogsRoutes"]> =
|
||||
lazy(() => {
|
||||
return import("./Routes/AllRoutes").then((m: AllRoutesModule) => {
|
||||
return { default: m.LogsRoutes };
|
||||
});
|
||||
});
|
||||
const MetricsRoutes: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
AllRoutesModule["MetricsRoutes"]
|
||||
> = lazy(() => {
|
||||
return import("./Routes/MetricsRoutes");
|
||||
return import("./Routes/AllRoutes").then((m: AllRoutesModule) => {
|
||||
return {
|
||||
default: m.MetricsRoutes,
|
||||
};
|
||||
});
|
||||
});
|
||||
const TracesRoutes: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
const TracesRoutes: React.LazyExoticComponent<AllRoutesModule["TracesRoutes"]> =
|
||||
lazy(() => {
|
||||
return import("./Routes/AllRoutes").then((m: AllRoutesModule) => {
|
||||
return {
|
||||
default: m.TracesRoutes,
|
||||
};
|
||||
});
|
||||
});
|
||||
const ExceptionsRoutes: React.LazyExoticComponent<
|
||||
AllRoutesModule["ExceptionsRoutes"]
|
||||
> = lazy(() => {
|
||||
return import("./Routes/TracesRoutes");
|
||||
});
|
||||
const MonitorsRoutes: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("./Routes/MonitorsRoutes");
|
||||
});
|
||||
const WorkflowRoutes: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("./Routes/WorkflowRoutes");
|
||||
});
|
||||
const StatusPagesRoutes: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("./Routes/StatusPagesRoutes");
|
||||
});
|
||||
const DashboardRoutes: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("./Routes/DashboardRoutes");
|
||||
});
|
||||
const ServiceRoutes: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("./Routes/ServiceRoutes");
|
||||
});
|
||||
const CodeRepositoryRoutes: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("./Routes/CodeRepositoryRoutes");
|
||||
return import("./Routes/AllRoutes").then((m: AllRoutesModule) => {
|
||||
return {
|
||||
default: m.ExceptionsRoutes,
|
||||
};
|
||||
});
|
||||
});
|
||||
const IncidentsRoutes: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
AllRoutesModule["IncidentsRoutes"]
|
||||
> = lazy(() => {
|
||||
return import("./Routes/IncidentsRoutes");
|
||||
});
|
||||
const AlertsRoutes: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("./Routes/AlertRoutes");
|
||||
return import("./Routes/AllRoutes").then((m: AllRoutesModule) => {
|
||||
return {
|
||||
default: m.IncidentsRoutes,
|
||||
};
|
||||
});
|
||||
});
|
||||
const AlertsRoutes: React.LazyExoticComponent<AllRoutesModule["AlertsRoutes"]> =
|
||||
lazy(() => {
|
||||
return import("./Routes/AllRoutes").then((m: AllRoutesModule) => {
|
||||
return {
|
||||
default: m.AlertsRoutes,
|
||||
};
|
||||
});
|
||||
});
|
||||
const ScheduledMaintenanceEventsRoutes: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
AllRoutesModule["ScheduledMaintenanceEventsRoutes"]
|
||||
> = lazy(() => {
|
||||
return import("./Routes/ScheduleMaintenanceEventsRoutes");
|
||||
});
|
||||
const SettingsRoutes: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("./Routes/SettingsRoutes");
|
||||
});
|
||||
const SettingsDangerZone: React.LazyExoticComponent<
|
||||
React.FunctionComponent<any>
|
||||
> = lazy(() => {
|
||||
return import("./Pages/Settings/DangerZone");
|
||||
return import("./Routes/AllRoutes").then((m: AllRoutesModule) => {
|
||||
return {
|
||||
default: m.ScheduledMaintenanceEventsRoutes,
|
||||
};
|
||||
});
|
||||
});
|
||||
const OnCallDutyRoutes: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
AllRoutesModule["OnCallDutyRoutes"]
|
||||
> = lazy(() => {
|
||||
return import("./Routes/OnCallDutyRoutes");
|
||||
return import("./Routes/AllRoutes").then((m: AllRoutesModule) => {
|
||||
return {
|
||||
default: m.OnCallDutyRoutes,
|
||||
};
|
||||
});
|
||||
});
|
||||
const Logout: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
const MonitorsRoutes: React.LazyExoticComponent<
|
||||
AllRoutesModule["MonitorsRoutes"]
|
||||
> = lazy(() => {
|
||||
return import("./Pages/Logout/Logout");
|
||||
});
|
||||
const UserProfilePicture: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("./Pages/Global/UserProfile/Picture");
|
||||
});
|
||||
const UserProfileOverview: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("./Pages/Global/UserProfile/Index");
|
||||
});
|
||||
const UserProfilePassword: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("./Pages/Global/UserProfile/Password");
|
||||
});
|
||||
const UseTwoFactorAuth: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("./Pages/Global/UserProfile/TwoFactorAuth");
|
||||
});
|
||||
const UserProfileDelete: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("./Pages/Global/UserProfile/DeleteAccount");
|
||||
});
|
||||
const ProjectInvitations: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("./Pages/Global/ProjectInvitations");
|
||||
});
|
||||
const ActiveIncidents: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("./Pages/Global/ActiveIncidents");
|
||||
});
|
||||
const ActiveAlerts: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("./Pages/Global/ActiveAlerts");
|
||||
});
|
||||
const ActiveAlertEpisodes: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("./Pages/Global/ActiveAlertEpisodes");
|
||||
});
|
||||
const ActiveIncidentEpisodes: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("./Pages/Global/ActiveIncidentEpisodes");
|
||||
});
|
||||
const MyOnCallPolicies: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("./Pages/Global/MyOnCallPolicies");
|
||||
});
|
||||
const UserSettingsRoutes: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("./Routes/UserSettingsRoutes");
|
||||
return import("./Routes/AllRoutes").then((m: AllRoutesModule) => {
|
||||
return {
|
||||
default: m.MonitorsRoutes,
|
||||
};
|
||||
});
|
||||
});
|
||||
const MonitorGroupRoutes: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
AllRoutesModule["MonitorGroupRoutes"]
|
||||
> = lazy(() => {
|
||||
return import("./Routes/MonitorGroupRoutes");
|
||||
return import("./Routes/AllRoutes").then((m: AllRoutesModule) => {
|
||||
return {
|
||||
default: m.MonitorGroupRoutes,
|
||||
};
|
||||
});
|
||||
});
|
||||
const WorkflowRoutes: React.LazyExoticComponent<
|
||||
AllRoutesModule["WorkflowRoutes"]
|
||||
> = lazy(() => {
|
||||
return import("./Routes/AllRoutes").then((m: AllRoutesModule) => {
|
||||
return {
|
||||
default: m.WorkflowRoutes,
|
||||
};
|
||||
});
|
||||
});
|
||||
const StatusPagesRoutes: React.LazyExoticComponent<
|
||||
AllRoutesModule["StatusPagesRoutes"]
|
||||
> = lazy(() => {
|
||||
return import("./Routes/AllRoutes").then((m: AllRoutesModule) => {
|
||||
return {
|
||||
default: m.StatusPagesRoutes,
|
||||
};
|
||||
});
|
||||
});
|
||||
const DashboardRoutes: React.LazyExoticComponent<
|
||||
AllRoutesModule["DashboardRoutes"]
|
||||
> = lazy(() => {
|
||||
return import("./Routes/AllRoutes").then((m: AllRoutesModule) => {
|
||||
return {
|
||||
default: m.DashboardRoutes,
|
||||
};
|
||||
});
|
||||
});
|
||||
const ServiceRoutes: React.LazyExoticComponent<
|
||||
AllRoutesModule["ServiceRoutes"]
|
||||
> = lazy(() => {
|
||||
return import("./Routes/AllRoutes").then((m: AllRoutesModule) => {
|
||||
return {
|
||||
default: m.ServiceRoutes,
|
||||
};
|
||||
});
|
||||
});
|
||||
const CodeRepositoryRoutes: React.LazyExoticComponent<
|
||||
AllRoutesModule["CodeRepositoryRoutes"]
|
||||
> = lazy(() => {
|
||||
return import("./Routes/AllRoutes").then((m: AllRoutesModule) => {
|
||||
return {
|
||||
default: m.CodeRepositoryRoutes,
|
||||
};
|
||||
});
|
||||
});
|
||||
const AIAgentTasksRoutes: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
AllRoutesModule["AIAgentTasksRoutes"]
|
||||
> = lazy(() => {
|
||||
return import("./Routes/AIAgentTasksRoutes");
|
||||
return import("./Routes/AllRoutes").then((m: AllRoutesModule) => {
|
||||
return {
|
||||
default: m.AIAgentTasksRoutes,
|
||||
};
|
||||
});
|
||||
});
|
||||
const ExceptionsRoutes: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
const SettingsRoutes: React.LazyExoticComponent<
|
||||
AllRoutesModule["SettingsRoutes"]
|
||||
> = lazy(() => {
|
||||
return import("./Routes/ExceptionsRoutes");
|
||||
return import("./Routes/AllRoutes").then((m: AllRoutesModule) => {
|
||||
return {
|
||||
default: m.SettingsRoutes,
|
||||
};
|
||||
});
|
||||
});
|
||||
const PageNotFound: React.LazyExoticComponent<
|
||||
React.FunctionComponent<PageComponentProps>
|
||||
const UserSettingsRoutes: React.LazyExoticComponent<
|
||||
AllRoutesModule["UserSettingsRoutes"]
|
||||
> = lazy(() => {
|
||||
return import("./Pages/PageNotFound/PageNotFound");
|
||||
return import("./Routes/AllRoutes").then((m: AllRoutesModule) => {
|
||||
return {
|
||||
default: m.UserSettingsRoutes,
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
const App: () => JSX.Element = () => {
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
import React, { FunctionComponent, ReactElement, useState } from "react";
|
||||
import MonitorStepDnsMonitor from "Common/Types/Monitor/MonitorStepDnsMonitor";
|
||||
import DnsRecordType from "Common/Types/Monitor/DnsMonitor/DnsRecordType";
|
||||
import Input, { InputType } from "Common/UI/Components/Input/Input";
|
||||
import Dropdown, {
|
||||
DropdownOption,
|
||||
DropdownValue,
|
||||
} from "Common/UI/Components/Dropdown/Dropdown";
|
||||
import FieldLabelElement from "Common/UI/Components/Forms/Fields/FieldLabel";
|
||||
import Button, { ButtonStyleType } from "Common/UI/Components/Button/Button";
|
||||
import DropdownUtil from "Common/UI/Utils/Dropdown";
|
||||
|
||||
export interface ComponentProps {
|
||||
monitorStepDnsMonitor: MonitorStepDnsMonitor;
|
||||
onChange: (value: MonitorStepDnsMonitor) => void;
|
||||
}
|
||||
|
||||
const DnsMonitorStepForm: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps,
|
||||
): ReactElement => {
|
||||
const [showAdvancedOptions, setShowAdvancedOptions] =
|
||||
useState<boolean>(false);
|
||||
|
||||
const recordTypeOptions: Array<DropdownOption> =
|
||||
DropdownUtil.getDropdownOptionsFromEnum(DnsRecordType);
|
||||
|
||||
return (
|
||||
<div className="space-y-5">
|
||||
<div>
|
||||
<FieldLabelElement
|
||||
title="Domain Name"
|
||||
description="The domain name to query (e.g. example.com)"
|
||||
required={true}
|
||||
/>
|
||||
<Input
|
||||
initialValue={props.monitorStepDnsMonitor.queryName}
|
||||
placeholder="example.com"
|
||||
onChange={(value: string) => {
|
||||
props.onChange({
|
||||
...props.monitorStepDnsMonitor,
|
||||
queryName: value,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<FieldLabelElement
|
||||
title="Record Type"
|
||||
description="The type of DNS record to query"
|
||||
required={true}
|
||||
/>
|
||||
<Dropdown
|
||||
options={recordTypeOptions}
|
||||
initialValue={recordTypeOptions.find((option: DropdownOption) => {
|
||||
return option.value === props.monitorStepDnsMonitor.recordType;
|
||||
})}
|
||||
onChange={(value: DropdownValue | Array<DropdownValue> | null) => {
|
||||
props.onChange({
|
||||
...props.monitorStepDnsMonitor,
|
||||
recordType: value as DnsRecordType,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<FieldLabelElement
|
||||
title="DNS Server (Optional)"
|
||||
description="Custom DNS server to use. Leave empty to use system default."
|
||||
required={false}
|
||||
/>
|
||||
<Input
|
||||
initialValue={props.monitorStepDnsMonitor.hostname || ""}
|
||||
placeholder="8.8.8.8 or leave empty for system default"
|
||||
onChange={(value: string) => {
|
||||
props.onChange({
|
||||
...props.monitorStepDnsMonitor,
|
||||
hostname: value || undefined,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{!showAdvancedOptions && (
|
||||
<div className="mt-1 -ml-3">
|
||||
<Button
|
||||
title="Advanced: Port, Timeout and Retries"
|
||||
buttonStyle={ButtonStyleType.SECONDARY_LINK}
|
||||
onClick={() => {
|
||||
setShowAdvancedOptions(true);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showAdvancedOptions && (
|
||||
<div className="space-y-4 border p-4 rounded-md bg-gray-50">
|
||||
<h4 className="font-medium">Advanced Options</h4>
|
||||
|
||||
<div>
|
||||
<FieldLabelElement
|
||||
title="Port"
|
||||
description="DNS port (default: 53)"
|
||||
required={false}
|
||||
/>
|
||||
<Input
|
||||
initialValue={
|
||||
props.monitorStepDnsMonitor.port?.toString() || "53"
|
||||
}
|
||||
placeholder="53"
|
||||
type={InputType.NUMBER}
|
||||
onChange={(value: string) => {
|
||||
props.onChange({
|
||||
...props.monitorStepDnsMonitor,
|
||||
port: parseInt(value) || 53,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<FieldLabelElement
|
||||
title="Timeout (ms)"
|
||||
description="How long to wait for a response before timing out"
|
||||
required={false}
|
||||
/>
|
||||
<Input
|
||||
initialValue={
|
||||
props.monitorStepDnsMonitor.timeout?.toString() || "5000"
|
||||
}
|
||||
placeholder="5000"
|
||||
type={InputType.NUMBER}
|
||||
onChange={(value: string) => {
|
||||
props.onChange({
|
||||
...props.monitorStepDnsMonitor,
|
||||
timeout: parseInt(value) || 5000,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<FieldLabelElement
|
||||
title="Retries"
|
||||
description="Number of times to retry on failure"
|
||||
required={false}
|
||||
/>
|
||||
<Input
|
||||
initialValue={
|
||||
props.monitorStepDnsMonitor.retries?.toString() || "3"
|
||||
}
|
||||
placeholder="3"
|
||||
type={InputType.NUMBER}
|
||||
onChange={(value: string) => {
|
||||
props.onChange({
|
||||
...props.monitorStepDnsMonitor,
|
||||
retries: parseInt(value) || 3,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DnsMonitorStepForm;
|
||||
@@ -75,6 +75,10 @@ import SnmpMonitorStepForm from "./SnmpMonitor/SnmpMonitorStepForm";
|
||||
import MonitorStepSnmpMonitor, {
|
||||
MonitorStepSnmpMonitorUtil,
|
||||
} from "Common/Types/Monitor/MonitorStepSnmpMonitor";
|
||||
import DnsMonitorStepForm from "./DnsMonitor/DnsMonitorStepForm";
|
||||
import MonitorStepDnsMonitor, {
|
||||
MonitorStepDnsMonitorUtil,
|
||||
} from "Common/Types/Monitor/MonitorStepDnsMonitor";
|
||||
|
||||
export interface ComponentProps {
|
||||
monitorStatusDropdownOptions: Array<DropdownOption>;
|
||||
@@ -790,6 +794,24 @@ return {
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{props.monitorType === MonitorType.DNS && (
|
||||
<Card
|
||||
title="DNS Monitor Configuration"
|
||||
description="Configure the DNS monitoring settings"
|
||||
>
|
||||
<DnsMonitorStepForm
|
||||
monitorStepDnsMonitor={
|
||||
monitorStep.data?.dnsMonitor ||
|
||||
MonitorStepDnsMonitorUtil.getDefault()
|
||||
}
|
||||
onChange={(value: MonitorStepDnsMonitor) => {
|
||||
monitorStep.setDnsMonitor(value);
|
||||
props.onChange?.(MonitorStep.clone(monitorStep));
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{/* Code Monitor Section */}
|
||||
{isCodeMonitor && (
|
||||
<Card
|
||||
|
||||
127
Dashboard/src/Components/Monitor/SummaryView/DnsMonitorView.tsx
Normal file
127
Dashboard/src/Components/Monitor/SummaryView/DnsMonitorView.tsx
Normal file
@@ -0,0 +1,127 @@
|
||||
import OneUptimeDate from "Common/Types/Date";
|
||||
import ProbeMonitorResponse from "Common/Types/Probe/ProbeMonitorResponse";
|
||||
import DnsMonitorResponse, {
|
||||
DnsRecordResponse,
|
||||
} from "Common/Types/Monitor/DnsMonitor/DnsMonitorResponse";
|
||||
import InfoCard from "Common/UI/Components/InfoCard/InfoCard";
|
||||
import React, { FunctionComponent, ReactElement } from "react";
|
||||
|
||||
export interface ComponentProps {
|
||||
probeMonitorResponse: ProbeMonitorResponse;
|
||||
probeName?: string | undefined;
|
||||
}
|
||||
|
||||
const DnsMonitorView: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps,
|
||||
): ReactElement => {
|
||||
const dnsResponse: DnsMonitorResponse | undefined =
|
||||
props.probeMonitorResponse?.dnsResponse;
|
||||
|
||||
let responseTimeInMs: number = dnsResponse?.responseTimeInMs || 0;
|
||||
|
||||
if (responseTimeInMs > 0) {
|
||||
responseTimeInMs = Math.round(responseTimeInMs);
|
||||
}
|
||||
|
||||
type GetDnssecStatusText = () => string;
|
||||
|
||||
const getDnssecStatusText: GetDnssecStatusText = (): string => {
|
||||
if (dnsResponse?.isDnssecValid === undefined) {
|
||||
return "Unknown";
|
||||
}
|
||||
return dnsResponse.isDnssecValid ? "Valid" : "Invalid";
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-5">
|
||||
<div className="flex space-x-3">
|
||||
<InfoCard
|
||||
className="w-1/5 shadow-none border-2 border-gray-100"
|
||||
title="Probe"
|
||||
value={props.probeName || "-"}
|
||||
/>
|
||||
<InfoCard
|
||||
className="w-1/5 shadow-none border-2 border-gray-100"
|
||||
title="Status"
|
||||
value={props.probeMonitorResponse.isOnline ? "Online" : "Offline"}
|
||||
/>
|
||||
<InfoCard
|
||||
className="w-1/5 shadow-none border-2 border-gray-100"
|
||||
title="Response Time"
|
||||
value={responseTimeInMs ? responseTimeInMs + " ms" : "-"}
|
||||
/>
|
||||
<InfoCard
|
||||
className="w-1/5 shadow-none border-2 border-gray-100"
|
||||
title="DNSSEC"
|
||||
value={getDnssecStatusText()}
|
||||
/>
|
||||
<InfoCard
|
||||
className="w-1/5 shadow-none border-2 border-gray-100"
|
||||
title="Monitored At"
|
||||
value={
|
||||
props.probeMonitorResponse?.monitoredAt
|
||||
? OneUptimeDate.getDateAsUserFriendlyLocalFormattedString(
|
||||
props.probeMonitorResponse.monitoredAt,
|
||||
)
|
||||
: "-"
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{props.probeMonitorResponse.failureCause && (
|
||||
<div className="flex space-x-3">
|
||||
<InfoCard
|
||||
className="w-full shadow-none border-2 border-gray-100"
|
||||
title="Error"
|
||||
value={props.probeMonitorResponse.failureCause?.toString() || "-"}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* DNS Records Section */}
|
||||
{dnsResponse?.records && dnsResponse.records.length > 0 && (
|
||||
<div className="space-y-3">
|
||||
<h3 className="text-sm font-medium text-gray-700">DNS Records</h3>
|
||||
<div className="border rounded-md overflow-hidden">
|
||||
<table className="min-w-full divide-y divide-gray-200">
|
||||
<thead className="bg-gray-50">
|
||||
<tr>
|
||||
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
Type
|
||||
</th>
|
||||
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
Value
|
||||
</th>
|
||||
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
TTL
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="bg-white divide-y divide-gray-200">
|
||||
{dnsResponse.records.map(
|
||||
(record: DnsRecordResponse, index: number) => {
|
||||
return (
|
||||
<tr key={index}>
|
||||
<td className="px-4 py-2 text-sm text-gray-500 font-mono">
|
||||
{record.type}
|
||||
</td>
|
||||
<td className="px-4 py-2 text-sm text-gray-900 font-mono">
|
||||
{record.value}
|
||||
</td>
|
||||
<td className="px-4 py-2 text-sm text-gray-500">
|
||||
{record.ttl !== undefined ? record.ttl : "-"}
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
},
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DnsMonitorView;
|
||||
@@ -7,6 +7,7 @@ import ServerMonitorSummaryView from "./ServerMonitorView";
|
||||
import SyntheticMonitorView from "./SyntheticMonitorView";
|
||||
import WebsiteMonitorSummaryView from "./WebsiteMonitorView";
|
||||
import SnmpMonitorView from "./SnmpMonitorView";
|
||||
import DnsMonitorView from "./DnsMonitorView";
|
||||
import IncomingMonitorRequest from "Common/Types/Monitor/IncomingMonitor/IncomingMonitorRequest";
|
||||
import IncomingEmailMonitorRequest from "Common/Types/Monitor/IncomingEmailMonitor/IncomingEmailMonitorRequest";
|
||||
import MonitorType, {
|
||||
@@ -121,6 +122,15 @@ const SummaryInfo: FunctionComponent<ComponentProps> = (
|
||||
);
|
||||
}
|
||||
|
||||
if (props.monitorType === MonitorType.DNS) {
|
||||
summaryComponent = (
|
||||
<DnsMonitorView
|
||||
probeMonitorResponse={probeMonitorResponse}
|
||||
probeName={props.probeName}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div key={key} className="space-y-6">
|
||||
{summaryComponent}
|
||||
|
||||
@@ -1,47 +1,22 @@
|
||||
import Loader from "../Components/Loader/Loader";
|
||||
import ComponentProps from "../Pages/PageComponentProps";
|
||||
import AIAgentTasksLayout from "../Pages/AIAgentTasks/Layout";
|
||||
import AIAgentTaskViewLayout from "../Pages/AIAgentTasks/View/Layout";
|
||||
import PageMap from "../Utils/PageMap";
|
||||
import RouteMap, { RouteUtil, AIAgentTasksRoutePath } from "../Utils/RouteMap";
|
||||
import Route from "Common/Types/API/Route";
|
||||
import React, {
|
||||
FunctionComponent,
|
||||
LazyExoticComponent,
|
||||
ReactElement,
|
||||
Suspense,
|
||||
lazy,
|
||||
} from "react";
|
||||
import React, { FunctionComponent, ReactElement } from "react";
|
||||
import { Route as PageRoute, Routes } from "react-router-dom";
|
||||
|
||||
// Pages
|
||||
const AIAgentTasks: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/AIAgentTasks/AIAgentTasks");
|
||||
});
|
||||
import AIAgentTasks from "../Pages/AIAgentTasks/AIAgentTasks";
|
||||
|
||||
const AIAgentTaskView: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/AIAgentTasks/View/Index");
|
||||
});
|
||||
import AIAgentTaskView from "../Pages/AIAgentTasks/View/Index";
|
||||
|
||||
const AIAgentTaskViewDelete: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/AIAgentTasks/View/Delete");
|
||||
});
|
||||
import AIAgentTaskViewDelete from "../Pages/AIAgentTasks/View/Delete";
|
||||
|
||||
const AIAgentTaskViewLogs: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/AIAgentTasks/View/Logs");
|
||||
});
|
||||
import AIAgentTaskViewLogs from "../Pages/AIAgentTasks/View/Logs";
|
||||
|
||||
const AIAgentTaskViewPullRequests: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/AIAgentTasks/View/PullRequests");
|
||||
});
|
||||
import AIAgentTaskViewPullRequests from "../Pages/AIAgentTasks/View/PullRequests";
|
||||
|
||||
const AIAgentTasksRoutes: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps,
|
||||
@@ -52,23 +27,19 @@ const AIAgentTasksRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
path={AIAgentTasksRoutePath[PageMap.AI_AGENT_TASKS] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<AIAgentTasks
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.AI_AGENT_TASKS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<AIAgentTasks
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.AI_AGENT_TASKS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
index
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<AIAgentTasks
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.AI_AGENT_TASKS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<AIAgentTasks
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.AI_AGENT_TASKS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</PageRoute>
|
||||
@@ -80,23 +51,19 @@ const AIAgentTasksRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
index
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<AIAgentTaskView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.AI_AGENT_TASK_VIEW] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<AIAgentTaskView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.AI_AGENT_TASK_VIEW] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.AI_AGENT_TASK_VIEW_LOGS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<AIAgentTaskViewLogs
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.AI_AGENT_TASK_VIEW_LOGS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<AIAgentTaskViewLogs
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.AI_AGENT_TASK_VIEW_LOGS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
@@ -104,25 +71,21 @@ const AIAgentTasksRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.AI_AGENT_TASK_VIEW_PULL_REQUESTS,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<AIAgentTaskViewPullRequests
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.AI_AGENT_TASK_VIEW_PULL_REQUESTS] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<AIAgentTaskViewPullRequests
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.AI_AGENT_TASK_VIEW_PULL_REQUESTS] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.AI_AGENT_TASK_VIEW_DELETE)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<AIAgentTaskViewDelete
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.AI_AGENT_TASK_VIEW_DELETE] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<AIAgentTaskViewDelete
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.AI_AGENT_TASK_VIEW_DELETE] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</PageRoute>
|
||||
|
||||
@@ -1,237 +1,88 @@
|
||||
import Navigation from "Common/UI/Utils/Navigation";
|
||||
import Loader from "../Components/Loader/Loader";
|
||||
import Layout from "../Pages/Alerts/Layout";
|
||||
import AlertViewLayout from "../Pages/Alerts/View/Layout";
|
||||
import ComponentProps from "../Pages/PageComponentProps";
|
||||
import PageMap from "../Utils/PageMap";
|
||||
import RouteMap, { AlertsRoutePath, RouteUtil } from "../Utils/RouteMap";
|
||||
import Route from "Common/Types/API/Route";
|
||||
import React, {
|
||||
FunctionComponent,
|
||||
LazyExoticComponent,
|
||||
Suspense,
|
||||
lazy,
|
||||
} from "react";
|
||||
import React, { FunctionComponent } from "react";
|
||||
import { Route as PageRoute, Routes } from "react-router-dom";
|
||||
|
||||
// Pages
|
||||
const Alerts: LazyExoticComponent<FunctionComponent<ComponentProps>> = lazy(
|
||||
() => {
|
||||
return import("../Pages/Alerts/Alerts");
|
||||
},
|
||||
);
|
||||
import Alerts from "../Pages/Alerts/Alerts";
|
||||
|
||||
const AlertCreate: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Alerts/Create");
|
||||
});
|
||||
const AlertView: LazyExoticComponent<FunctionComponent<ComponentProps>> = lazy(
|
||||
() => {
|
||||
return import("../Pages/Alerts/View/Index");
|
||||
},
|
||||
);
|
||||
import AlertCreate from "../Pages/Alerts/Create";
|
||||
import AlertView from "../Pages/Alerts/View/Index";
|
||||
|
||||
const AlertViewNotificationLogs: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Alerts/View/NotificationLogs");
|
||||
});
|
||||
import AlertViewNotificationLogs from "../Pages/Alerts/View/NotificationLogs";
|
||||
|
||||
const AlertViewAILogs: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Alerts/View/AILogs");
|
||||
});
|
||||
import AlertViewAILogs from "../Pages/Alerts/View/AILogs";
|
||||
|
||||
const AlertsWorkspaceConnectionSlack: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Alerts/WorkspaceConnectionSlack");
|
||||
});
|
||||
import AlertsWorkspaceConnectionSlack from "../Pages/Alerts/WorkspaceConnectionSlack";
|
||||
|
||||
const AlertsWorkspaceConnectionMicrosoftTeams: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Alerts/WorkspaceConnectionMicrosoftTeams");
|
||||
});
|
||||
import AlertsWorkspaceConnectionMicrosoftTeams from "../Pages/Alerts/WorkspaceConnectionMicrosoftTeams";
|
||||
|
||||
const AlertOnCallPolicyExecutionLogs: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Alerts/View/OnCallPolicyExecutionLogs");
|
||||
});
|
||||
import AlertOnCallPolicyExecutionLogs from "../Pages/Alerts/View/OnCallPolicyExecutionLogs";
|
||||
|
||||
const AlertViewDelete: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Alerts/View/Delete");
|
||||
});
|
||||
const AlertViewStateTimeline: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Alerts/View/StateTimeline");
|
||||
});
|
||||
import AlertViewDelete from "../Pages/Alerts/View/Delete";
|
||||
import AlertViewStateTimeline from "../Pages/Alerts/View/StateTimeline";
|
||||
|
||||
const AlertInternalNote: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Alerts/View/InternalNote");
|
||||
});
|
||||
import AlertInternalNote from "../Pages/Alerts/View/InternalNote";
|
||||
|
||||
const UnresolvedAlerts: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Alerts/Unresolved");
|
||||
});
|
||||
const AlertViewCustomFields: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Alerts/View/CustomFields");
|
||||
});
|
||||
const AlertViewOwner: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Alerts/View/Owners");
|
||||
});
|
||||
import UnresolvedAlerts from "../Pages/Alerts/Unresolved";
|
||||
import AlertViewCustomFields from "../Pages/Alerts/View/CustomFields";
|
||||
import AlertViewOwner from "../Pages/Alerts/View/Owners";
|
||||
|
||||
const AlertViewRootCause: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Alerts/View/RootCause");
|
||||
});
|
||||
import AlertViewRootCause from "../Pages/Alerts/View/RootCause";
|
||||
|
||||
const AlertViewRemediation: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Alerts/View/Remediation");
|
||||
});
|
||||
import AlertViewRemediation from "../Pages/Alerts/View/Remediation";
|
||||
|
||||
const AlertDescription: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Alerts/View/Description");
|
||||
});
|
||||
import AlertDescription from "../Pages/Alerts/View/Description";
|
||||
|
||||
// Settings Pages
|
||||
const AlertSettingsState: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Alerts/Settings/AlertState");
|
||||
});
|
||||
import AlertSettingsState from "../Pages/Alerts/Settings/AlertState";
|
||||
|
||||
const AlertSettingsSeverity: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Alerts/Settings/AlertSeverity");
|
||||
});
|
||||
import AlertSettingsSeverity from "../Pages/Alerts/Settings/AlertSeverity";
|
||||
|
||||
const AlertSettingsNoteTemplates: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Alerts/Settings/AlertNoteTemplates");
|
||||
});
|
||||
import AlertSettingsNoteTemplates from "../Pages/Alerts/Settings/AlertNoteTemplates";
|
||||
|
||||
const AlertSettingsNoteTemplatesView: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Alerts/Settings/AlertNoteTemplateDetail");
|
||||
});
|
||||
import AlertSettingsNoteTemplatesView from "../Pages/Alerts/Settings/AlertNoteTemplateDetail";
|
||||
|
||||
const AlertSettingsCustomFields: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Alerts/Settings/AlertCustomFields");
|
||||
});
|
||||
import AlertSettingsCustomFields from "../Pages/Alerts/Settings/AlertCustomFields";
|
||||
|
||||
const AlertSettingsGroupingRules: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Alerts/Settings/AlertGroupingRules");
|
||||
});
|
||||
import AlertSettingsGroupingRules from "../Pages/Alerts/Settings/AlertGroupingRules";
|
||||
|
||||
const AlertSettingsMore: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Alerts/Settings/AlertMoreSettings");
|
||||
});
|
||||
import AlertSettingsMore from "../Pages/Alerts/Settings/AlertMoreSettings";
|
||||
|
||||
// Episode Pages
|
||||
const Episodes: LazyExoticComponent<FunctionComponent<ComponentProps>> = lazy(
|
||||
() => {
|
||||
return import("../Pages/Alerts/Episodes");
|
||||
},
|
||||
);
|
||||
import Episodes from "../Pages/Alerts/Episodes";
|
||||
|
||||
const EpisodeCreate: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Alerts/EpisodeCreate");
|
||||
});
|
||||
import EpisodeCreate from "../Pages/Alerts/EpisodeCreate";
|
||||
|
||||
const UnresolvedEpisodes: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Alerts/UnresolvedEpisodes");
|
||||
});
|
||||
import UnresolvedEpisodes from "../Pages/Alerts/UnresolvedEpisodes";
|
||||
|
||||
// Episode View Pages
|
||||
const EpisodeViewLayout: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Alerts/EpisodeView/Layout");
|
||||
});
|
||||
import EpisodeViewLayout from "../Pages/Alerts/EpisodeView/Layout";
|
||||
|
||||
const EpisodeView: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Alerts/EpisodeView/Index");
|
||||
});
|
||||
import EpisodeView from "../Pages/Alerts/EpisodeView/Index";
|
||||
|
||||
const EpisodeViewDescription: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Alerts/EpisodeView/Description");
|
||||
});
|
||||
import EpisodeViewDescription from "../Pages/Alerts/EpisodeView/Description";
|
||||
|
||||
const EpisodeViewRootCause: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Alerts/EpisodeView/RootCause");
|
||||
});
|
||||
import EpisodeViewRootCause from "../Pages/Alerts/EpisodeView/RootCause";
|
||||
|
||||
const EpisodeViewOwners: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Alerts/EpisodeView/Owners");
|
||||
});
|
||||
import EpisodeViewOwners from "../Pages/Alerts/EpisodeView/Owners";
|
||||
|
||||
const EpisodeViewStateTimeline: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Alerts/EpisodeView/StateTimeline");
|
||||
});
|
||||
import EpisodeViewStateTimeline from "../Pages/Alerts/EpisodeView/StateTimeline";
|
||||
|
||||
const EpisodeViewAlerts: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Alerts/EpisodeView/Alerts");
|
||||
});
|
||||
import EpisodeViewAlerts from "../Pages/Alerts/EpisodeView/Alerts";
|
||||
|
||||
const EpisodeViewInternalNote: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Alerts/EpisodeView/InternalNote");
|
||||
});
|
||||
import EpisodeViewInternalNote from "../Pages/Alerts/EpisodeView/InternalNote";
|
||||
|
||||
const EpisodeViewRemediation: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Alerts/EpisodeView/Remediation");
|
||||
});
|
||||
import EpisodeViewRemediation from "../Pages/Alerts/EpisodeView/Remediation";
|
||||
|
||||
const EpisodeViewDelete: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Alerts/EpisodeView/Delete");
|
||||
});
|
||||
import EpisodeViewDelete from "../Pages/Alerts/EpisodeView/Delete";
|
||||
|
||||
const AlertEpisodeDocs: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Alerts/EpisodeDocs");
|
||||
});
|
||||
import AlertEpisodeDocs from "../Pages/Alerts/EpisodeDocs";
|
||||
|
||||
const AlertsRoutes: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps,
|
||||
@@ -251,24 +102,17 @@ const AlertsRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
path={AlertsRoutePath[PageMap.ALERTS] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<Alerts
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERTS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<Alerts {...props} pageRoute={RouteMap[PageMap.ALERTS] as Route} />
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={AlertsRoutePath[PageMap.UNRESOLVED_ALERTS] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<UnresolvedAlerts
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.UNRESOLVED_ALERTS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<UnresolvedAlerts
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.UNRESOLVED_ALERTS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -277,14 +121,12 @@ const AlertsRoutes: FunctionComponent<ComponentProps> = (
|
||||
AlertsRoutePath[PageMap.ALERTS_WORKSPACE_CONNECTION_SLACK] || ""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<AlertsWorkspaceConnectionSlack
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ALERTS_WORKSPACE_CONNECTION_SLACK] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<AlertsWorkspaceConnectionSlack
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ALERTS_WORKSPACE_CONNECTION_SLACK] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -295,28 +137,24 @@ const AlertsRoutes: FunctionComponent<ComponentProps> = (
|
||||
] || ""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<AlertsWorkspaceConnectionMicrosoftTeams
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ALERTS_WORKSPACE_CONNECTION_MICROSOFT_TEAMS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<AlertsWorkspaceConnectionMicrosoftTeams
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ALERTS_WORKSPACE_CONNECTION_MICROSOFT_TEAMS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={AlertsRoutePath[PageMap.ALERT_CREATE] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<AlertCreate
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_CREATE] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<AlertCreate
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_CREATE] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -324,38 +162,32 @@ const AlertsRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
path={AlertsRoutePath[PageMap.ALERTS_SETTINGS_STATE] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<AlertSettingsState
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERTS_SETTINGS_STATE] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<AlertSettingsState
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERTS_SETTINGS_STATE] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={AlertsRoutePath[PageMap.ALERTS_SETTINGS_SEVERITY] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<AlertSettingsSeverity
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERTS_SETTINGS_SEVERITY] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<AlertSettingsSeverity
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERTS_SETTINGS_SEVERITY] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={AlertsRoutePath[PageMap.ALERTS_SETTINGS_NOTE_TEMPLATES] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<AlertSettingsNoteTemplates
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ALERTS_SETTINGS_NOTE_TEMPLATES] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<AlertSettingsNoteTemplates
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ALERTS_SETTINGS_NOTE_TEMPLATES] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -364,54 +196,46 @@ const AlertsRoutes: FunctionComponent<ComponentProps> = (
|
||||
AlertsRoutePath[PageMap.ALERTS_SETTINGS_NOTE_TEMPLATES_VIEW] || ""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<AlertSettingsNoteTemplatesView
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ALERTS_SETTINGS_NOTE_TEMPLATES_VIEW] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<AlertSettingsNoteTemplatesView
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ALERTS_SETTINGS_NOTE_TEMPLATES_VIEW] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={AlertsRoutePath[PageMap.ALERTS_SETTINGS_CUSTOM_FIELDS] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<AlertSettingsCustomFields
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ALERTS_SETTINGS_CUSTOM_FIELDS] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<AlertSettingsCustomFields
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ALERTS_SETTINGS_CUSTOM_FIELDS] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={AlertsRoutePath[PageMap.ALERTS_SETTINGS_GROUPING_RULES] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<AlertSettingsGroupingRules
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ALERTS_SETTINGS_GROUPING_RULES] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<AlertSettingsGroupingRules
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ALERTS_SETTINGS_GROUPING_RULES] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={AlertsRoutePath[PageMap.ALERTS_SETTINGS_MORE] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<AlertSettingsMore
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERTS_SETTINGS_MORE] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<AlertSettingsMore
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERTS_SETTINGS_MORE] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -419,48 +243,40 @@ const AlertsRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
path={AlertsRoutePath[PageMap.ALERT_EPISODE_CREATE] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<EpisodeCreate
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_EPISODE_CREATE] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<EpisodeCreate
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_EPISODE_CREATE] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={AlertsRoutePath[PageMap.ALERT_EPISODES] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<Episodes
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_EPISODES] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<Episodes
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_EPISODES] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={AlertsRoutePath[PageMap.UNRESOLVED_ALERT_EPISODES] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<UnresolvedEpisodes
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.UNRESOLVED_ALERT_EPISODES] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<UnresolvedEpisodes
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.UNRESOLVED_ALERT_EPISODES] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={AlertsRoutePath[PageMap.ALERT_EPISODE_DOCS] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<AlertEpisodeDocs
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_EPISODE_DOCS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<AlertEpisodeDocs
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_EPISODE_DOCS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</PageRoute>
|
||||
@@ -472,12 +288,10 @@ const AlertsRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
index
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<AlertView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_VIEW] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<AlertView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_VIEW] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
@@ -485,105 +299,87 @@ const AlertsRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.ALERT_VIEW_NOTIFICATION_LOGS,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<AlertViewNotificationLogs
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ALERT_VIEW_NOTIFICATION_LOGS] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<AlertViewNotificationLogs
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ALERT_VIEW_NOTIFICATION_LOGS] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.ALERT_VIEW_AI_LOGS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<AlertViewAILogs
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_VIEW_AI_LOGS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<AlertViewAILogs
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_VIEW_AI_LOGS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.ALERT_VIEW_DESCRIPTION)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<AlertDescription
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_VIEW_DESCRIPTION] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<AlertDescription
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_VIEW_DESCRIPTION] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.ALERT_VIEW_ROOT_CAUSE)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<AlertViewRootCause
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_VIEW_ROOT_CAUSE] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<AlertViewRootCause
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_VIEW_ROOT_CAUSE] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.ALERT_VIEW_REMEDIATION)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<AlertViewRemediation
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_VIEW_REMEDIATION] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<AlertViewRemediation
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_VIEW_REMEDIATION] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.ALERT_VIEW_STATE_TIMELINE)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<AlertViewStateTimeline
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_VIEW_STATE_TIMELINE] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<AlertViewStateTimeline
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_VIEW_STATE_TIMELINE] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.ALERT_VIEW_INTERNAL_NOTE)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<AlertInternalNote
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_VIEW_INTERNAL_NOTE] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<AlertInternalNote
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_VIEW_INTERNAL_NOTE] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.ALERT_VIEW_CUSTOM_FIELDS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<AlertViewCustomFields
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_VIEW_CUSTOM_FIELDS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<AlertViewCustomFields
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_VIEW_CUSTOM_FIELDS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.ALERT_VIEW_OWNERS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<AlertViewOwner
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_VIEW_OWNERS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<AlertViewOwner
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_VIEW_OWNERS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
@@ -591,27 +387,23 @@ const AlertsRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.ALERT_VIEW_ON_CALL_POLICY_EXECUTION_LOGS,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<AlertOnCallPolicyExecutionLogs
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ALERT_VIEW_ON_CALL_POLICY_EXECUTION_LOGS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<AlertOnCallPolicyExecutionLogs
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ALERT_VIEW_ON_CALL_POLICY_EXECUTION_LOGS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.ALERT_VIEW_DELETE)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<AlertViewDelete
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_VIEW_DELETE] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<AlertViewDelete
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_VIEW_DELETE] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</PageRoute>
|
||||
@@ -624,12 +416,10 @@ const AlertsRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
index
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<EpisodeView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_EPISODE_VIEW] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<EpisodeView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_EPISODE_VIEW] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
@@ -637,14 +427,12 @@ const AlertsRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.ALERT_EPISODE_VIEW_DESCRIPTION,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<EpisodeViewDescription
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ALERT_EPISODE_VIEW_DESCRIPTION] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<EpisodeViewDescription
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ALERT_EPISODE_VIEW_DESCRIPTION] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
@@ -652,25 +440,21 @@ const AlertsRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.ALERT_EPISODE_VIEW_ROOT_CAUSE,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<EpisodeViewRootCause
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ALERT_EPISODE_VIEW_ROOT_CAUSE] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<EpisodeViewRootCause
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ALERT_EPISODE_VIEW_ROOT_CAUSE] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.ALERT_EPISODE_VIEW_OWNERS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<EpisodeViewOwners
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_EPISODE_VIEW_OWNERS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<EpisodeViewOwners
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_EPISODE_VIEW_OWNERS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
@@ -678,25 +462,21 @@ const AlertsRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.ALERT_EPISODE_VIEW_STATE_TIMELINE,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<EpisodeViewStateTimeline
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ALERT_EPISODE_VIEW_STATE_TIMELINE] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<EpisodeViewStateTimeline
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ALERT_EPISODE_VIEW_STATE_TIMELINE] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.ALERT_EPISODE_VIEW_ALERTS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<EpisodeViewAlerts
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_EPISODE_VIEW_ALERTS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<EpisodeViewAlerts
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_EPISODE_VIEW_ALERTS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
@@ -704,14 +484,12 @@ const AlertsRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.ALERT_EPISODE_VIEW_INTERNAL_NOTE,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<EpisodeViewInternalNote
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ALERT_EPISODE_VIEW_INTERNAL_NOTE] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<EpisodeViewInternalNote
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ALERT_EPISODE_VIEW_INTERNAL_NOTE] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
@@ -719,25 +497,21 @@ const AlertsRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.ALERT_EPISODE_VIEW_REMEDIATION,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<EpisodeViewRemediation
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ALERT_EPISODE_VIEW_REMEDIATION] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<EpisodeViewRemediation
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ALERT_EPISODE_VIEW_REMEDIATION] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.ALERT_EPISODE_VIEW_DELETE)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<EpisodeViewDelete
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_EPISODE_VIEW_DELETE] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<EpisodeViewDelete
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ALERT_EPISODE_VIEW_DELETE] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</PageRoute>
|
||||
|
||||
27
Dashboard/src/Routes/AllRoutes.tsx
Normal file
27
Dashboard/src/Routes/AllRoutes.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
// Observability
|
||||
export { default as LogsRoutes } from "./LogsRoutes";
|
||||
export { default as MetricsRoutes } from "./MetricsRoutes";
|
||||
export { default as TracesRoutes } from "./TracesRoutes";
|
||||
export { default as ExceptionsRoutes } from "./ExceptionsRoutes";
|
||||
|
||||
// Incident management
|
||||
export { default as IncidentsRoutes } from "./IncidentsRoutes";
|
||||
export { default as AlertsRoutes } from "./AlertRoutes";
|
||||
export { default as ScheduledMaintenanceEventsRoutes } from "./ScheduleMaintenanceEventsRoutes";
|
||||
export { default as OnCallDutyRoutes } from "./OnCallDutyRoutes";
|
||||
|
||||
// Monitoring
|
||||
export { default as MonitorsRoutes } from "./MonitorsRoutes";
|
||||
export { default as MonitorGroupRoutes } from "./MonitorGroupRoutes";
|
||||
|
||||
// Platform
|
||||
export { default as WorkflowRoutes } from "./WorkflowRoutes";
|
||||
export { default as StatusPagesRoutes } from "./StatusPagesRoutes";
|
||||
export { default as DashboardRoutes } from "./DashboardRoutes";
|
||||
export { default as ServiceRoutes } from "./ServiceRoutes";
|
||||
export { default as CodeRepositoryRoutes } from "./CodeRepositoryRoutes";
|
||||
export { default as AIAgentTasksRoutes } from "./AIAgentTasksRoutes";
|
||||
|
||||
// Settings
|
||||
export { default as SettingsRoutes } from "./SettingsRoutes";
|
||||
export { default as UserSettingsRoutes } from "./UserSettingsRoutes";
|
||||
@@ -1,4 +1,3 @@
|
||||
import Loader from "../Components/Loader/Loader";
|
||||
import ComponentProps from "../Pages/PageComponentProps";
|
||||
import CodeRepositoryViewLayout from "../Pages/CodeRepository/View/Layout";
|
||||
import CodeRepositoryLayout from "../Pages/CodeRepository/Layout";
|
||||
@@ -8,44 +7,19 @@ import RouteMap, {
|
||||
CodeRepositoryRoutePath,
|
||||
} from "../Utils/RouteMap";
|
||||
import Route from "Common/Types/API/Route";
|
||||
import React, {
|
||||
FunctionComponent,
|
||||
LazyExoticComponent,
|
||||
ReactElement,
|
||||
Suspense,
|
||||
lazy,
|
||||
} from "react";
|
||||
import React, { FunctionComponent, ReactElement } from "react";
|
||||
import { Route as PageRoute, Routes } from "react-router-dom";
|
||||
|
||||
// Pages
|
||||
const CodeRepository: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/CodeRepository/CodeRepository");
|
||||
});
|
||||
import CodeRepository from "../Pages/CodeRepository/CodeRepository";
|
||||
|
||||
const CodeRepositoryView: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/CodeRepository/View/Index");
|
||||
});
|
||||
import CodeRepositoryView from "../Pages/CodeRepository/View/Index";
|
||||
|
||||
const CodeRepositoryViewDelete: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/CodeRepository/View/Delete");
|
||||
});
|
||||
import CodeRepositoryViewDelete from "../Pages/CodeRepository/View/Delete";
|
||||
|
||||
const CodeRepositoryViewSettings: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/CodeRepository/View/Settings");
|
||||
});
|
||||
import CodeRepositoryViewSettings from "../Pages/CodeRepository/View/Settings";
|
||||
|
||||
const CodeRepositoryViewServices: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/CodeRepository/View/Services");
|
||||
});
|
||||
import CodeRepositoryViewServices from "../Pages/CodeRepository/View/Services";
|
||||
|
||||
const CodeRepositoryRoutes: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps,
|
||||
@@ -56,12 +30,10 @@ const CodeRepositoryRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
path={CodeRepositoryRoutePath[PageMap.CODE_REPOSITORY] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<CodeRepository
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.CODE_REPOSITORY] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<CodeRepository
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.CODE_REPOSITORY] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</PageRoute>
|
||||
@@ -73,12 +45,10 @@ const CodeRepositoryRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
index
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<CodeRepositoryView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.CODE_REPOSITORY_VIEW] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<CodeRepositoryView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.CODE_REPOSITORY_VIEW] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -87,14 +57,10 @@ const CodeRepositoryRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.CODE_REPOSITORY_VIEW_DELETE,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<CodeRepositoryViewDelete
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.CODE_REPOSITORY_VIEW_DELETE] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<CodeRepositoryViewDelete
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.CODE_REPOSITORY_VIEW_DELETE] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -103,14 +69,12 @@ const CodeRepositoryRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.CODE_REPOSITORY_VIEW_SETTINGS,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<CodeRepositoryViewSettings
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.CODE_REPOSITORY_VIEW_SETTINGS] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<CodeRepositoryViewSettings
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.CODE_REPOSITORY_VIEW_SETTINGS] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -119,14 +83,12 @@ const CodeRepositoryRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.CODE_REPOSITORY_VIEW_SERVICES,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<CodeRepositoryViewServices
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.CODE_REPOSITORY_VIEW_SERVICES] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<CodeRepositoryViewServices
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.CODE_REPOSITORY_VIEW_SERVICES] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</PageRoute>
|
||||
|
||||
@@ -1,46 +1,20 @@
|
||||
import Loader from "../Components/Loader/Loader";
|
||||
import ComponentProps from "../Pages/PageComponentProps";
|
||||
import DashboardViewLayout from "../Pages/Dashboards/View/Layout";
|
||||
import PageMap from "../Utils/PageMap";
|
||||
import RouteMap, { DashboardsRoutePath, RouteUtil } from "../Utils/RouteMap";
|
||||
import Route from "Common/Types/API/Route";
|
||||
import React, {
|
||||
FunctionComponent,
|
||||
LazyExoticComponent,
|
||||
ReactElement,
|
||||
Suspense,
|
||||
lazy,
|
||||
} from "react";
|
||||
import React, { FunctionComponent, ReactElement } from "react";
|
||||
import { Route as PageRoute, Routes } from "react-router-dom";
|
||||
|
||||
const Dashboards: LazyExoticComponent<FunctionComponent<ComponentProps>> = lazy(
|
||||
() => {
|
||||
return import("../Pages/Dashboards/Dashboards");
|
||||
},
|
||||
);
|
||||
import Dashboards from "../Pages/Dashboards/Dashboards";
|
||||
|
||||
const DashboardView: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Dashboards/View/Index");
|
||||
});
|
||||
import DashboardView from "../Pages/Dashboards/View/Index";
|
||||
|
||||
const DashboardViewOverview: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Dashboards/View/Overview");
|
||||
});
|
||||
import DashboardViewOverview from "../Pages/Dashboards/View/Overview";
|
||||
|
||||
const DashboardViewDelete: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Dashboards/View/Delete");
|
||||
});
|
||||
import DashboardViewDelete from "../Pages/Dashboards/View/Delete";
|
||||
|
||||
const DashboardViewSettings: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Dashboards/View/Settings");
|
||||
});
|
||||
import DashboardViewSettings from "../Pages/Dashboards/View/Settings";
|
||||
|
||||
const DashboardsRoutes: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps,
|
||||
@@ -50,12 +24,10 @@ const DashboardsRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
path={DashboardsRoutePath[PageMap.DASHBOARDS] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<Dashboards
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.DASHBOARDS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<Dashboards
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.DASHBOARDS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -66,48 +38,40 @@ const DashboardsRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
index
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<DashboardView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.DASHBOARD_VIEW] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<DashboardView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.DASHBOARD_VIEW] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.DASHBOARD_VIEW_OVERVIEW)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<DashboardViewOverview
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.DASHBOARD_VIEW_OVERVIEW] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<DashboardViewOverview
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.DASHBOARD_VIEW_OVERVIEW] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.DASHBOARD_VIEW_DELETE)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<DashboardViewDelete
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.DASHBOARD_VIEW_DELETE] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<DashboardViewDelete
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.DASHBOARD_VIEW_DELETE] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.DASHBOARD_VIEW_SETTINGS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<DashboardViewSettings
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.DASHBOARD_VIEW_SETTINGS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<DashboardViewSettings
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.DASHBOARD_VIEW_SETTINGS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</PageRoute>
|
||||
|
||||
@@ -1,42 +1,20 @@
|
||||
import Loader from "../Components/Loader/Loader";
|
||||
import ComponentProps from "../Pages/PageComponentProps";
|
||||
import ExceptionsLayout from "../Pages/Exceptions/Layout";
|
||||
import ExceptionViewLayout from "../Pages/Exceptions/View/Layout";
|
||||
import PageMap from "../Utils/PageMap";
|
||||
import RouteMap, { ExceptionsRoutePath } from "../Utils/RouteMap";
|
||||
import Route from "Common/Types/API/Route";
|
||||
import React, {
|
||||
FunctionComponent,
|
||||
LazyExoticComponent,
|
||||
ReactElement,
|
||||
Suspense,
|
||||
lazy,
|
||||
} from "react";
|
||||
import React, { FunctionComponent, ReactElement } from "react";
|
||||
import { Route as PageRoute, Routes } from "react-router-dom";
|
||||
|
||||
// Lazy Pages
|
||||
const ExceptionsUnresolved: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Exceptions/Unresolved");
|
||||
});
|
||||
// Pages
|
||||
import ExceptionsUnresolved from "../Pages/Exceptions/Unresolved";
|
||||
|
||||
const ExceptionsResolved: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Exceptions/Resolved");
|
||||
});
|
||||
import ExceptionsResolved from "../Pages/Exceptions/Resolved";
|
||||
|
||||
const ExceptionsArchived: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Exceptions/Archived");
|
||||
});
|
||||
import ExceptionsArchived from "../Pages/Exceptions/Archived";
|
||||
|
||||
const ExceptionView: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Exceptions/View/Index");
|
||||
});
|
||||
import ExceptionView from "../Pages/Exceptions/View/Index";
|
||||
|
||||
const ExceptionsRoutes: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps,
|
||||
@@ -47,48 +25,40 @@ const ExceptionsRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
index
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ExceptionsUnresolved
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.EXCEPTIONS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<ExceptionsUnresolved
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.EXCEPTIONS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={ExceptionsRoutePath[PageMap.EXCEPTIONS_UNRESOLVED] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ExceptionsUnresolved
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.EXCEPTIONS_UNRESOLVED] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<ExceptionsUnresolved
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.EXCEPTIONS_UNRESOLVED] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={ExceptionsRoutePath[PageMap.EXCEPTIONS_RESOLVED] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ExceptionsResolved
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.EXCEPTIONS_RESOLVED] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<ExceptionsResolved
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.EXCEPTIONS_RESOLVED] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={ExceptionsRoutePath[PageMap.EXCEPTIONS_ARCHIVED] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ExceptionsArchived
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.EXCEPTIONS_ARCHIVED] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<ExceptionsArchived
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.EXCEPTIONS_ARCHIVED] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</PageRoute>
|
||||
@@ -101,12 +71,10 @@ const ExceptionsRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
index
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ExceptionView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.EXCEPTIONS_VIEW] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<ExceptionView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.EXCEPTIONS_VIEW] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</PageRoute>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,11 @@
|
||||
import Loader from "../Components/Loader/Loader";
|
||||
import { RoutesProps } from "../Types/RoutesProps";
|
||||
import PageMap from "../Utils/PageMap";
|
||||
import RouteMap from "../Utils/RouteMap";
|
||||
import Route from "Common/Types/API/Route";
|
||||
import React, { FunctionComponent, ReactElement, Suspense, lazy } from "react";
|
||||
import React, { FunctionComponent, ReactElement } from "react";
|
||||
import { Route as PageRoute, Routes } from "react-router-dom";
|
||||
|
||||
const Init: any = lazy(() => {
|
||||
return import("../Pages/Init/Init");
|
||||
});
|
||||
import Init from "../Pages/Init/Init";
|
||||
|
||||
const InitRoutes: FunctionComponent<RoutesProps> = (
|
||||
props: RoutesProps,
|
||||
@@ -19,28 +16,24 @@ const InitRoutes: FunctionComponent<RoutesProps> = (
|
||||
<PageRoute
|
||||
path={RouteMap[PageMap.INIT]?.toString() || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<Init
|
||||
{...rest}
|
||||
pageRoute={RouteMap[PageMap.INIT] as Route}
|
||||
projects={projects}
|
||||
isLoadingProjects={isLoading}
|
||||
/>
|
||||
</Suspense>
|
||||
<Init
|
||||
{...rest}
|
||||
pageRoute={RouteMap[PageMap.INIT] as Route}
|
||||
projects={projects}
|
||||
isLoadingProjects={isLoading}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteMap[PageMap.INIT_PROJECT]?.toString() || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<Init
|
||||
{...rest}
|
||||
pageRoute={RouteMap[PageMap.INIT_PROJECT] as Route}
|
||||
projects={projects}
|
||||
isLoadingProjects={isLoading}
|
||||
/>
|
||||
</Suspense>
|
||||
<Init
|
||||
{...rest}
|
||||
pageRoute={RouteMap[PageMap.INIT_PROJECT] as Route}
|
||||
projects={projects}
|
||||
isLoadingProjects={isLoading}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Routes>
|
||||
|
||||
@@ -1,24 +1,13 @@
|
||||
import Loader from "../Components/Loader/Loader";
|
||||
import ComponentProps from "../Pages/PageComponentProps";
|
||||
import LogsLayout from "../Pages/Logs/Layout";
|
||||
import PageMap from "../Utils/PageMap";
|
||||
import RouteMap from "../Utils/RouteMap";
|
||||
import Route from "Common/Types/API/Route";
|
||||
import React, {
|
||||
FunctionComponent,
|
||||
LazyExoticComponent,
|
||||
ReactElement,
|
||||
Suspense,
|
||||
lazy,
|
||||
} from "react";
|
||||
import React, { FunctionComponent, ReactElement } from "react";
|
||||
import { Route as PageRoute, Routes } from "react-router-dom";
|
||||
|
||||
// Lazy Pages
|
||||
const LogsPage: LazyExoticComponent<FunctionComponent<ComponentProps>> = lazy(
|
||||
() => {
|
||||
return import("../Pages/Logs/Index");
|
||||
},
|
||||
);
|
||||
// Pages
|
||||
import LogsPage from "../Pages/Logs/Index";
|
||||
|
||||
const LogsRoutes: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps,
|
||||
@@ -29,12 +18,7 @@ const LogsRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
index
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<LogsPage
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.LOGS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<LogsPage {...props} pageRoute={RouteMap[PageMap.LOGS] as Route} />
|
||||
}
|
||||
/>
|
||||
</PageRoute>
|
||||
|
||||
@@ -1,29 +1,16 @@
|
||||
import Loader from "../Components/Loader/Loader";
|
||||
import ComponentProps from "../Pages/PageComponentProps";
|
||||
import MetricsLayout from "../Pages/Metrics/Layout";
|
||||
import MetricsViewLayout from "../Pages/Metrics/View/Layout";
|
||||
import PageMap from "../Utils/PageMap";
|
||||
import RouteMap, { RouteUtil, MetricsRoutePath } from "../Utils/RouteMap";
|
||||
import Route from "Common/Types/API/Route";
|
||||
import React, {
|
||||
FunctionComponent,
|
||||
LazyExoticComponent,
|
||||
ReactElement,
|
||||
Suspense,
|
||||
lazy,
|
||||
} from "react";
|
||||
import React, { FunctionComponent, ReactElement } from "react";
|
||||
import { Route as PageRoute, Routes } from "react-router-dom";
|
||||
|
||||
// Lazy Pages
|
||||
const MetricsPage: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Metrics/Index");
|
||||
});
|
||||
// Pages
|
||||
import MetricsPage from "../Pages/Metrics/Index";
|
||||
|
||||
const MetricViewPage: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Metrics/View/Index");
|
||||
});
|
||||
import MetricViewPage from "../Pages/Metrics/View/Index";
|
||||
|
||||
const MetricsRoutes: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps,
|
||||
@@ -34,12 +21,10 @@ const MetricsRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
index
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MetricsPage
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.METRICS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<MetricsPage
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.METRICS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</PageRoute>
|
||||
@@ -52,24 +37,20 @@ const MetricsRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
index
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MetricViewPage
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.METRIC_VIEW] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<MetricViewPage
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.METRIC_VIEW] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.METRIC_VIEW)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MetricViewPage
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.METRIC_VIEW] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<MetricViewPage
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.METRIC_VIEW] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</PageRoute>
|
||||
|
||||
@@ -1,54 +1,21 @@
|
||||
import Loader from "../Components/Loader/Loader";
|
||||
import MonitorGroupViewLayout from "../Pages/MonitorGroup/View/Layout";
|
||||
import ComponentProps from "../Pages/PageComponentProps";
|
||||
import PageMap from "../Utils/PageMap";
|
||||
import RouteMap, { MonitorGroupRoutePath, RouteUtil } from "../Utils/RouteMap";
|
||||
import Route from "Common/Types/API/Route";
|
||||
import React, {
|
||||
FunctionComponent,
|
||||
LazyExoticComponent,
|
||||
ReactElement,
|
||||
Suspense,
|
||||
lazy,
|
||||
} from "react";
|
||||
import React, { FunctionComponent, ReactElement } from "react";
|
||||
import { Route as PageRoute, Routes } from "react-router-dom";
|
||||
|
||||
// Pages
|
||||
const MonitorGroups: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/MonitorGroup/MonitorGroups");
|
||||
});
|
||||
const MonitorGroupView: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/MonitorGroup/View/Index");
|
||||
});
|
||||
const MonitorGroupViewDelete: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/MonitorGroup/View/Delete");
|
||||
});
|
||||
import MonitorGroups from "../Pages/MonitorGroup/MonitorGroups";
|
||||
import MonitorGroupView from "../Pages/MonitorGroup/View/Index";
|
||||
import MonitorGroupViewDelete from "../Pages/MonitorGroup/View/Delete";
|
||||
|
||||
const MonitorGroupAlerts: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/MonitorGroup/View/Alerts");
|
||||
});
|
||||
import MonitorGroupAlerts from "../Pages/MonitorGroup/View/Alerts";
|
||||
|
||||
const MonitorGroupViewMonitors: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/MonitorGroup/View/Monitors");
|
||||
});
|
||||
const MonitorGroupViewIncidents: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/MonitorGroup/View/Incidents");
|
||||
});
|
||||
const MonitorGroupViewOwners: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/MonitorGroup/View/Owners");
|
||||
});
|
||||
import MonitorGroupViewMonitors from "../Pages/MonitorGroup/View/Monitors";
|
||||
import MonitorGroupViewIncidents from "../Pages/MonitorGroup/View/Incidents";
|
||||
import MonitorGroupViewOwners from "../Pages/MonitorGroup/View/Owners";
|
||||
|
||||
const MonitorGroupRoutes: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps,
|
||||
@@ -58,12 +25,10 @@ const MonitorGroupRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
path={MonitorGroupRoutePath[PageMap.MONITOR_GROUPS] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MonitorGroups
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_GROUPS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<MonitorGroups
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_GROUPS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -74,35 +39,29 @@ const MonitorGroupRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
index
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MonitorGroupView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_GROUP_VIEW] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<MonitorGroupView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_GROUP_VIEW] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.MONITOR_GROUP_VIEW_DELETE)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MonitorGroupViewDelete
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_GROUP_VIEW_DELETE] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<MonitorGroupViewDelete
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_GROUP_VIEW_DELETE] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.MONITOR_GROUP_VIEW_ALERTS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MonitorGroupAlerts
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_GROUP_VIEW_ALERTS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<MonitorGroupAlerts
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_GROUP_VIEW_ALERTS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -111,14 +70,10 @@ const MonitorGroupRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.MONITOR_GROUP_VIEW_MONITORS,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MonitorGroupViewMonitors
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.MONITOR_GROUP_VIEW_MONITORS] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<MonitorGroupViewMonitors
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_GROUP_VIEW_MONITORS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -127,26 +82,22 @@ const MonitorGroupRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.MONITOR_GROUP_VIEW_INCIDENTS,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MonitorGroupViewIncidents
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.MONITOR_GROUP_VIEW_INCIDENTS] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<MonitorGroupViewIncidents
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.MONITOR_GROUP_VIEW_INCIDENTS] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.MONITOR_GROUP_VIEW_OWNERS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MonitorGroupViewOwners
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_GROUP_VIEW_OWNERS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<MonitorGroupViewOwners
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_GROUP_VIEW_OWNERS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</PageRoute>
|
||||
|
||||
@@ -1,160 +1,57 @@
|
||||
import Navigation from "Common/UI/Utils/Navigation";
|
||||
import Loader from "../Components/Loader/Loader";
|
||||
import MonitorLayout from "../Pages/Monitor/Layout";
|
||||
import MonitorViewLayout from "../Pages/Monitor/View/Layout";
|
||||
import ComponentProps from "../Pages/PageComponentProps";
|
||||
import PageMap from "../Utils/PageMap";
|
||||
import RouteMap, { MonitorsRoutePath, RouteUtil } from "../Utils/RouteMap";
|
||||
import Route from "Common/Types/API/Route";
|
||||
import React, {
|
||||
FunctionComponent,
|
||||
LazyExoticComponent,
|
||||
ReactElement,
|
||||
Suspense,
|
||||
lazy,
|
||||
} from "react";
|
||||
import React, { FunctionComponent, ReactElement } from "react";
|
||||
import { Route as PageRoute, Routes } from "react-router-dom";
|
||||
|
||||
// Pages
|
||||
const MonitorPage: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Monitor/Monitors");
|
||||
});
|
||||
import MonitorPage from "../Pages/Monitor/Monitors";
|
||||
|
||||
const WorkspaceConnectionSlack: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Monitor/WorkspaceConnectionSlack");
|
||||
});
|
||||
import WorkspaceConnectionSlack from "../Pages/Monitor/WorkspaceConnectionSlack";
|
||||
|
||||
const WorkspaceConnectionTeams: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Monitor/WorkspaceConnectionMicrosoftTeams");
|
||||
});
|
||||
import WorkspaceConnectionTeams from "../Pages/Monitor/WorkspaceConnectionMicrosoftTeams";
|
||||
|
||||
const MonitorViewMetrics: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Monitor/View/Metrics");
|
||||
});
|
||||
import MonitorViewMetrics from "../Pages/Monitor/View/Metrics";
|
||||
|
||||
const MonitorprobeDisconnected: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Monitor/ProbeDisconnected");
|
||||
});
|
||||
import MonitorprobeDisconnected from "../Pages/Monitor/ProbeDisconnected";
|
||||
|
||||
const MonitorProbeDisabled: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Monitor/ProbeDisabled");
|
||||
});
|
||||
import MonitorProbeDisabled from "../Pages/Monitor/ProbeDisabled";
|
||||
|
||||
const MonitorView: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Monitor/View/Index");
|
||||
});
|
||||
const MonitorViewDelete: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Monitor/View/Delete");
|
||||
});
|
||||
import MonitorView from "../Pages/Monitor/View/Index";
|
||||
import MonitorViewDelete from "../Pages/Monitor/View/Delete";
|
||||
|
||||
const MonitorViewLogs: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Monitor/View/Logs");
|
||||
});
|
||||
import MonitorViewLogs from "../Pages/Monitor/View/Logs";
|
||||
|
||||
const MonitorViewCriteria: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Monitor/View/Criteria");
|
||||
});
|
||||
const MonitorViewStatusTimeline: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Monitor/View/StatusTimeline");
|
||||
});
|
||||
const MonitorIncidents: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Monitor/View/Incidents");
|
||||
});
|
||||
import MonitorViewCriteria from "../Pages/Monitor/View/Criteria";
|
||||
import MonitorViewStatusTimeline from "../Pages/Monitor/View/StatusTimeline";
|
||||
import MonitorIncidents from "../Pages/Monitor/View/Incidents";
|
||||
|
||||
const MonitorAlerts: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Monitor/View/Alerts");
|
||||
});
|
||||
const MonitorInoperational: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Monitor/NotOperationalMonitors");
|
||||
});
|
||||
const MonitorDisabled: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Monitor/DisabledMonitors");
|
||||
});
|
||||
const MonitorViewCustomFields: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Monitor/View/CustomFields");
|
||||
});
|
||||
const MonitorViewInterval: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Monitor/View/Interval");
|
||||
});
|
||||
import MonitorAlerts from "../Pages/Monitor/View/Alerts";
|
||||
import MonitorInoperational from "../Pages/Monitor/NotOperationalMonitors";
|
||||
import MonitorDisabled from "../Pages/Monitor/DisabledMonitors";
|
||||
import MonitorViewCustomFields from "../Pages/Monitor/View/CustomFields";
|
||||
import MonitorViewInterval from "../Pages/Monitor/View/Interval";
|
||||
|
||||
const MonitorViewDocumentation: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Monitor/View/Documentation");
|
||||
});
|
||||
import MonitorViewDocumentation from "../Pages/Monitor/View/Documentation";
|
||||
|
||||
const MonitorViewProbes: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Monitor/View/Probes");
|
||||
});
|
||||
const MonitorViewOwner: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Monitor/View/Owners");
|
||||
});
|
||||
const MonitorViewSettings: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Monitor/View/Settings");
|
||||
});
|
||||
import MonitorViewProbes from "../Pages/Monitor/View/Probes";
|
||||
import MonitorViewOwner from "../Pages/Monitor/View/Owners";
|
||||
import MonitorViewSettings from "../Pages/Monitor/View/Settings";
|
||||
|
||||
const MonitorViewNotificationLogs: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Monitor/View/NotificationLogs");
|
||||
});
|
||||
import MonitorViewNotificationLogs from "../Pages/Monitor/View/NotificationLogs";
|
||||
|
||||
const MonitorCreate: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Monitor/Create");
|
||||
});
|
||||
import MonitorCreate from "../Pages/Monitor/Create";
|
||||
|
||||
// Settings Pages
|
||||
const MonitorSettingsStatus: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Monitor/Settings/MonitorStatus");
|
||||
});
|
||||
import MonitorSettingsStatus from "../Pages/Monitor/Settings/MonitorStatus";
|
||||
|
||||
const MonitorSettingsCustomFields: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Monitor/Settings/MonitorCustomFields");
|
||||
});
|
||||
import MonitorSettingsCustomFields from "../Pages/Monitor/Settings/MonitorCustomFields";
|
||||
|
||||
const MonitorSettingsSecrets: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Monitor/Settings/MonitorSecrets");
|
||||
});
|
||||
import MonitorSettingsSecrets from "../Pages/Monitor/Settings/MonitorSecrets";
|
||||
|
||||
const MonitorRoutes: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps,
|
||||
@@ -174,61 +71,49 @@ const MonitorRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
index
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MonitorPage
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITORS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<MonitorPage
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITORS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
path={MonitorsRoutePath[PageMap.MONITORS_DISABLED] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MonitorDisabled
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITORS_DISABLED] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<MonitorDisabled
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITORS_DISABLED] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={MonitorsRoutePath[PageMap.MONITORS_PROBE_DISCONNECTED] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MonitorprobeDisconnected
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.MONITORS_PROBE_DISCONNECTED] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<MonitorprobeDisconnected
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITORS_PROBE_DISCONNECTED] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={MonitorsRoutePath[PageMap.MONITORS_PROBE_DISABLED] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MonitorProbeDisabled
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITORS_PROBE_DISABLED] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<MonitorProbeDisabled
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITORS_PROBE_DISABLED] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={MonitorsRoutePath[PageMap.MONITORS_INOPERATIONAL] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MonitorInoperational
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITORS_INOPERATIONAL] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<MonitorInoperational
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITORS_INOPERATIONAL] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -237,14 +122,12 @@ const MonitorRoutes: FunctionComponent<ComponentProps> = (
|
||||
MonitorsRoutePath[PageMap.MONITORS_WORKSPACE_CONNECTION_SLACK] || ""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<WorkspaceConnectionSlack
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.MONITORS_WORKSPACE_CONNECTION_SLACK] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<WorkspaceConnectionSlack
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.MONITORS_WORKSPACE_CONNECTION_SLACK] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -255,28 +138,24 @@ const MonitorRoutes: FunctionComponent<ComponentProps> = (
|
||||
] || ""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<WorkspaceConnectionTeams
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.MONITORS_WORKSPACE_CONNECTION_MICROSOFT_TEAMS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<WorkspaceConnectionTeams
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.MONITORS_WORKSPACE_CONNECTION_MICROSOFT_TEAMS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={MonitorsRoutePath[PageMap.MONITOR_CREATE] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MonitorCreate
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_CREATE] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<MonitorCreate
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_CREATE] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -284,12 +163,10 @@ const MonitorRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
path={MonitorsRoutePath[PageMap.MONITORS_SETTINGS] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MonitorSettingsStatus
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITORS_SETTINGS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<MonitorSettingsStatus
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITORS_SETTINGS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -298,26 +175,22 @@ const MonitorRoutes: FunctionComponent<ComponentProps> = (
|
||||
MonitorsRoutePath[PageMap.MONITORS_SETTINGS_CUSTOM_FIELDS] || ""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MonitorSettingsCustomFields
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.MONITORS_SETTINGS_CUSTOM_FIELDS] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<MonitorSettingsCustomFields
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.MONITORS_SETTINGS_CUSTOM_FIELDS] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={MonitorsRoutePath[PageMap.MONITORS_SETTINGS_SECRETS] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MonitorSettingsSecrets
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITORS_SETTINGS_SECRETS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<MonitorSettingsSecrets
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITORS_SETTINGS_SECRETS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</PageRoute>
|
||||
@@ -329,83 +202,67 @@ const MonitorRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
index
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MonitorView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_VIEW] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<MonitorView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_VIEW] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.MONITOR_VIEW_SETTINGS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MonitorViewSettings
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_VIEW_SETTINGS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<MonitorViewSettings
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_VIEW_SETTINGS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.MONITOR_VIEW_OWNERS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MonitorViewOwner
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_VIEW_OWNERS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<MonitorViewOwner
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_VIEW_OWNERS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.MONITOR_VIEW_CRITERIA)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MonitorViewCriteria
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_VIEW_CRITERIA] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<MonitorViewCriteria
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_VIEW_CRITERIA] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.MONITOR_VIEW_METRICS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MonitorViewMetrics
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_VIEW_METRICS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<MonitorViewMetrics
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_VIEW_METRICS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.MONITOR_VIEW_INTERVAL)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MonitorViewInterval
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_VIEW_INTERVAL] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<MonitorViewInterval
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_VIEW_INTERVAL] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.MONITOR_VIEW_DOCUMENTATION)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MonitorViewDocumentation
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.MONITOR_VIEW_DOCUMENTATION] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<MonitorViewDocumentation
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_VIEW_DOCUMENTATION] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -414,88 +271,72 @@ const MonitorRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.MONITOR_VIEW_STATUS_TIMELINE,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MonitorViewStatusTimeline
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.MONITOR_VIEW_STATUS_TIMELINE] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<MonitorViewStatusTimeline
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.MONITOR_VIEW_STATUS_TIMELINE] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.MONITOR_VIEW_INCIDENTS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MonitorIncidents
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_VIEW_INCIDENTS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<MonitorIncidents
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_VIEW_INCIDENTS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.MONITOR_VIEW_ALERTS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MonitorAlerts
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_VIEW_ALERTS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<MonitorAlerts
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_VIEW_ALERTS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.MONITOR_VIEW_DELETE)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MonitorViewDelete
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_VIEW_DELETE] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<MonitorViewDelete
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_VIEW_DELETE] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.MONITOR_VIEW_CUSTOM_FIELDS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MonitorViewCustomFields
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.MONITOR_VIEW_CUSTOM_FIELDS] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<MonitorViewCustomFields
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_VIEW_CUSTOM_FIELDS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.MONITOR_VIEW_PROBES)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MonitorViewProbes
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_VIEW_PROBES] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<MonitorViewProbes
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_VIEW_PROBES] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.MONITOR_VIEW_LOGS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MonitorViewLogs
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_VIEW_LOGS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<MonitorViewLogs
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITOR_VIEW_LOGS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -504,14 +345,12 @@ const MonitorRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.MONITOR_VIEW_NOTIFICATION_LOGS,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<MonitorViewNotificationLogs
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.MONITOR_VIEW_NOTIFICATION_LOGS] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<MonitorViewNotificationLogs
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.MONITOR_VIEW_NOTIFICATION_LOGS] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</PageRoute>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import Loader from "../Components/Loader/Loader";
|
||||
import OnCallDutyLayout from "../Pages/OnCallDuty/Layout";
|
||||
import OnCallDutyPolicyViewLayout from "../Pages/OnCallDuty/OnCallDutyPolicy/Layout";
|
||||
import OnCallDutyScheduleViewLayout from "../Pages/OnCallDuty/OnCallDutySchedule/Layout";
|
||||
@@ -6,201 +5,67 @@ import ComponentProps from "../Pages/PageComponentProps";
|
||||
import PageMap from "../Utils/PageMap";
|
||||
import RouteMap, { OnCallDutyRoutePath, RouteUtil } from "../Utils/RouteMap";
|
||||
import Route from "Common/Types/API/Route";
|
||||
import React, {
|
||||
FunctionComponent,
|
||||
LazyExoticComponent,
|
||||
ReactElement,
|
||||
Suspense,
|
||||
lazy,
|
||||
} from "react";
|
||||
import React, { FunctionComponent, ReactElement } from "react";
|
||||
import { Route as PageRoute, Routes } from "react-router-dom";
|
||||
|
||||
// Polcies
|
||||
const OnCallDutyPoliciesPage: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/OnCallDutyPolicies");
|
||||
});
|
||||
const OnCallDutyExecutionLogs: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/OnCallDutyExecutionLogs");
|
||||
});
|
||||
import OnCallDutyPoliciesPage from "../Pages/OnCallDuty/OnCallDutyPolicies";
|
||||
import OnCallDutyExecutionLogs from "../Pages/OnCallDuty/OnCallDutyExecutionLogs";
|
||||
|
||||
const OnCallDutyUserOverrides: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/UserOverrides");
|
||||
});
|
||||
import OnCallDutyUserOverrides from "../Pages/OnCallDuty/UserOverrides";
|
||||
|
||||
const OnCallDutyPolicyViewUserOverrides: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/OnCallDutyPolicy/UserOverrides");
|
||||
});
|
||||
const OnCallDutyPolicyExecutionLogTimeline: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/OnCallDutyExecutionLogView");
|
||||
});
|
||||
const OnCallDutyPolicyView: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/OnCallDutyPolicy/Index");
|
||||
});
|
||||
const OnCallDutyPolicyViewOwners: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/OnCallDutyPolicy/Owners");
|
||||
});
|
||||
import OnCallDutyPolicyViewUserOverrides from "../Pages/OnCallDuty/OnCallDutyPolicy/UserOverrides";
|
||||
import OnCallDutyPolicyExecutionLogTimeline from "../Pages/OnCallDuty/OnCallDutyExecutionLogView";
|
||||
import OnCallDutyPolicyView from "../Pages/OnCallDuty/OnCallDutyPolicy/Index";
|
||||
import OnCallDutyPolicyViewOwners from "../Pages/OnCallDuty/OnCallDutyPolicy/Owners";
|
||||
|
||||
const OnCallDutyPolicyViewDelete: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/OnCallDutyPolicy/Delete");
|
||||
});
|
||||
const OnCallDutyPolicyViewLogs: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/OnCallDutyPolicy/ExecutionLogs");
|
||||
});
|
||||
const OnCallDutyPolicyViewLogsView: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/OnCallDutyPolicy/ExecutionLogView");
|
||||
});
|
||||
import OnCallDutyPolicyViewDelete from "../Pages/OnCallDuty/OnCallDutyPolicy/Delete";
|
||||
import OnCallDutyPolicyViewLogs from "../Pages/OnCallDuty/OnCallDutyPolicy/ExecutionLogs";
|
||||
import OnCallDutyPolicyViewLogsView from "../Pages/OnCallDuty/OnCallDutyPolicy/ExecutionLogView";
|
||||
|
||||
const OnCallDutyPolicyViewNotificationLogs: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/OnCallDutyPolicy/NotificationLogs");
|
||||
});
|
||||
const OnCallDutyPolicyViewEscalation: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/OnCallDutyPolicy/Escalation");
|
||||
});
|
||||
const OnCallDutyPolicyViewCustomFields: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/OnCallDutyPolicy/CustomFields");
|
||||
});
|
||||
import OnCallDutyPolicyViewNotificationLogs from "../Pages/OnCallDuty/OnCallDutyPolicy/NotificationLogs";
|
||||
import OnCallDutyPolicyViewEscalation from "../Pages/OnCallDuty/OnCallDutyPolicy/Escalation";
|
||||
import OnCallDutyPolicyViewCustomFields from "../Pages/OnCallDuty/OnCallDutyPolicy/CustomFields";
|
||||
|
||||
// Schedules
|
||||
const OnCallDutySchedules: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/OnCallDutySchedules");
|
||||
});
|
||||
const OnCallDutyScheduleView: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/OnCallDutySchedule/Index");
|
||||
});
|
||||
const OnCallDutyScheduleViewDelete: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/OnCallDutySchedule/Delete");
|
||||
});
|
||||
const OnCallDutyScheduleViewLayers: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/OnCallDutySchedule/Layers");
|
||||
});
|
||||
import OnCallDutySchedules from "../Pages/OnCallDuty/OnCallDutySchedules";
|
||||
import OnCallDutyScheduleView from "../Pages/OnCallDuty/OnCallDutySchedule/Index";
|
||||
import OnCallDutyScheduleViewDelete from "../Pages/OnCallDuty/OnCallDutySchedule/Delete";
|
||||
import OnCallDutyScheduleViewLayers from "../Pages/OnCallDuty/OnCallDutySchedule/Layers";
|
||||
|
||||
const OnCallDutyScheduleViewNotificationLogs: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/OnCallDutySchedule/NotificationLogs");
|
||||
});
|
||||
const OnCallDutyScheduleViewSettings: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/OnCallDutySchedule/Settings");
|
||||
});
|
||||
import OnCallDutyScheduleViewNotificationLogs from "../Pages/OnCallDuty/OnCallDutySchedule/NotificationLogs";
|
||||
import OnCallDutyScheduleViewSettings from "../Pages/OnCallDuty/OnCallDutySchedule/Settings";
|
||||
|
||||
// slack
|
||||
const WorkspaceConnectionSlack: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/WorkspaceConnectionSlack");
|
||||
});
|
||||
import WorkspaceConnectionSlack from "../Pages/OnCallDuty/WorkspaceConnectionSlack";
|
||||
|
||||
// Microsoft Teams
|
||||
const WorkspaceConnectionTeams: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/WorkspaceConnectionMicrosoftTeams");
|
||||
});
|
||||
import WorkspaceConnectionTeams from "../Pages/OnCallDuty/WorkspaceConnectionMicrosoftTeams";
|
||||
|
||||
// User Time Logs
|
||||
const OnCallDutyUserTimeLogs: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/OnCallDutyUserTimeLogs");
|
||||
});
|
||||
import OnCallDutyUserTimeLogs from "../Pages/OnCallDuty/OnCallDutyUserTimeLogs";
|
||||
|
||||
// Settings Pages
|
||||
const OnCallDutySettingsCustomFields: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/Settings/OnCallDutyPolicyCustomFields");
|
||||
});
|
||||
import OnCallDutySettingsCustomFields from "../Pages/OnCallDuty/Settings/OnCallDutyPolicyCustomFields";
|
||||
|
||||
// Incoming Call Policies
|
||||
const IncomingCallPoliciesPage: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/IncomingCallPolicies");
|
||||
});
|
||||
import IncomingCallPoliciesPage from "../Pages/OnCallDuty/IncomingCallPolicies";
|
||||
|
||||
const IncomingCallPolicyViewLayout: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/IncomingCallPolicy/Layout");
|
||||
});
|
||||
import IncomingCallPolicyViewLayout from "../Pages/OnCallDuty/IncomingCallPolicy/Layout";
|
||||
|
||||
const IncomingCallPolicyView: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/IncomingCallPolicy/Index");
|
||||
});
|
||||
import IncomingCallPolicyView from "../Pages/OnCallDuty/IncomingCallPolicy/Index";
|
||||
|
||||
const IncomingCallPolicyViewEscalation: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/IncomingCallPolicy/Escalation");
|
||||
});
|
||||
import IncomingCallPolicyViewEscalation from "../Pages/OnCallDuty/IncomingCallPolicy/Escalation";
|
||||
|
||||
const IncomingCallPolicyViewLogs: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/IncomingCallPolicy/Logs");
|
||||
});
|
||||
import IncomingCallPolicyViewLogs from "../Pages/OnCallDuty/IncomingCallPolicy/Logs";
|
||||
|
||||
const IncomingCallPolicyViewLogView: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/IncomingCallPolicy/LogView");
|
||||
});
|
||||
import IncomingCallPolicyViewLogView from "../Pages/OnCallDuty/IncomingCallPolicy/LogView";
|
||||
|
||||
const IncomingCallPolicyViewDelete: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/IncomingCallPolicy/Delete");
|
||||
});
|
||||
import IncomingCallPolicyViewDelete from "../Pages/OnCallDuty/IncomingCallPolicy/Delete";
|
||||
|
||||
const IncomingCallPolicyViewSettings: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/IncomingCallPolicy/Settings");
|
||||
});
|
||||
import IncomingCallPolicyViewSettings from "../Pages/OnCallDuty/IncomingCallPolicy/Settings";
|
||||
|
||||
const IncomingCallPolicyViewDocs: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/OnCallDuty/IncomingCallPolicy/Docs");
|
||||
});
|
||||
import IncomingCallPolicyViewDocs from "../Pages/OnCallDuty/IncomingCallPolicy/Docs";
|
||||
|
||||
const OnCallDutyRoutes: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps,
|
||||
@@ -211,12 +76,10 @@ const OnCallDutyRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
path={OnCallDutyRoutePath[PageMap.ON_CALL_DUTY] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<OnCallDutyPoliciesPage
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ON_CALL_DUTY] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<OnCallDutyPoliciesPage
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ON_CALL_DUTY] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -227,16 +90,14 @@ const OnCallDutyRoutes: FunctionComponent<ComponentProps> = (
|
||||
] || ""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<WorkspaceConnectionSlack
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ON_CALL_DUTY_WORKSPACE_CONNECTION_SLACK
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<WorkspaceConnectionSlack
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ON_CALL_DUTY_WORKSPACE_CONNECTION_SLACK
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -247,41 +108,33 @@ const OnCallDutyRoutes: FunctionComponent<ComponentProps> = (
|
||||
] || ""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<WorkspaceConnectionTeams
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ON_CALL_DUTY_WORKSPACE_CONNECTION_MICROSOFT_TEAMS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<WorkspaceConnectionTeams
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ON_CALL_DUTY_WORKSPACE_CONNECTION_MICROSOFT_TEAMS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={OnCallDutyRoutePath[PageMap.ON_CALL_DUTY_POLICIES] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<OnCallDutyPoliciesPage
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ON_CALL_DUTY_POLICIES] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<OnCallDutyPoliciesPage
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ON_CALL_DUTY_POLICIES] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
path={OnCallDutyRoutePath[PageMap.ON_CALL_DUTY_EXECUTION_LOGS] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<OnCallDutyExecutionLogs
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ON_CALL_DUTY_EXECUTION_LOGS] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<OnCallDutyExecutionLogs
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ON_CALL_DUTY_EXECUTION_LOGS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -291,14 +144,12 @@ const OnCallDutyRoutes: FunctionComponent<ComponentProps> = (
|
||||
""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<OnCallDutyUserOverrides
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ON_CALL_DUTY_POLICY_USER_OVERRIDES] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<OnCallDutyUserOverrides
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ON_CALL_DUTY_POLICY_USER_OVERRIDES] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -308,42 +159,32 @@ const OnCallDutyRoutes: FunctionComponent<ComponentProps> = (
|
||||
""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<OnCallDutyPolicyExecutionLogTimeline
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ON_CALL_DUTY_EXECUTION_LOGS_TIMELINE
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<OnCallDutyPolicyExecutionLogTimeline
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ON_CALL_DUTY_EXECUTION_LOGS_TIMELINE] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={OnCallDutyRoutePath[PageMap.ON_CALL_DUTY_SCHEDULES] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<OnCallDutySchedules
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ON_CALL_DUTY_SCHEDULES] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<OnCallDutySchedules
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ON_CALL_DUTY_SCHEDULES] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={OnCallDutyRoutePath[PageMap.ON_CALLDUTY_USER_TIME_LOGS] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<OnCallDutyUserTimeLogs
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ON_CALLDUTY_USER_TIME_LOGS] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<OnCallDutyUserTimeLogs
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ON_CALLDUTY_USER_TIME_LOGS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -354,14 +195,12 @@ const OnCallDutyRoutes: FunctionComponent<ComponentProps> = (
|
||||
""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<OnCallDutySettingsCustomFields
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ON_CALL_DUTY_SETTINGS_CUSTOM_FIELDS] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<OnCallDutySettingsCustomFields
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ON_CALL_DUTY_SETTINGS_CUSTOM_FIELDS] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -372,14 +211,12 @@ const OnCallDutyRoutes: FunctionComponent<ComponentProps> = (
|
||||
""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<IncomingCallPoliciesPage
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ON_CALL_DUTY_INCOMING_CALL_POLICIES] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<IncomingCallPoliciesPage
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ON_CALL_DUTY_INCOMING_CALL_POLICIES] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</PageRoute>
|
||||
@@ -391,12 +228,10 @@ const OnCallDutyRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
index
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<OnCallDutyPolicyView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ON_CALL_DUTY_POLICY_VIEW] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<OnCallDutyPolicyView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ON_CALL_DUTY_POLICY_VIEW] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -405,14 +240,12 @@ const OnCallDutyRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.ON_CALL_DUTY_POLICY_VIEW_DELETE,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<OnCallDutyPolicyViewDelete
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ON_CALL_DUTY_POLICY_VIEW_DELETE] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<OnCallDutyPolicyViewDelete
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ON_CALL_DUTY_POLICY_VIEW_DELETE] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -421,14 +254,12 @@ const OnCallDutyRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.ON_CALL_DUTY_POLICY_VIEW_OWNERS,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<OnCallDutyPolicyViewOwners
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ON_CALL_DUTY_POLICY_VIEW_OWNERS] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<OnCallDutyPolicyViewOwners
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ON_CALL_DUTY_POLICY_VIEW_OWNERS] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -437,14 +268,12 @@ const OnCallDutyRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.ON_CALL_DUTY_POLICY_VIEW_ESCALATION,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<OnCallDutyPolicyViewEscalation
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ON_CALL_DUTY_POLICY_VIEW_ESCALATION] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<OnCallDutyPolicyViewEscalation
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ON_CALL_DUTY_POLICY_VIEW_ESCALATION] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -453,16 +282,14 @@ const OnCallDutyRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.ON_CALL_DUTY_POLICY_VIEW_USER_OVERRIDES,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<OnCallDutyPolicyViewUserOverrides
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ON_CALL_DUTY_POLICY_VIEW_USER_OVERRIDES
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<OnCallDutyPolicyViewUserOverrides
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ON_CALL_DUTY_POLICY_VIEW_USER_OVERRIDES
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -471,16 +298,14 @@ const OnCallDutyRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.ON_CALL_DUTY_POLICY_VIEW_CUSTOM_FIELDS,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<OnCallDutyPolicyViewCustomFields
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ON_CALL_DUTY_POLICY_VIEW_CUSTOM_FIELDS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<OnCallDutyPolicyViewCustomFields
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ON_CALL_DUTY_POLICY_VIEW_CUSTOM_FIELDS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -489,16 +314,14 @@ const OnCallDutyRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.ON_CALL_DUTY_POLICY_VIEW_EXECUTION_LOGS,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<OnCallDutyPolicyViewLogs
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ON_CALL_DUTY_POLICY_VIEW_EXECUTION_LOGS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<OnCallDutyPolicyViewLogs
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ON_CALL_DUTY_POLICY_VIEW_EXECUTION_LOGS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -508,16 +331,14 @@ const OnCallDutyRoutes: FunctionComponent<ComponentProps> = (
|
||||
2,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<OnCallDutyPolicyViewLogsView
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ON_CALL_DUTY_POLICY_VIEW_EXECUTION_LOG_VIEW
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<OnCallDutyPolicyViewLogsView
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ON_CALL_DUTY_POLICY_VIEW_EXECUTION_LOG_VIEW
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -526,16 +347,14 @@ const OnCallDutyRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.ON_CALL_DUTY_POLICY_VIEW_NOTIFICATION_LOGS,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<OnCallDutyPolicyViewNotificationLogs
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ON_CALL_DUTY_POLICY_VIEW_NOTIFICATION_LOGS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<OnCallDutyPolicyViewNotificationLogs
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ON_CALL_DUTY_POLICY_VIEW_NOTIFICATION_LOGS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</PageRoute>
|
||||
@@ -546,14 +365,10 @@ const OnCallDutyRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
index
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<OnCallDutyScheduleView
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ON_CALL_DUTY_SCHEDULE_VIEW] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<OnCallDutyScheduleView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.ON_CALL_DUTY_SCHEDULE_VIEW] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -562,14 +377,12 @@ const OnCallDutyRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.ON_CALL_DUTY_SCHEDULE_VIEW_DELETE,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<OnCallDutyScheduleViewDelete
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ON_CALL_DUTY_SCHEDULE_VIEW_DELETE] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<OnCallDutyScheduleViewDelete
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ON_CALL_DUTY_SCHEDULE_VIEW_DELETE] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -578,14 +391,12 @@ const OnCallDutyRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.ON_CALL_DUTY_SCHEDULE_VIEW_LAYERS,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<OnCallDutyScheduleViewLayers
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ON_CALL_DUTY_SCHEDULE_VIEW_LAYERS] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<OnCallDutyScheduleViewLayers
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ON_CALL_DUTY_SCHEDULE_VIEW_LAYERS] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -594,16 +405,14 @@ const OnCallDutyRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.ON_CALL_DUTY_SCHEDULE_VIEW_NOTIFICATION_LOGS,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<OnCallDutyScheduleViewNotificationLogs
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ON_CALL_DUTY_SCHEDULE_VIEW_NOTIFICATION_LOGS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<OnCallDutyScheduleViewNotificationLogs
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ON_CALL_DUTY_SCHEDULE_VIEW_NOTIFICATION_LOGS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -612,14 +421,12 @@ const OnCallDutyRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.ON_CALL_DUTY_SCHEDULE_VIEW_SETTINGS,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<OnCallDutyScheduleViewSettings
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ON_CALL_DUTY_SCHEDULE_VIEW_SETTINGS] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<OnCallDutyScheduleViewSettings
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ON_CALL_DUTY_SCHEDULE_VIEW_SETTINGS] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</PageRoute>
|
||||
@@ -630,25 +437,19 @@ const OnCallDutyRoutes: FunctionComponent<ComponentProps> = (
|
||||
OnCallDutyRoutePath[PageMap.ON_CALL_DUTY_INCOMING_CALL_POLICY_VIEW] ||
|
||||
""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<IncomingCallPolicyViewLayout {...props} />
|
||||
</Suspense>
|
||||
}
|
||||
element={<IncomingCallPolicyViewLayout {...props} />}
|
||||
>
|
||||
<PageRoute
|
||||
index
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<IncomingCallPolicyView
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ON_CALL_DUTY_INCOMING_CALL_POLICY_VIEW
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<IncomingCallPolicyView
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ON_CALL_DUTY_INCOMING_CALL_POLICY_VIEW
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -657,16 +458,14 @@ const OnCallDutyRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.ON_CALL_DUTY_INCOMING_CALL_POLICY_VIEW_ESCALATION,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<IncomingCallPolicyViewEscalation
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ON_CALL_DUTY_INCOMING_CALL_POLICY_VIEW_ESCALATION
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<IncomingCallPolicyViewEscalation
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ON_CALL_DUTY_INCOMING_CALL_POLICY_VIEW_ESCALATION
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -675,16 +474,14 @@ const OnCallDutyRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.ON_CALL_DUTY_INCOMING_CALL_POLICY_VIEW_LOGS,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<IncomingCallPolicyViewLogs
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ON_CALL_DUTY_INCOMING_CALL_POLICY_VIEW_LOGS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<IncomingCallPolicyViewLogs
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ON_CALL_DUTY_INCOMING_CALL_POLICY_VIEW_LOGS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -694,16 +491,14 @@ const OnCallDutyRoutes: FunctionComponent<ComponentProps> = (
|
||||
2,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<IncomingCallPolicyViewLogView
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ON_CALL_DUTY_INCOMING_CALL_POLICY_VIEW_LOG_VIEW
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<IncomingCallPolicyViewLogView
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ON_CALL_DUTY_INCOMING_CALL_POLICY_VIEW_LOG_VIEW
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -712,16 +507,14 @@ const OnCallDutyRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.ON_CALL_DUTY_INCOMING_CALL_POLICY_VIEW_SETTINGS,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<IncomingCallPolicyViewSettings
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ON_CALL_DUTY_INCOMING_CALL_POLICY_VIEW_SETTINGS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<IncomingCallPolicyViewSettings
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ON_CALL_DUTY_INCOMING_CALL_POLICY_VIEW_SETTINGS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -730,16 +523,14 @@ const OnCallDutyRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.ON_CALL_DUTY_INCOMING_CALL_POLICY_VIEW_DELETE,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<IncomingCallPolicyViewDelete
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ON_CALL_DUTY_INCOMING_CALL_POLICY_VIEW_DELETE
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<IncomingCallPolicyViewDelete
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ON_CALL_DUTY_INCOMING_CALL_POLICY_VIEW_DELETE
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -748,16 +539,14 @@ const OnCallDutyRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.ON_CALL_DUTY_INCOMING_CALL_POLICY_VIEW_DOCS,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<IncomingCallPolicyViewDocs
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ON_CALL_DUTY_INCOMING_CALL_POLICY_VIEW_DOCS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<IncomingCallPolicyViewDocs
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ON_CALL_DUTY_INCOMING_CALL_POLICY_VIEW_DOCS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</PageRoute>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import Navigation from "Common/UI/Utils/Navigation";
|
||||
import Loader from "../Components/Loader/Loader";
|
||||
import ComponentProps from "../Pages/PageComponentProps";
|
||||
import ScheduledMaintenancesLaoyut from "../Pages/ScheduledMaintenanceEvents/Layout";
|
||||
import ScheduledMaintenanceViewLayout from "../Pages/ScheduledMaintenanceEvents/View/Layout";
|
||||
@@ -9,167 +8,51 @@ import RouteMap, {
|
||||
ScheduledMaintenanceEventsRoutePath,
|
||||
} from "../Utils/RouteMap";
|
||||
import Route from "Common/Types/API/Route";
|
||||
import React, {
|
||||
FunctionComponent,
|
||||
LazyExoticComponent,
|
||||
ReactElement,
|
||||
Suspense,
|
||||
lazy,
|
||||
} from "react";
|
||||
import React, { FunctionComponent, ReactElement } from "react";
|
||||
import { Route as PageRoute, Routes } from "react-router-dom";
|
||||
|
||||
// Pages
|
||||
|
||||
const ScheduledMaintenanceEvents: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import(
|
||||
"../Pages/ScheduledMaintenanceEvents/ScheduledMaintenanceEvents"
|
||||
);
|
||||
});
|
||||
const ScheduledMaintenanceEventView: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/ScheduledMaintenanceEvents/View/Index");
|
||||
});
|
||||
const ScheduledMaintenanceEventViewDelete: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/ScheduledMaintenanceEvents/View/Delete");
|
||||
});
|
||||
import ScheduledMaintenanceEvents from "../Pages/ScheduledMaintenanceEvents/ScheduledMaintenanceEvents";
|
||||
import ScheduledMaintenanceEventView from "../Pages/ScheduledMaintenanceEvents/View/Index";
|
||||
import ScheduledMaintenanceEventViewDelete from "../Pages/ScheduledMaintenanceEvents/View/Delete";
|
||||
|
||||
const ScheduledMaintenanceEventsWorkspaceConnectionMicrosoftTeams: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import(
|
||||
"../Pages/ScheduledMaintenanceEvents/WorkspaceConnectionMicrosoftTeams"
|
||||
);
|
||||
});
|
||||
import ScheduledMaintenanceEventsWorkspaceConnectionMicrosoftTeams from "../Pages/ScheduledMaintenanceEvents/WorkspaceConnectionMicrosoftTeams";
|
||||
|
||||
const ScheduledMaintenanceEventViewOwner: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/ScheduledMaintenanceEvents/View/Owners");
|
||||
});
|
||||
import ScheduledMaintenanceEventViewOwner from "../Pages/ScheduledMaintenanceEvents/View/Owners";
|
||||
|
||||
const ScheduledMaintenanceEventsWorkspaceConnectionSlack: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/ScheduledMaintenanceEvents/WorkspaceConnectionSlack");
|
||||
});
|
||||
import ScheduledMaintenanceEventsWorkspaceConnectionSlack from "../Pages/ScheduledMaintenanceEvents/WorkspaceConnectionSlack";
|
||||
|
||||
const ScheduledMaintenanceEventsViewSettings: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/ScheduledMaintenanceEvents/View/Settings");
|
||||
});
|
||||
import ScheduledMaintenanceEventsViewSettings from "../Pages/ScheduledMaintenanceEvents/View/Settings";
|
||||
|
||||
const ScheduledMaintenanceEventViewStateTimeline: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/ScheduledMaintenanceEvents/View/StateTimeline");
|
||||
});
|
||||
const ScheduledMaintenanceEventInternalNote: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/ScheduledMaintenanceEvents/View/InternalNote");
|
||||
});
|
||||
const ScheduledMaintenanceEventPublicNote: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/ScheduledMaintenanceEvents/View/PublicNote");
|
||||
});
|
||||
const OngoingScheduledMaintenanceEvents: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/ScheduledMaintenanceEvents/Ongoing");
|
||||
});
|
||||
const ScheduledMaintenanceEventsViewCustomFields: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/ScheduledMaintenanceEvents/View/CustomFields");
|
||||
});
|
||||
import ScheduledMaintenanceEventViewStateTimeline from "../Pages/ScheduledMaintenanceEvents/View/StateTimeline";
|
||||
import ScheduledMaintenanceEventInternalNote from "../Pages/ScheduledMaintenanceEvents/View/InternalNote";
|
||||
import ScheduledMaintenanceEventPublicNote from "../Pages/ScheduledMaintenanceEvents/View/PublicNote";
|
||||
import OngoingScheduledMaintenanceEvents from "../Pages/ScheduledMaintenanceEvents/Ongoing";
|
||||
import ScheduledMaintenanceEventsViewCustomFields from "../Pages/ScheduledMaintenanceEvents/View/CustomFields";
|
||||
|
||||
const ScheduledMaintenanceEventViewNotificationLogs: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/ScheduledMaintenanceEvents/View/NotificationLogs");
|
||||
});
|
||||
import ScheduledMaintenanceEventViewNotificationLogs from "../Pages/ScheduledMaintenanceEvents/View/NotificationLogs";
|
||||
|
||||
const ScheduledMaintenanceEventViewAILogs: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/ScheduledMaintenanceEvents/View/AILogs");
|
||||
});
|
||||
import ScheduledMaintenanceEventViewAILogs from "../Pages/ScheduledMaintenanceEvents/View/AILogs";
|
||||
|
||||
const ScheduledMaintenanceEventViewDescription: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/ScheduledMaintenanceEvents/View/Description");
|
||||
});
|
||||
import ScheduledMaintenanceEventViewDescription from "../Pages/ScheduledMaintenanceEvents/View/Description";
|
||||
|
||||
const ScheduledMaintenanceEventCreate: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/ScheduledMaintenanceEvents/Create");
|
||||
});
|
||||
import ScheduledMaintenanceEventCreate from "../Pages/ScheduledMaintenanceEvents/Create";
|
||||
|
||||
// Settings Pages
|
||||
const ScheduledMaintenanceSettingsState: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import(
|
||||
"../Pages/ScheduledMaintenanceEvents/Settings/ScheduledMaintenanceState"
|
||||
);
|
||||
});
|
||||
import ScheduledMaintenanceSettingsState from "../Pages/ScheduledMaintenanceEvents/Settings/ScheduledMaintenanceState";
|
||||
|
||||
const ScheduledMaintenanceSettingsTemplates: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import(
|
||||
"../Pages/ScheduledMaintenanceEvents/Settings/ScheduledMaintenanceTemplates"
|
||||
);
|
||||
});
|
||||
import ScheduledMaintenanceSettingsTemplates from "../Pages/ScheduledMaintenanceEvents/Settings/ScheduledMaintenanceTemplates";
|
||||
|
||||
const ScheduledMaintenanceSettingsTemplatesView: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import(
|
||||
"../Pages/ScheduledMaintenanceEvents/Settings/ScheduledMaintenanceTemplateView"
|
||||
);
|
||||
});
|
||||
import ScheduledMaintenanceSettingsTemplatesView from "../Pages/ScheduledMaintenanceEvents/Settings/ScheduledMaintenanceTemplateView";
|
||||
|
||||
const ScheduledMaintenanceSettingsNoteTemplates: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import(
|
||||
"../Pages/ScheduledMaintenanceEvents/Settings/ScheduledMaintenanceNoteTemplates"
|
||||
);
|
||||
});
|
||||
import ScheduledMaintenanceSettingsNoteTemplates from "../Pages/ScheduledMaintenanceEvents/Settings/ScheduledMaintenanceNoteTemplates";
|
||||
|
||||
const ScheduledMaintenanceSettingsNoteTemplatesView: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import(
|
||||
"../Pages/ScheduledMaintenanceEvents/Settings/ScheduledMaintenanceNoteTemplateView"
|
||||
);
|
||||
});
|
||||
import ScheduledMaintenanceSettingsNoteTemplatesView from "../Pages/ScheduledMaintenanceEvents/Settings/ScheduledMaintenanceNoteTemplateView";
|
||||
|
||||
const ScheduledMaintenanceSettingsCustomFields: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import(
|
||||
"../Pages/ScheduledMaintenanceEvents/Settings/ScheduledMaintenanceCusomFields"
|
||||
);
|
||||
});
|
||||
import ScheduledMaintenanceSettingsCustomFields from "../Pages/ScheduledMaintenanceEvents/Settings/ScheduledMaintenanceCusomFields";
|
||||
|
||||
const ScheduledMaintenanceSettingsMore: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import(
|
||||
"../Pages/ScheduledMaintenanceEvents/Settings/ScheduledMaintenanceMoreSettings"
|
||||
);
|
||||
});
|
||||
import ScheduledMaintenanceSettingsMore from "../Pages/ScheduledMaintenanceEvents/Settings/ScheduledMaintenanceMoreSettings";
|
||||
|
||||
const ScheduledMaintenanceEventsRoutes: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps,
|
||||
@@ -195,14 +78,12 @@ const ScheduledMaintenanceEventsRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
index
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ScheduledMaintenanceEvents
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.SCHEDULED_MAINTENANCE_EVENTS] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<ScheduledMaintenanceEvents
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.SCHEDULED_MAINTENANCE_EVENTS] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
@@ -212,16 +93,12 @@ const ScheduledMaintenanceEventsRoutes: FunctionComponent<ComponentProps> = (
|
||||
] || ""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<OngoingScheduledMaintenanceEvents
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.ONGOING_SCHEDULED_MAINTENANCE_EVENTS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<OngoingScheduledMaintenanceEvents
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.ONGOING_SCHEDULED_MAINTENANCE_EVENTS] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -232,17 +109,15 @@ const ScheduledMaintenanceEventsRoutes: FunctionComponent<ComponentProps> = (
|
||||
] || ""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ScheduledMaintenanceEventsWorkspaceConnectionSlack
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap
|
||||
.SCHEDULED_MAINTENANCE_EVENTS_WORKSPACE_CONNECTION_SLACK
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<ScheduledMaintenanceEventsWorkspaceConnectionSlack
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap
|
||||
.SCHEDULED_MAINTENANCE_EVENTS_WORKSPACE_CONNECTION_SLACK
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -254,17 +129,15 @@ const ScheduledMaintenanceEventsRoutes: FunctionComponent<ComponentProps> = (
|
||||
] || ""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ScheduledMaintenanceEventsWorkspaceConnectionMicrosoftTeams
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap
|
||||
.SCHEDULED_MAINTENANCE_EVENTS_WORKSPACE_CONNECTION_MICROSOFT_TEAMS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<ScheduledMaintenanceEventsWorkspaceConnectionMicrosoftTeams
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap
|
||||
.SCHEDULED_MAINTENANCE_EVENTS_WORKSPACE_CONNECTION_MICROSOFT_TEAMS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -275,14 +148,12 @@ const ScheduledMaintenanceEventsRoutes: FunctionComponent<ComponentProps> = (
|
||||
] || ""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ScheduledMaintenanceEventCreate
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.SCHEDULED_MAINTENANCE_EVENT_CREATE] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<ScheduledMaintenanceEventCreate
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.SCHEDULED_MAINTENANCE_EVENT_CREATE] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -294,16 +165,14 @@ const ScheduledMaintenanceEventsRoutes: FunctionComponent<ComponentProps> = (
|
||||
] || ""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ScheduledMaintenanceSettingsState
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.SCHEDULED_MAINTENANCE_EVENTS_SETTINGS_STATE
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<ScheduledMaintenanceSettingsState
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.SCHEDULED_MAINTENANCE_EVENTS_SETTINGS_STATE
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -314,16 +183,14 @@ const ScheduledMaintenanceEventsRoutes: FunctionComponent<ComponentProps> = (
|
||||
] || ""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ScheduledMaintenanceSettingsTemplates
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.SCHEDULED_MAINTENANCE_EVENTS_SETTINGS_TEMPLATES
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<ScheduledMaintenanceSettingsTemplates
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.SCHEDULED_MAINTENANCE_EVENTS_SETTINGS_TEMPLATES
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -334,16 +201,14 @@ const ScheduledMaintenanceEventsRoutes: FunctionComponent<ComponentProps> = (
|
||||
] || ""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ScheduledMaintenanceSettingsTemplatesView
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.SCHEDULED_MAINTENANCE_EVENTS_SETTINGS_TEMPLATES_VIEW
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<ScheduledMaintenanceSettingsTemplatesView
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.SCHEDULED_MAINTENANCE_EVENTS_SETTINGS_TEMPLATES_VIEW
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -354,16 +219,14 @@ const ScheduledMaintenanceEventsRoutes: FunctionComponent<ComponentProps> = (
|
||||
] || ""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ScheduledMaintenanceSettingsNoteTemplates
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.SCHEDULED_MAINTENANCE_EVENTS_SETTINGS_NOTE_TEMPLATES
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<ScheduledMaintenanceSettingsNoteTemplates
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.SCHEDULED_MAINTENANCE_EVENTS_SETTINGS_NOTE_TEMPLATES
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -374,17 +237,15 @@ const ScheduledMaintenanceEventsRoutes: FunctionComponent<ComponentProps> = (
|
||||
] || ""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ScheduledMaintenanceSettingsNoteTemplatesView
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap
|
||||
.SCHEDULED_MAINTENANCE_EVENTS_SETTINGS_NOTE_TEMPLATES_VIEW
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<ScheduledMaintenanceSettingsNoteTemplatesView
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap
|
||||
.SCHEDULED_MAINTENANCE_EVENTS_SETTINGS_NOTE_TEMPLATES_VIEW
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -395,16 +256,14 @@ const ScheduledMaintenanceEventsRoutes: FunctionComponent<ComponentProps> = (
|
||||
] || ""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ScheduledMaintenanceSettingsCustomFields
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.SCHEDULED_MAINTENANCE_EVENTS_SETTINGS_CUSTOM_FIELDS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<ScheduledMaintenanceSettingsCustomFields
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.SCHEDULED_MAINTENANCE_EVENTS_SETTINGS_CUSTOM_FIELDS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -415,16 +274,14 @@ const ScheduledMaintenanceEventsRoutes: FunctionComponent<ComponentProps> = (
|
||||
] || ""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ScheduledMaintenanceSettingsMore
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.SCHEDULED_MAINTENANCE_EVENTS_SETTINGS_MORE
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<ScheduledMaintenanceSettingsMore
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.SCHEDULED_MAINTENANCE_EVENTS_SETTINGS_MORE
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</PageRoute>
|
||||
@@ -440,14 +297,10 @@ const ScheduledMaintenanceEventsRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
index
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ScheduledMaintenanceEventView
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.SCHEDULED_MAINTENANCE_VIEW] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<ScheduledMaintenanceEventView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SCHEDULED_MAINTENANCE_VIEW] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
@@ -455,16 +308,14 @@ const ScheduledMaintenanceEventsRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.SCHEDULED_MAINTENANCE_VIEW_CUSTOM_FIELDS,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ScheduledMaintenanceEventsViewCustomFields
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.SCHEDULED_MAINTENANCE_VIEW_CUSTOM_FIELDS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<ScheduledMaintenanceEventsViewCustomFields
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.SCHEDULED_MAINTENANCE_VIEW_CUSTOM_FIELDS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
@@ -472,16 +323,14 @@ const ScheduledMaintenanceEventsRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.SCHEDULED_MAINTENANCE_VIEW_NOTIFICATION_LOGS,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ScheduledMaintenanceEventViewNotificationLogs
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.SCHEDULED_MAINTENANCE_VIEW_NOTIFICATION_LOGS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<ScheduledMaintenanceEventViewNotificationLogs
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.SCHEDULED_MAINTENANCE_VIEW_NOTIFICATION_LOGS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
@@ -489,14 +338,12 @@ const ScheduledMaintenanceEventsRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.SCHEDULED_MAINTENANCE_VIEW_AI_LOGS,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ScheduledMaintenanceEventViewAILogs
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.SCHEDULED_MAINTENANCE_VIEW_AI_LOGS] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<ScheduledMaintenanceEventViewAILogs
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.SCHEDULED_MAINTENANCE_VIEW_AI_LOGS] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
@@ -504,14 +351,12 @@ const ScheduledMaintenanceEventsRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.SCHEDULED_MAINTENANCE_VIEW_SETTINGS,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ScheduledMaintenanceEventsViewSettings
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.SCHEDULED_MAINTENANCE_VIEW_SETTINGS] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<ScheduledMaintenanceEventsViewSettings
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.SCHEDULED_MAINTENANCE_VIEW_SETTINGS] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
@@ -519,14 +364,12 @@ const ScheduledMaintenanceEventsRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.SCHEDULED_MAINTENANCE_VIEW_DELETE,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ScheduledMaintenanceEventViewDelete
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.SCHEDULED_MAINTENANCE_VIEW_DELETE] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<ScheduledMaintenanceEventViewDelete
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.SCHEDULED_MAINTENANCE_VIEW_DELETE] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -535,16 +378,14 @@ const ScheduledMaintenanceEventsRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.SCHEDULED_MAINTENANCE_VIEW_DESCRIPTION,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ScheduledMaintenanceEventViewDescription
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.SCHEDULED_MAINTENANCE_VIEW_DESCRIPTION
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<ScheduledMaintenanceEventViewDescription
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.SCHEDULED_MAINTENANCE_VIEW_DESCRIPTION
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -553,14 +394,12 @@ const ScheduledMaintenanceEventsRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.SCHEDULED_MAINTENANCE_VIEW_OWNERS,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ScheduledMaintenanceEventViewOwner
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.SCHEDULED_MAINTENANCE_VIEW_OWNERS] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<ScheduledMaintenanceEventViewOwner
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.SCHEDULED_MAINTENANCE_VIEW_OWNERS] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -569,16 +408,14 @@ const ScheduledMaintenanceEventsRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.SCHEDULED_MAINTENANCE_VIEW_STATE_TIMELINE,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ScheduledMaintenanceEventViewStateTimeline
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.SCHEDULED_MAINTENANCE_VIEW_STATE_TIMELINE
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<ScheduledMaintenanceEventViewStateTimeline
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.SCHEDULED_MAINTENANCE_VIEW_STATE_TIMELINE
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -587,14 +424,12 @@ const ScheduledMaintenanceEventsRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.SCHEDULED_MAINTENANCE_INTERNAL_NOTE,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ScheduledMaintenanceEventInternalNote
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.SCHEDULED_MAINTENANCE_INTERNAL_NOTE] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<ScheduledMaintenanceEventInternalNote
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.SCHEDULED_MAINTENANCE_INTERNAL_NOTE] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -603,14 +438,12 @@ const ScheduledMaintenanceEventsRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.SCHEDULED_MAINTENANCE_PUBLIC_NOTE,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ScheduledMaintenanceEventPublicNote
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.SCHEDULED_MAINTENANCE_PUBLIC_NOTE] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<ScheduledMaintenanceEventPublicNote
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.SCHEDULED_MAINTENANCE_PUBLIC_NOTE] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</PageRoute>
|
||||
|
||||
@@ -1,99 +1,38 @@
|
||||
import Loader from "../Components/Loader/Loader";
|
||||
import ComponentProps from "../Pages/PageComponentProps";
|
||||
import StatusPageViewLayout from "../Pages/Service/View/Layout";
|
||||
import ServiceLayout from "../Pages/Service/Layout";
|
||||
import PageMap from "../Utils/PageMap";
|
||||
import RouteMap, { RouteUtil, ServiceRoutePath } from "../Utils/RouteMap";
|
||||
import Route from "Common/Types/API/Route";
|
||||
import React, {
|
||||
FunctionComponent,
|
||||
LazyExoticComponent,
|
||||
ReactElement,
|
||||
Suspense,
|
||||
lazy,
|
||||
} from "react";
|
||||
import React, { FunctionComponent, ReactElement } from "react";
|
||||
import { Route as PageRoute, Routes } from "react-router-dom";
|
||||
|
||||
// Pages
|
||||
const Services: LazyExoticComponent<FunctionComponent<ComponentProps>> = lazy(
|
||||
() => {
|
||||
return import("../Pages/Service/Services");
|
||||
},
|
||||
);
|
||||
const ServiceDependencyGraph: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Service/DependencyGraph");
|
||||
});
|
||||
const ServiceView: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Service/View/Index");
|
||||
});
|
||||
import Services from "../Pages/Service/Services";
|
||||
import ServiceDependencyGraph from "../Pages/Service/DependencyGraph";
|
||||
import ServiceView from "../Pages/Service/View/Index";
|
||||
|
||||
const ServiceViewMonitors: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Service/View/Monitors");
|
||||
});
|
||||
import ServiceViewMonitors from "../Pages/Service/View/Monitors";
|
||||
|
||||
const ServiceViewIncidents: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Service/View/Incidents");
|
||||
});
|
||||
import ServiceViewIncidents from "../Pages/Service/View/Incidents";
|
||||
|
||||
const ServiceViewAlerts: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Service/View/Alerts");
|
||||
});
|
||||
import ServiceViewAlerts from "../Pages/Service/View/Alerts";
|
||||
|
||||
const ServiceViewLogs: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Service/View/Logs");
|
||||
});
|
||||
import ServiceViewLogs from "../Pages/Service/View/Logs";
|
||||
|
||||
const ServiceViewTraces: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Service/View/Traces");
|
||||
});
|
||||
import ServiceViewTraces from "../Pages/Service/View/Traces";
|
||||
|
||||
const ServiceViewMetrics: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Service/View/Metrics");
|
||||
});
|
||||
import ServiceViewMetrics from "../Pages/Service/View/Metrics";
|
||||
|
||||
const ServiceViewDelete: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Service/View/Delete");
|
||||
});
|
||||
import ServiceViewDelete from "../Pages/Service/View/Delete";
|
||||
|
||||
const ServiceViewSettings: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Service/View/Settings");
|
||||
});
|
||||
import ServiceViewSettings from "../Pages/Service/View/Settings";
|
||||
|
||||
const ServiceViewOwners: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Service/View/Owners");
|
||||
});
|
||||
import ServiceViewOwners from "../Pages/Service/View/Owners";
|
||||
|
||||
const ServiceViewDependencies: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Service/View/Dependencies");
|
||||
});
|
||||
import ServiceViewDependencies from "../Pages/Service/View/Dependencies";
|
||||
|
||||
const ServiceViewCodeRepositories: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Service/View/CodeRepositories");
|
||||
});
|
||||
import ServiceViewCodeRepositories from "../Pages/Service/View/CodeRepositories";
|
||||
|
||||
const ServiceRoutes: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps,
|
||||
@@ -104,23 +43,19 @@ const ServiceRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
path={ServiceRoutePath[PageMap.SERVICES] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<Services
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SERVICES] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<Services
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SERVICES] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SERVICE_DEPENDENCY_GRAPH)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ServiceDependencyGraph
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SERVICE_DEPENDENCY_GRAPH] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<ServiceDependencyGraph
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SERVICE_DEPENDENCY_GRAPH] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</PageRoute>
|
||||
@@ -132,132 +67,110 @@ const ServiceRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
index
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ServiceView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SERVICE_VIEW] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<ServiceView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SERVICE_VIEW] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SERVICE_VIEW_DELETE)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ServiceViewDelete
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SERVICE_VIEW_DELETE] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<ServiceViewDelete
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SERVICE_VIEW_DELETE] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SERVICE_VIEW_SETTINGS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ServiceViewSettings
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SERVICE_VIEW_SETTINGS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<ServiceViewSettings
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SERVICE_VIEW_SETTINGS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SERVICE_VIEW_MONITORS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ServiceViewMonitors
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SERVICE_VIEW_MONITORS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<ServiceViewMonitors
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SERVICE_VIEW_MONITORS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SERVICE_VIEW_ALERTS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ServiceViewAlerts
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SERVICE_VIEW_ALERTS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<ServiceViewAlerts
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SERVICE_VIEW_ALERTS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SERVICE_VIEW_INCIDENTS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ServiceViewIncidents
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SERVICE_VIEW_INCIDENTS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<ServiceViewIncidents
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SERVICE_VIEW_INCIDENTS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SERVICE_VIEW_LOGS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ServiceViewLogs
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SERVICE_VIEW_LOGS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<ServiceViewLogs
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SERVICE_VIEW_LOGS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SERVICE_VIEW_TRACES)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ServiceViewTraces
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SERVICE_VIEW_TRACES] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<ServiceViewTraces
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SERVICE_VIEW_TRACES] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SERVICE_VIEW_METRICS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ServiceViewMetrics
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SERVICE_VIEW_METRICS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<ServiceViewMetrics
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SERVICE_VIEW_METRICS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SERVICE_VIEW_OWNERS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ServiceViewOwners
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SERVICE_VIEW_OWNERS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<ServiceViewOwners
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SERVICE_VIEW_OWNERS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SERVICE_VIEW_DEPENDENCIES)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ServiceViewDependencies
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SERVICE_VIEW_DEPENDENCIES] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<ServiceViewDependencies
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SERVICE_VIEW_DEPENDENCIES] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -266,14 +179,12 @@ const ServiceRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.SERVICE_VIEW_CODE_REPOSITORIES,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ServiceViewCodeRepositories
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.SERVICE_VIEW_CODE_REPOSITORIES] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<ServiceViewCodeRepositories
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.SERVICE_VIEW_CODE_REPOSITORIES] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</PageRoute>
|
||||
|
||||
@@ -1,171 +1,63 @@
|
||||
import Loader from "../Components/Loader/Loader";
|
||||
import ComponentProps from "../Pages/PageComponentProps";
|
||||
import SettingsLayout from "../Pages/Settings/Layout";
|
||||
|
||||
import PageMap from "../Utils/PageMap";
|
||||
import RouteMap, { RouteUtil, SettingsRoutePath } from "../Utils/RouteMap";
|
||||
import Route from "Common/Types/API/Route";
|
||||
import React, {
|
||||
FunctionComponent,
|
||||
LazyExoticComponent,
|
||||
ReactElement,
|
||||
Suspense,
|
||||
lazy,
|
||||
} from "react";
|
||||
import React, { FunctionComponent, ReactElement } from "react";
|
||||
import { Route as PageRoute, Routes } from "react-router-dom";
|
||||
|
||||
// Pages
|
||||
const ProjectSettings: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Settings/ProjectSettings");
|
||||
});
|
||||
const SettingsApiKeys: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Settings/APIKeys");
|
||||
});
|
||||
import ProjectSettings from "../Pages/Settings/ProjectSettings";
|
||||
import SettingsApiKeys from "../Pages/Settings/APIKeys";
|
||||
|
||||
const SettingsUsers: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Settings/Users");
|
||||
});
|
||||
import SettingsUsers from "../Pages/Settings/Users";
|
||||
|
||||
const SettingsUserView: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Settings/UserView");
|
||||
});
|
||||
import SettingsUserView from "../Pages/Settings/UserView";
|
||||
|
||||
const SettingsApiKeyView: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Settings/APIKeyView");
|
||||
});
|
||||
import SettingsApiKeyView from "../Pages/Settings/APIKeyView";
|
||||
|
||||
const SettingsIngestionKeys: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Settings/TelemetryIngestionKeys");
|
||||
});
|
||||
import SettingsIngestionKeys from "../Pages/Settings/TelemetryIngestionKeys";
|
||||
|
||||
const SettingsIngestionKeyView: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Settings/TelemetryIngestionKeyView");
|
||||
});
|
||||
import SettingsIngestionKeyView from "../Pages/Settings/TelemetryIngestionKeyView";
|
||||
|
||||
const SettingLabels: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Settings/Labels");
|
||||
});
|
||||
import SettingLabels from "../Pages/Settings/Labels";
|
||||
|
||||
const SettingProbes: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Settings/Probes");
|
||||
});
|
||||
import SettingProbes from "../Pages/Settings/Probes";
|
||||
|
||||
const SettingAIAgents: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Settings/AIAgents");
|
||||
});
|
||||
import SettingAIAgents from "../Pages/Settings/AIAgents";
|
||||
|
||||
const SettingsAIAgentView: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Settings/AIAgentView");
|
||||
});
|
||||
import SettingsAIAgentView from "../Pages/Settings/AIAgentView";
|
||||
|
||||
const SettingLlmProviders: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Settings/LlmProviders");
|
||||
});
|
||||
import SettingLlmProviders from "../Pages/Settings/LlmProviders";
|
||||
|
||||
const SettingsLlmProviderView: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Settings/LlmProviderView");
|
||||
});
|
||||
import SettingsLlmProviderView from "../Pages/Settings/LlmProviderView";
|
||||
|
||||
const SettingsAIBilling: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Settings/AIBillingSettings");
|
||||
});
|
||||
import SettingsAIBilling from "../Pages/Settings/AIBillingSettings";
|
||||
|
||||
const SettingFeatureFlags: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Settings/FeatureFlags");
|
||||
});
|
||||
const SettingsTeams: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Settings/Teams");
|
||||
});
|
||||
const SettingsTeamView: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Settings/TeamView");
|
||||
});
|
||||
import SettingFeatureFlags from "../Pages/Settings/FeatureFlags";
|
||||
import SettingsTeams from "../Pages/Settings/Teams";
|
||||
import SettingsTeamView from "../Pages/Settings/TeamView";
|
||||
|
||||
const SettingsProbeView: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Settings/ProbeView");
|
||||
});
|
||||
import SettingsProbeView from "../Pages/Settings/ProbeView";
|
||||
|
||||
const SettingsDomains: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Settings/Domains");
|
||||
});
|
||||
import SettingsDomains from "../Pages/Settings/Domains";
|
||||
|
||||
const SettingsBilling: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Settings/Billing");
|
||||
});
|
||||
const SettingsSSO: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Settings/SSO");
|
||||
});
|
||||
import SettingsBilling from "../Pages/Settings/Billing";
|
||||
import SettingsSSO from "../Pages/Settings/SSO";
|
||||
|
||||
const SettingsSCIM: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Settings/SCIM");
|
||||
});
|
||||
import SettingsSCIM from "../Pages/Settings/SCIM";
|
||||
|
||||
const SettingsNotificationLogs: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Settings/NotificationLogs");
|
||||
});
|
||||
const SettingsAILogs: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Settings/AILogs");
|
||||
});
|
||||
const SettingsNotifications: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Settings/NotificationSettings");
|
||||
});
|
||||
const SettingsInvoices: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Settings/Invoices");
|
||||
});
|
||||
import SettingsNotificationLogs from "../Pages/Settings/NotificationLogs";
|
||||
import SettingsAILogs from "../Pages/Settings/AILogs";
|
||||
import SettingsNotifications from "../Pages/Settings/NotificationSettings";
|
||||
import SettingsInvoices from "../Pages/Settings/Invoices";
|
||||
|
||||
const SettingsMicrosoftTeamsIntegration: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Settings/MicrosoftTeamsIntegration");
|
||||
});
|
||||
import SettingsMicrosoftTeamsIntegration from "../Pages/Settings/MicrosoftTeamsIntegration";
|
||||
|
||||
const SettingsUsageHistory: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Settings/UsageHistory");
|
||||
});
|
||||
import SettingsUsageHistory from "../Pages/Settings/UsageHistory";
|
||||
|
||||
const SettingsSlackIntegration: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Settings/SlackIntegration");
|
||||
});
|
||||
import SettingsSlackIntegration from "../Pages/Settings/SlackIntegration";
|
||||
|
||||
const SettingsRoutes: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps,
|
||||
@@ -179,60 +71,48 @@ const SettingsRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
index
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<ProjectSettings
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<ProjectSettings
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SETTINGS_NOTIFICATION_LOGS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<SettingsNotificationLogs
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.SETTINGS_NOTIFICATION_LOGS] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<SettingsNotificationLogs
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_NOTIFICATION_LOGS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SETTINGS_AI_LOGS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<SettingsAILogs
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_AI_LOGS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<SettingsAILogs
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_AI_LOGS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SETTINGS_USAGE_HISTORY)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<SettingsUsageHistory
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_USAGE_HISTORY] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<SettingsUsageHistory
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_USAGE_HISTORY] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SETTINGS_FEATURE_FLAGS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<SettingFeatureFlags
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_FEATURE_FLAGS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<SettingFeatureFlags
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_FEATURE_FLAGS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -241,28 +121,22 @@ const SettingsRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.SETTINGS_NOTIFICATION_SETTINGS,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<SettingsNotifications
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.SETTINGS_NOTIFICATION_SETTINGS] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<SettingsNotifications
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.SETTINGS_NOTIFICATION_SETTINGS] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SETTINGS_SLACK_INTEGRATION)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<SettingsSlackIntegration
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.SETTINGS_SLACK_INTEGRATION] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<SettingsSlackIntegration
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_SLACK_INTEGRATION] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -271,76 +145,62 @@ const SettingsRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.SETTINGS_MICROSOFT_TEAMS_INTEGRATION,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<SettingsMicrosoftTeamsIntegration
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.SETTINGS_MICROSOFT_TEAMS_INTEGRATION
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<SettingsMicrosoftTeamsIntegration
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.SETTINGS_MICROSOFT_TEAMS_INTEGRATION] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SETTINGS_SSO)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<SettingsSSO
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_SSO] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<SettingsSSO
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_SSO] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SETTINGS_SCIM)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<SettingsSCIM
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_SCIM] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<SettingsSCIM
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_SCIM] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SETTINGS_DOMAINS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<SettingsDomains
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_DOMAINS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<SettingsDomains
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_DOMAINS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SETTINGS_APIKEYS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<SettingsApiKeys
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_APIKEYS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<SettingsApiKeys
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_APIKEYS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SETTINGS_APIKEY_VIEW, 2)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<SettingsApiKeyView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_APIKEY_VIEW] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<SettingsApiKeyView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_APIKEY_VIEW] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -349,14 +209,12 @@ const SettingsRoutes: FunctionComponent<ComponentProps> = (
|
||||
PageMap.SETTINGS_TELEMETRY_INGESTION_KEYS,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<SettingsIngestionKeys
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.SETTINGS_TELEMETRY_INGESTION_KEYS] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<SettingsIngestionKeys
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.SETTINGS_TELEMETRY_INGESTION_KEYS] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -366,160 +224,132 @@ const SettingsRoutes: FunctionComponent<ComponentProps> = (
|
||||
2,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<SettingsIngestionKeyView
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.SETTINGS_TELEMETRY_INGESTION_KEY_VIEW
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<SettingsIngestionKeyView
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.SETTINGS_TELEMETRY_INGESTION_KEY_VIEW] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SETTINGS_BILLING)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<SettingsBilling
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_BILLING] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<SettingsBilling
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_BILLING] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SETTINGS_BILLING_INVOICES)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<SettingsInvoices
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_BILLING_INVOICES] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<SettingsInvoices
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_BILLING_INVOICES] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SETTINGS_LABELS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<SettingLabels
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_LABELS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<SettingLabels
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_LABELS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SETTINGS_PROBES)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<SettingProbes
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_PROBES] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<SettingProbes
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_PROBES] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SETTINGS_AI_AGENTS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<SettingAIAgents
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_AI_AGENTS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<SettingAIAgents
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_AI_AGENTS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SETTINGS_AI_AGENT_VIEW, 2)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<SettingsAIAgentView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_AI_AGENT_VIEW] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<SettingsAIAgentView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_AI_AGENT_VIEW] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SETTINGS_LLM_PROVIDERS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<SettingLlmProviders
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_LLM_PROVIDERS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<SettingLlmProviders
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_LLM_PROVIDERS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SETTINGS_TEAMS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<SettingsTeams
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_TEAMS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<SettingsTeams
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_TEAMS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SETTINGS_USERS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<SettingsUsers
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_USERS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<SettingsUsers
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_USERS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SETTINGS_TEAM_VIEW, 2)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<SettingsTeamView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_TEAM_VIEW] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<SettingsTeamView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_TEAM_VIEW] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SETTINGS_USER_VIEW, 2)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<SettingsUserView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_USER_VIEW] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<SettingsUserView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_USER_VIEW] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SETTINGS_PROBE_VIEW, 2)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<SettingsProbeView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_PROBE_VIEW] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<SettingsProbeView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_PROBE_VIEW] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -529,26 +359,20 @@ const SettingsRoutes: FunctionComponent<ComponentProps> = (
|
||||
2,
|
||||
)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<SettingsLlmProviderView
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.SETTINGS_LLM_PROVIDER_VIEW] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<SettingsLlmProviderView
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_LLM_PROVIDER_VIEW] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.SETTINGS_AI_BILLING)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<SettingsAIBilling
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_AI_BILLING] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<SettingsAIBilling
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.SETTINGS_AI_BILLING] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</PageRoute>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,30 +1,16 @@
|
||||
import Loader from "../Components/Loader/Loader";
|
||||
import ComponentProps from "../Pages/PageComponentProps";
|
||||
import TracesLayout from "../Pages/Traces/Layout";
|
||||
import TracesViewLayout from "../Pages/Traces/View/Layout";
|
||||
import PageMap from "../Utils/PageMap";
|
||||
import RouteMap, { RouteUtil, TracesRoutePath } from "../Utils/RouteMap";
|
||||
import Route from "Common/Types/API/Route";
|
||||
import React, {
|
||||
FunctionComponent,
|
||||
LazyExoticComponent,
|
||||
ReactElement,
|
||||
Suspense,
|
||||
lazy,
|
||||
} from "react";
|
||||
import React, { FunctionComponent, ReactElement } from "react";
|
||||
import { Route as PageRoute, Routes } from "react-router-dom";
|
||||
|
||||
// Lazy Pages
|
||||
const TracesPage: LazyExoticComponent<FunctionComponent<ComponentProps>> = lazy(
|
||||
() => {
|
||||
return import("../Pages/Traces/Index");
|
||||
},
|
||||
);
|
||||
// Pages
|
||||
import TracesPage from "../Pages/Traces/Index";
|
||||
|
||||
const TraceViewPage: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Traces/View/Index");
|
||||
});
|
||||
import TraceViewPage from "../Pages/Traces/View/Index";
|
||||
|
||||
const TracesRoutes: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps,
|
||||
@@ -35,12 +21,10 @@ const TracesRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
index
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<TracesPage
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.TRACES] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<TracesPage
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.TRACES] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</PageRoute>
|
||||
@@ -53,24 +37,20 @@ const TracesRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
index
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<TraceViewPage
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.TRACE_VIEW] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<TraceViewPage
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.TRACE_VIEW] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.TRACE_VIEW)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<TraceViewPage
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.TRACE_VIEW] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<TraceViewPage
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.TRACE_VIEW] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</PageRoute>
|
||||
|
||||
@@ -1,86 +1,31 @@
|
||||
import Loader from "../Components/Loader/Loader";
|
||||
import ComponentProps from "../Pages/PageComponentProps";
|
||||
import UserSettingsLayout from "../Pages/UserSettings/Layout";
|
||||
import PageMap from "../Utils/PageMap";
|
||||
import RouteMap, { UserSettingsRoutePath } from "../Utils/RouteMap";
|
||||
import Route from "Common/Types/API/Route";
|
||||
import React, {
|
||||
FunctionComponent,
|
||||
LazyExoticComponent,
|
||||
ReactElement,
|
||||
Suspense,
|
||||
lazy,
|
||||
} from "react";
|
||||
import React, { FunctionComponent, ReactElement } from "react";
|
||||
import { Route as PageRoute, Routes } from "react-router-dom";
|
||||
|
||||
// Pages
|
||||
const UserSettingsNotificationMethods: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/UserSettings/NotificationMethods");
|
||||
});
|
||||
const UserSettingsCustomFields: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/UserSettings/CustomFields");
|
||||
});
|
||||
const UserSettingsIncidentNotificationRules: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/UserSettings/IncidentOnCallRules");
|
||||
});
|
||||
import UserSettingsNotificationMethods from "../Pages/UserSettings/NotificationMethods";
|
||||
import UserSettingsCustomFields from "../Pages/UserSettings/CustomFields";
|
||||
import UserSettingsIncidentNotificationRules from "../Pages/UserSettings/IncidentOnCallRules";
|
||||
|
||||
const UserSettingsMicrosoftTeamsIntegration: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/UserSettings/MicrosoftTeamsIntegration");
|
||||
});
|
||||
import UserSettingsMicrosoftTeamsIntegration from "../Pages/UserSettings/MicrosoftTeamsIntegration";
|
||||
|
||||
const UserSettingsAlertNotificationRules: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/UserSettings/AlertOnCallRules");
|
||||
});
|
||||
import UserSettingsAlertNotificationRules from "../Pages/UserSettings/AlertOnCallRules";
|
||||
|
||||
const UserSettingsAlertEpisodeNotificationRules: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/UserSettings/EpisodeOnCallRules");
|
||||
});
|
||||
import UserSettingsAlertEpisodeNotificationRules from "../Pages/UserSettings/EpisodeOnCallRules";
|
||||
|
||||
const UserSettingsIncidentEpisodeNotificationRules: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/UserSettings/IncidentEpisodeOnCallRules");
|
||||
});
|
||||
import UserSettingsIncidentEpisodeNotificationRules from "../Pages/UserSettings/IncidentEpisodeOnCallRules";
|
||||
|
||||
const UserSettingsNotificationLogs: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/UserSettings/OnCallLogs");
|
||||
});
|
||||
const UserSettingsNotificationLogsTimeline: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/UserSettings/OnCallLogsTimeline");
|
||||
});
|
||||
const UserSettingsNotiifcationSetting: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/UserSettings/NotificationSettings");
|
||||
});
|
||||
import UserSettingsNotificationLogs from "../Pages/UserSettings/OnCallLogs";
|
||||
import UserSettingsNotificationLogsTimeline from "../Pages/UserSettings/OnCallLogsTimeline";
|
||||
import UserSettingsNotiifcationSetting from "../Pages/UserSettings/NotificationSettings";
|
||||
|
||||
const UserSettingsSlackIntegration: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/UserSettings/SlackIntegration");
|
||||
});
|
||||
import UserSettingsSlackIntegration from "../Pages/UserSettings/SlackIntegration";
|
||||
|
||||
const UserSettingsIncomingCallPhoneNumbers: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/UserSettings/IncomingCallPhoneNumbers");
|
||||
});
|
||||
import UserSettingsIncomingCallPhoneNumbers from "../Pages/UserSettings/IncomingCallPhoneNumbers";
|
||||
|
||||
const UserSettingsRoutes: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps,
|
||||
@@ -91,12 +36,10 @@ const UserSettingsRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
path={UserSettingsRoutePath[PageMap.USER_SETTINGS] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<UserSettingsNotificationMethods
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.USER_SETTINGS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<UserSettingsNotificationMethods
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.USER_SETTINGS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
@@ -104,27 +47,19 @@ const UserSettingsRoutes: FunctionComponent<ComponentProps> = (
|
||||
UserSettingsRoutePath[PageMap.USER_SETTINGS_CUSTOM_FIELDS] || ""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<UserSettingsCustomFields
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.USER_SETTINGS_CUSTOM_FIELDS] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<UserSettingsCustomFields
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.USER_SETTINGS_CUSTOM_FIELDS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
path={UserSettingsRoutePath[PageMap.USER_SETTINGS_ON_CALL_LOGS] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<UserSettingsNotificationLogs
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.USER_SETTINGS_ON_CALL_LOGS] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<UserSettingsNotificationLogs
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.USER_SETTINGS_ON_CALL_LOGS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -135,14 +70,12 @@ const UserSettingsRoutes: FunctionComponent<ComponentProps> = (
|
||||
] || ""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<UserSettingsNotificationLogsTimeline
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.USER_SETTINGS_ON_CALL_LOGS_TIMELINE] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<UserSettingsNotificationLogsTimeline
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.USER_SETTINGS_ON_CALL_LOGS_TIMELINE] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -153,14 +86,12 @@ const UserSettingsRoutes: FunctionComponent<ComponentProps> = (
|
||||
] || ""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<UserSettingsNotiifcationSetting
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.USER_SETTINGS_NOTIFICATION_SETTINGS] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<UserSettingsNotiifcationSetting
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.USER_SETTINGS_NOTIFICATION_SETTINGS] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -170,14 +101,12 @@ const UserSettingsRoutes: FunctionComponent<ComponentProps> = (
|
||||
""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<UserSettingsNotificationMethods
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.USER_SETTINGS_NOTIFICATION_METHODS] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<UserSettingsNotificationMethods
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.USER_SETTINGS_NOTIFICATION_METHODS] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -188,16 +117,12 @@ const UserSettingsRoutes: FunctionComponent<ComponentProps> = (
|
||||
] || ""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<UserSettingsIncidentNotificationRules
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.USER_SETTINGS_INCIDENT_ON_CALL_RULES
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<UserSettingsIncidentNotificationRules
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.USER_SETTINGS_INCIDENT_ON_CALL_RULES] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -206,14 +131,12 @@ const UserSettingsRoutes: FunctionComponent<ComponentProps> = (
|
||||
UserSettingsRoutePath[PageMap.USER_SETTINGS_SLACK_INTEGRATION] || ""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<UserSettingsSlackIntegration
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.USER_SETTINGS_SLACK_INTEGRATION] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<UserSettingsSlackIntegration
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.USER_SETTINGS_SLACK_INTEGRATION] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -224,16 +147,14 @@ const UserSettingsRoutes: FunctionComponent<ComponentProps> = (
|
||||
] || ""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<UserSettingsMicrosoftTeamsIntegration
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.USER_SETTINGS_MICROSOFT_TEAMS_INTEGRATION
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<UserSettingsMicrosoftTeamsIntegration
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.USER_SETTINGS_MICROSOFT_TEAMS_INTEGRATION
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -243,14 +164,12 @@ const UserSettingsRoutes: FunctionComponent<ComponentProps> = (
|
||||
""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<UserSettingsAlertNotificationRules
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.USER_SETTINGS_ALERT_ON_CALL_RULES] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<UserSettingsAlertNotificationRules
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[PageMap.USER_SETTINGS_ALERT_ON_CALL_RULES] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -261,16 +180,14 @@ const UserSettingsRoutes: FunctionComponent<ComponentProps> = (
|
||||
] || ""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<UserSettingsAlertEpisodeNotificationRules
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.USER_SETTINGS_ALERT_EPISODE_ON_CALL_RULES
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<UserSettingsAlertEpisodeNotificationRules
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.USER_SETTINGS_ALERT_EPISODE_ON_CALL_RULES
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -281,16 +198,14 @@ const UserSettingsRoutes: FunctionComponent<ComponentProps> = (
|
||||
] || ""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<UserSettingsIncidentEpisodeNotificationRules
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.USER_SETTINGS_INCIDENT_EPISODE_ON_CALL_RULES
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<UserSettingsIncidentEpisodeNotificationRules
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.USER_SETTINGS_INCIDENT_EPISODE_ON_CALL_RULES
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -301,16 +216,14 @@ const UserSettingsRoutes: FunctionComponent<ComponentProps> = (
|
||||
] || ""
|
||||
}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<UserSettingsIncomingCallPhoneNumbers
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.USER_SETTINGS_INCOMING_CALL_PHONE_NUMBERS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
<UserSettingsIncomingCallPhoneNumbers
|
||||
{...props}
|
||||
pageRoute={
|
||||
RouteMap[
|
||||
PageMap.USER_SETTINGS_INCOMING_CALL_PHONE_NUMBERS
|
||||
] as Route
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</PageRoute>
|
||||
|
||||
@@ -1,59 +1,22 @@
|
||||
import Loader from "../Components/Loader/Loader";
|
||||
import ComponentProps from "../Pages/PageComponentProps";
|
||||
import WorkflowsLayout from "../Pages/Workflow/Layout";
|
||||
import WorkflowViewLayout from "../Pages/Workflow/View/Layout";
|
||||
import PageMap from "../Utils/PageMap";
|
||||
import RouteMap, { RouteUtil, WorkflowRoutePath } from "../Utils/RouteMap";
|
||||
import Route from "Common/Types/API/Route";
|
||||
import React, {
|
||||
FunctionComponent,
|
||||
LazyExoticComponent,
|
||||
ReactElement,
|
||||
Suspense,
|
||||
lazy,
|
||||
} from "react";
|
||||
import React, { FunctionComponent, ReactElement } from "react";
|
||||
import { Route as PageRoute, Routes } from "react-router-dom";
|
||||
|
||||
// Lazy Pages
|
||||
const Workflows: LazyExoticComponent<FunctionComponent<ComponentProps>> = lazy(
|
||||
() => {
|
||||
return import("../Pages/Workflow/Workflows");
|
||||
},
|
||||
);
|
||||
const WorkflowsVariables: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Workflow/Variable");
|
||||
});
|
||||
const WorkflowsLogs: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Workflow/Logs");
|
||||
});
|
||||
const WorkflowLogs: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Workflow/View/Logs");
|
||||
});
|
||||
const WorkflowDelete: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Workflow/View/Delete");
|
||||
});
|
||||
const WorkflowBuilder: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Workflow/View/Builder");
|
||||
});
|
||||
const WorkflowOverview: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Workflow/View/Index");
|
||||
});
|
||||
const WorkflowVariables: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
return import("../Pages/Workflow/View/Variable");
|
||||
});
|
||||
const WorkflowSettings: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Workflow/View/Settings");
|
||||
});
|
||||
// Pages
|
||||
import Workflows from "../Pages/Workflow/Workflows";
|
||||
import WorkflowsVariables from "../Pages/Workflow/Variable";
|
||||
import WorkflowsLogs from "../Pages/Workflow/Logs";
|
||||
import WorkflowLogs from "../Pages/Workflow/View/Logs";
|
||||
import WorkflowDelete from "../Pages/Workflow/View/Delete";
|
||||
import WorkflowBuilder from "../Pages/Workflow/View/Builder";
|
||||
import WorkflowOverview from "../Pages/Workflow/View/Index";
|
||||
import WorkflowVariables from "../Pages/Workflow/View/Variable";
|
||||
import WorkflowSettings from "../Pages/Workflow/View/Settings";
|
||||
|
||||
const WorkflowRoutes: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps,
|
||||
@@ -64,36 +27,30 @@ const WorkflowRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
index
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<Workflows
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.WORKFLOWS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<Workflows
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.WORKFLOWS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={WorkflowRoutePath[PageMap.WORKFLOWS_VARIABLES] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<WorkflowsVariables
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.WORKFLOWS_VARIABLES] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<WorkflowsVariables
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.WORKFLOWS_VARIABLES] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={WorkflowRoutePath[PageMap.WORKFLOWS_LOGS] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<WorkflowsLogs
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.WORKFLOWS_LOGS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<WorkflowsLogs
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.WORKFLOWS_LOGS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</PageRoute>
|
||||
@@ -105,71 +62,59 @@ const WorkflowRoutes: FunctionComponent<ComponentProps> = (
|
||||
<PageRoute
|
||||
index
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<WorkflowOverview
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.WORKFLOW_VIEW] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<WorkflowOverview
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.WORKFLOW_VIEW] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.WORKFLOW_VIEW_SETTINGS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<WorkflowSettings
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.WORKFLOW_VIEW_SETTINGS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<WorkflowSettings
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.WORKFLOW_VIEW_SETTINGS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.WORKFLOW_VARIABLES)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<WorkflowVariables
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.WORKFLOW_VARIABLES] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<WorkflowVariables
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.WORKFLOW_VARIABLES] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.WORKFLOW_BUILDER)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<WorkflowBuilder
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.WORKFLOW_BUILDER] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<WorkflowBuilder
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.WORKFLOW_BUILDER] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.WORKFLOW_LOGS)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<WorkflowLogs
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.WORKFLOW_LOGS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<WorkflowLogs
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.WORKFLOW_LOGS] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={RouteUtil.getLastPathForKey(PageMap.WORKFLOW_DELETE)}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<WorkflowDelete
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.WORKFLOW_DELETE] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
<WorkflowDelete
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.WORKFLOW_DELETE] as Route}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</PageRoute>
|
||||
|
||||
@@ -283,6 +283,18 @@ export default class CriteriaFilterUtil {
|
||||
});
|
||||
}
|
||||
|
||||
if (monitorType === MonitorType.DNS) {
|
||||
options = options.filter((i: DropdownOption) => {
|
||||
return (
|
||||
i.value === CheckOn.DnsIsOnline ||
|
||||
i.value === CheckOn.DnsResponseTime ||
|
||||
i.value === CheckOn.DnsRecordValue ||
|
||||
i.value === CheckOn.DnssecIsValid ||
|
||||
i.value === CheckOn.DnsRecordExists
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
@@ -498,6 +510,40 @@ export default class CriteriaFilterUtil {
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
checkOn === CheckOn.DnsIsOnline ||
|
||||
checkOn === CheckOn.DnssecIsValid ||
|
||||
checkOn === CheckOn.DnsRecordExists
|
||||
) {
|
||||
options = options.filter((i: DropdownOption) => {
|
||||
return i.value === FilterType.True || i.value === FilterType.False;
|
||||
});
|
||||
}
|
||||
|
||||
if (checkOn === CheckOn.DnsResponseTime) {
|
||||
options = options.filter((i: DropdownOption) => {
|
||||
return (
|
||||
i.value === FilterType.GreaterThan ||
|
||||
i.value === FilterType.LessThan ||
|
||||
i.value === FilterType.LessThanOrEqualTo ||
|
||||
i.value === FilterType.GreaterThanOrEqualTo
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
if (checkOn === CheckOn.DnsRecordValue) {
|
||||
options = options.filter((i: DropdownOption) => {
|
||||
return (
|
||||
i.value === FilterType.Contains ||
|
||||
i.value === FilterType.NotContains ||
|
||||
i.value === FilterType.EqualTo ||
|
||||
i.value === FilterType.NotEqualTo ||
|
||||
i.value === FilterType.StartsWith ||
|
||||
i.value === FilterType.EndsWith
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
if (checkOn === CheckOn.SnmpResponseTime) {
|
||||
options = options.filter((i: DropdownOption) => {
|
||||
return (
|
||||
@@ -655,6 +701,14 @@ export default class CriteriaFilterUtil {
|
||||
return "1";
|
||||
}
|
||||
|
||||
if (checkOn === CheckOn.DnsResponseTime) {
|
||||
return "5000";
|
||||
}
|
||||
|
||||
if (checkOn === CheckOn.DnsRecordValue) {
|
||||
return "192.168.1.1";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
6
Examples/fluentd/package-lock.json
generated
6
Examples/fluentd/package-lock.json
generated
@@ -613,9 +613,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.14.1",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz",
|
||||
"integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==",
|
||||
"version": "6.14.2",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz",
|
||||
"integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"side-channel": "^1.1.0"
|
||||
|
||||
@@ -128,9 +128,13 @@ export default class BlogPostUtil {
|
||||
}
|
||||
|
||||
public static async getBlogPost(fileName: string): Promise<BlogPost | null> {
|
||||
const blogPost: BlogPost | null = await this.getBlogPostFromFile(fileName);
|
||||
|
||||
return blogPost;
|
||||
try {
|
||||
const blogPost: BlogPost | null =
|
||||
await this.getBlogPostFromFile(fileName);
|
||||
return blogPost;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static async getTags(): Promise<string[]> {
|
||||
|
||||
6
MCP/package-lock.json
generated
6
MCP/package-lock.json
generated
@@ -4328,9 +4328,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.14.1",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz",
|
||||
"integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==",
|
||||
"version": "6.14.2",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz",
|
||||
"integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"side-channel": "^1.1.0"
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
import "./global.css";
|
||||
export { default } from "./src/App";
|
||||
|
||||
@@ -6,18 +6,20 @@
|
||||
"orientation": "portrait",
|
||||
"icon": "./assets/icon.png",
|
||||
"scheme": "oneuptime",
|
||||
"userInterfaceStyle": "dark",
|
||||
"userInterfaceStyle": "automatic",
|
||||
"newArchEnabled": true,
|
||||
"splash": {
|
||||
"image": "./assets/splash-icon.png",
|
||||
"resizeMode": "contain",
|
||||
"backgroundColor": "#0D1117"
|
||||
"backgroundColor": "#FFFFFF"
|
||||
},
|
||||
"ios": {
|
||||
"supportsTablet": true,
|
||||
"bundleIdentifier": "com.oneuptime.oncall",
|
||||
"infoPlist": {
|
||||
"UIBackgroundModes": ["remote-notification"],
|
||||
"UIBackgroundModes": [
|
||||
"remote-notification"
|
||||
],
|
||||
"NSFaceIDUsageDescription": "Authenticate to access OneUptime On-Call"
|
||||
}
|
||||
},
|
||||
@@ -36,7 +38,8 @@
|
||||
"color": "#58A6FF"
|
||||
}
|
||||
],
|
||||
"expo-local-authentication"
|
||||
"expo-local-authentication",
|
||||
"expo-font"
|
||||
],
|
||||
"web": {
|
||||
"favicon": "./assets/favicon.png"
|
||||
|
||||
9
MobileApp/babel.config.js
Normal file
9
MobileApp/babel.config.js
Normal file
@@ -0,0 +1,9 @@
|
||||
module.exports = function (api) {
|
||||
api.cache(true);
|
||||
return {
|
||||
presets: [
|
||||
["babel-preset-expo", { jsxImportSource: "nativewind" }],
|
||||
"nativewind/babel",
|
||||
],
|
||||
};
|
||||
};
|
||||
89
MobileApp/global.css
Normal file
89
MobileApp/global.css
Normal file
@@ -0,0 +1,89 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
:root {
|
||||
--color-bg-primary: #FFFFFF;
|
||||
--color-bg-secondary: #F8F8FA;
|
||||
--color-bg-tertiary: #F0F0F2;
|
||||
--color-bg-elevated: #FFFFFF;
|
||||
--color-card-accent: rgba(0, 0, 0, 0.04);
|
||||
--color-bg-glass: rgba(255, 255, 255, 0.85);
|
||||
--color-icon-bg: rgba(0, 0, 0, 0.05);
|
||||
--color-border-default: #E5E5EA;
|
||||
--color-border-subtle: #F0F0F2;
|
||||
--color-text-primary: #111111;
|
||||
--color-text-secondary: #6B6B6B;
|
||||
--color-text-tertiary: #9A9A9A;
|
||||
--color-text-inverse: #FFFFFF;
|
||||
--color-severity-critical: #CF222E;
|
||||
--color-severity-critical-bg: #CF222E1A;
|
||||
--color-severity-major: #BC4C00;
|
||||
--color-severity-major-bg: #BC4C001A;
|
||||
--color-severity-minor: #9A6700;
|
||||
--color-severity-minor-bg: #9A67001A;
|
||||
--color-severity-warning: #BF8700;
|
||||
--color-severity-warning-bg: #BF87001A;
|
||||
--color-severity-info: #0969DA;
|
||||
--color-severity-info-bg: #0969DA1A;
|
||||
--color-state-created: #CF222E;
|
||||
--color-state-acknowledged: #9A6700;
|
||||
--color-state-resolved: #1A7F37;
|
||||
--color-state-investigating: #BC4C00;
|
||||
--color-state-muted: #8C959F;
|
||||
--color-oncall-active: #1A7F37;
|
||||
--color-oncall-active-bg: #1A7F371A;
|
||||
--color-oncall-inactive: #8C959F;
|
||||
--color-oncall-inactive-bg: #8C959F1A;
|
||||
--color-action-primary: #1A1A1A;
|
||||
--color-action-primary-pressed: #333333;
|
||||
--color-action-destructive: #CF222E;
|
||||
--color-action-destructive-pressed: #A40E26;
|
||||
--color-status-success: #1A7F37;
|
||||
--color-status-success-bg: #1A7F371A;
|
||||
--color-status-error: #CF222E;
|
||||
--color-status-error-bg: #CF222E1A;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--color-bg-primary: #000000;
|
||||
--color-bg-secondary: #0A0A0A;
|
||||
--color-bg-tertiary: #161616;
|
||||
--color-bg-elevated: #0F0F0F;
|
||||
--color-card-accent: rgba(255, 255, 255, 0.07);
|
||||
--color-bg-glass: rgba(255, 255, 255, 0.05);
|
||||
--color-icon-bg: rgba(255, 255, 255, 0.07);
|
||||
--color-border-default: #1C1C1E;
|
||||
--color-border-subtle: #141414;
|
||||
--color-text-primary: #F0F0F0;
|
||||
--color-text-secondary: #8E8E93;
|
||||
--color-text-tertiary: #636366;
|
||||
--color-text-inverse: #000000;
|
||||
--color-severity-critical: #F85149;
|
||||
--color-severity-critical-bg: #F8514926;
|
||||
--color-severity-major: #F0883E;
|
||||
--color-severity-major-bg: #F0883E26;
|
||||
--color-severity-minor: #D29922;
|
||||
--color-severity-minor-bg: #D2992226;
|
||||
--color-severity-warning: #E3B341;
|
||||
--color-severity-warning-bg: #E3B34126;
|
||||
--color-severity-info: #58A6FF;
|
||||
--color-severity-info-bg: #58A6FF26;
|
||||
--color-state-created: #F85149;
|
||||
--color-state-acknowledged: #D29922;
|
||||
--color-state-resolved: #3FB950;
|
||||
--color-state-investigating: #F0883E;
|
||||
--color-state-muted: #636366;
|
||||
--color-oncall-active: #3FB950;
|
||||
--color-oncall-active-bg: #3FB95026;
|
||||
--color-oncall-inactive: #636366;
|
||||
--color-oncall-inactive-bg: #63636626;
|
||||
--color-action-primary: #FFFFFF;
|
||||
--color-action-primary-pressed: #D4D4D4;
|
||||
--color-action-destructive: #F85149;
|
||||
--color-action-destructive-pressed: #DA3633;
|
||||
--color-status-success: #3FB950;
|
||||
--color-status-success-bg: #3FB95026;
|
||||
--color-status-error: #F85149;
|
||||
--color-status-error-bg: #F8514926;
|
||||
}
|
||||
6
MobileApp/metro.config.js
Normal file
6
MobileApp/metro.config.js
Normal file
@@ -0,0 +1,6 @@
|
||||
const { getDefaultConfig } = require("expo/metro-config");
|
||||
const { withNativeWind } = require("nativewind/metro");
|
||||
|
||||
const config = getDefaultConfig(__dirname);
|
||||
|
||||
module.exports = withNativeWind(config, { input: "./global.css" });
|
||||
3
MobileApp/nativewind-env.d.ts
vendored
Normal file
3
MobileApp/nativewind-env.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
/// <reference types="nativewind/types" />
|
||||
|
||||
// NOTE: This file should not be edited and should be committed with your source code. It is generated by NativeWind.
|
||||
1337
MobileApp/package-lock.json
generated
1337
MobileApp/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,7 @@
|
||||
"compile": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@expo/vector-icons": "^15.0.3",
|
||||
"@react-native-async-storage/async-storage": "^2.2.0",
|
||||
"@react-native-community/netinfo": "11.4.1",
|
||||
"@react-navigation/bottom-tabs": "^7.12.0",
|
||||
@@ -22,23 +23,29 @@
|
||||
"expo": "~54.0.33",
|
||||
"expo-constants": "~18.0.0",
|
||||
"expo-device": "~8.0.10",
|
||||
"expo-font": "~14.0.11",
|
||||
"expo-haptics": "~15.0.8",
|
||||
"expo-linear-gradient": "~15.0.8",
|
||||
"expo-linking": "~8.0.11",
|
||||
"expo-local-authentication": "~17.0.8",
|
||||
"expo-notifications": "~0.32.0",
|
||||
"expo-splash-screen": "^31.0.13",
|
||||
"expo-status-bar": "~3.0.9",
|
||||
"expo-system-ui": "~6.0.9",
|
||||
"nativewind": "^4.2.1",
|
||||
"postcss": "^8.5.6",
|
||||
"react": "19.1.0",
|
||||
"react-dom": "19.1.0",
|
||||
"react-native": "0.81.5",
|
||||
"react-native-keychain": "^10.0.0",
|
||||
"react-native-safe-area-context": "^5.6.2",
|
||||
"react-native-screens": "~4.16.0",
|
||||
"react-native-web": "^0.21.0"
|
||||
"react-native-svg": "15.12.1",
|
||||
"react-native-web": "^0.21.0",
|
||||
"tailwindcss": "^3.4.19"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "~19.1.0",
|
||||
"babel-preset-expo": "^54.0.10",
|
||||
"typescript": "~5.9.2"
|
||||
},
|
||||
"private": true
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from "react";
|
||||
import { View, StyleSheet, ViewStyle } from "react-native";
|
||||
import { View } from "react-native";
|
||||
import { SafeAreaProvider } from "react-native-safe-area-context";
|
||||
import { StatusBar } from "expo-status-bar";
|
||||
import { QueryClient } from "@tanstack/react-query";
|
||||
import { PersistQueryClientProvider } from "@tanstack/react-query-persist-client";
|
||||
@@ -30,10 +31,8 @@ function AppContent(): React.JSX.Element {
|
||||
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
styles.container,
|
||||
{ backgroundColor: theme.colors.backgroundPrimary },
|
||||
]}
|
||||
className="flex-1 bg-bg-primary"
|
||||
style={{ flex: 1, backgroundColor: theme.colors.backgroundPrimary }}
|
||||
>
|
||||
<StatusBar style={theme.isDark ? "light" : "dark"} />
|
||||
<RootNavigator />
|
||||
@@ -44,23 +43,19 @@ function AppContent(): React.JSX.Element {
|
||||
|
||||
export default function App(): React.JSX.Element {
|
||||
return (
|
||||
<PersistQueryClientProvider
|
||||
client={queryClient}
|
||||
persistOptions={{ persister: asyncStoragePersister }}
|
||||
>
|
||||
<ThemeProvider>
|
||||
<AuthProvider>
|
||||
<ProjectProvider>
|
||||
<AppContent />
|
||||
</ProjectProvider>
|
||||
</AuthProvider>
|
||||
</ThemeProvider>
|
||||
</PersistQueryClientProvider>
|
||||
<SafeAreaProvider>
|
||||
<PersistQueryClientProvider
|
||||
client={queryClient}
|
||||
persistOptions={{ persister: asyncStoragePersister }}
|
||||
>
|
||||
<ThemeProvider>
|
||||
<AuthProvider>
|
||||
<ProjectProvider>
|
||||
<AppContent />
|
||||
</ProjectProvider>
|
||||
</AuthProvider>
|
||||
</ThemeProvider>
|
||||
</PersistQueryClientProvider>
|
||||
</SafeAreaProvider>
|
||||
);
|
||||
}
|
||||
|
||||
const styles: { container: ViewStyle } = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -6,6 +6,7 @@ import type {
|
||||
AlertState,
|
||||
StateTimelineItem,
|
||||
NoteItem,
|
||||
FeedItem,
|
||||
} from "./types";
|
||||
|
||||
export async function fetchAlertEpisodes(
|
||||
@@ -43,6 +44,41 @@ export async function fetchAlertEpisodes(
|
||||
return response.data;
|
||||
}
|
||||
|
||||
export async function fetchAllAlertEpisodes(
|
||||
options: { skip?: number; limit?: number; unresolvedOnly?: boolean } = {},
|
||||
): Promise<ListResponse<AlertEpisodeItem>> {
|
||||
const { skip = 0, limit = 100, unresolvedOnly = false } = options;
|
||||
|
||||
const query: Record<string, unknown> = {};
|
||||
if (unresolvedOnly) {
|
||||
query.currentAlertState = { isResolvedState: false };
|
||||
}
|
||||
|
||||
const response: AxiosResponse = await apiClient.post(
|
||||
`/api/alert-episode/get-list?skip=${skip}&limit=${limit}`,
|
||||
{
|
||||
query,
|
||||
select: {
|
||||
_id: true,
|
||||
title: true,
|
||||
episodeNumber: true,
|
||||
episodeNumberWithPrefix: true,
|
||||
description: true,
|
||||
createdAt: true,
|
||||
alertCount: true,
|
||||
currentAlertState: { _id: true, name: true, color: true },
|
||||
alertSeverity: { _id: true, name: true, color: true },
|
||||
projectId: true,
|
||||
},
|
||||
sort: { createdAt: "DESC" },
|
||||
},
|
||||
{
|
||||
headers: { "is-multi-tenant-query": "true" },
|
||||
},
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
export async function fetchAlertEpisodeById(
|
||||
projectId: string,
|
||||
episodeId: string,
|
||||
@@ -118,6 +154,31 @@ export async function fetchAlertEpisodeStateTimeline(
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
export async function fetchAlertEpisodeFeed(
|
||||
projectId: string,
|
||||
episodeId: string,
|
||||
): Promise<FeedItem[]> {
|
||||
const response: AxiosResponse = await apiClient.post(
|
||||
"/api/alert-episode-feed/get-list?skip=0&limit=50",
|
||||
{
|
||||
query: { alertEpisodeId: episodeId },
|
||||
select: {
|
||||
_id: true,
|
||||
feedInfoInMarkdown: true,
|
||||
moreInformationInMarkdown: true,
|
||||
displayColor: true,
|
||||
postedAt: true,
|
||||
createdAt: true,
|
||||
},
|
||||
sort: { postedAt: "DESC" },
|
||||
},
|
||||
{
|
||||
headers: { tenantid: projectId },
|
||||
},
|
||||
);
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
export async function changeAlertEpisodeState(
|
||||
projectId: string,
|
||||
episodeId: string,
|
||||
|
||||
@@ -5,6 +5,7 @@ import type {
|
||||
AlertItem,
|
||||
AlertState,
|
||||
StateTimelineItem,
|
||||
FeedItem,
|
||||
} from "./types";
|
||||
|
||||
export async function fetchAlerts(
|
||||
@@ -42,6 +43,41 @@ export async function fetchAlerts(
|
||||
return response.data;
|
||||
}
|
||||
|
||||
export async function fetchAllAlerts(
|
||||
options: { skip?: number; limit?: number; unresolvedOnly?: boolean } = {},
|
||||
): Promise<ListResponse<AlertItem>> {
|
||||
const { skip = 0, limit = 100, unresolvedOnly = false } = options;
|
||||
|
||||
const query: Record<string, unknown> = {};
|
||||
if (unresolvedOnly) {
|
||||
query.currentAlertState = { isResolvedState: false };
|
||||
}
|
||||
|
||||
const response: AxiosResponse = await apiClient.post(
|
||||
`/api/alert/get-list?skip=${skip}&limit=${limit}`,
|
||||
{
|
||||
query,
|
||||
select: {
|
||||
_id: true,
|
||||
title: true,
|
||||
alertNumber: true,
|
||||
alertNumberWithPrefix: true,
|
||||
description: true,
|
||||
createdAt: true,
|
||||
currentAlertState: { _id: true, name: true, color: true },
|
||||
alertSeverity: { _id: true, name: true, color: true },
|
||||
monitor: { _id: true, name: true },
|
||||
projectId: true,
|
||||
},
|
||||
sort: { createdAt: "DESC" },
|
||||
},
|
||||
{
|
||||
headers: { "is-multi-tenant-query": "true" },
|
||||
},
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
export async function fetchAlertById(
|
||||
projectId: string,
|
||||
alertId: string,
|
||||
@@ -117,6 +153,31 @@ export async function fetchAlertStateTimeline(
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
export async function fetchAlertFeed(
|
||||
projectId: string,
|
||||
alertId: string,
|
||||
): Promise<FeedItem[]> {
|
||||
const response: AxiosResponse = await apiClient.post(
|
||||
"/api/alert-feed/get-list?skip=0&limit=50",
|
||||
{
|
||||
query: { alertId },
|
||||
select: {
|
||||
_id: true,
|
||||
feedInfoInMarkdown: true,
|
||||
moreInformationInMarkdown: true,
|
||||
displayColor: true,
|
||||
postedAt: true,
|
||||
createdAt: true,
|
||||
},
|
||||
sort: { postedAt: "DESC" },
|
||||
},
|
||||
{
|
||||
headers: { tenantid: projectId },
|
||||
},
|
||||
);
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
export async function changeAlertState(
|
||||
projectId: string,
|
||||
alertId: string,
|
||||
|
||||
@@ -13,6 +13,42 @@ import {
|
||||
type StoredTokens,
|
||||
} from "../storage/keychain";
|
||||
|
||||
/**
|
||||
* Recursively normalizes OneUptime API serialized types in response data.
|
||||
* Converts { _type: "ObjectID", value: "uuid" } → "uuid"
|
||||
* Converts { _type: "DateTime", value: "iso-string" } → "iso-string"
|
||||
*/
|
||||
function normalizeResponseData(data: unknown): unknown {
|
||||
if (data === null || data === undefined) {
|
||||
return data;
|
||||
}
|
||||
|
||||
if (Array.isArray(data)) {
|
||||
return data.map(normalizeResponseData);
|
||||
}
|
||||
|
||||
if (typeof data === "object") {
|
||||
const obj: Record<string, unknown> = data as Record<string, unknown>;
|
||||
|
||||
// Check for serialized OneUptime types
|
||||
if (
|
||||
typeof obj["_type"] === "string" &&
|
||||
typeof obj["value"] === "string" &&
|
||||
(obj["_type"] === "ObjectID" || obj["_type"] === "DateTime")
|
||||
) {
|
||||
return obj["value"];
|
||||
}
|
||||
|
||||
const normalized: Record<string, unknown> = {};
|
||||
for (const key in obj) {
|
||||
normalized[key] = normalizeResponseData(obj[key]);
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
let isRefreshing: boolean = false;
|
||||
let refreshSubscribers: Array<(token: string) => void> = [];
|
||||
let onAuthFailure: (() => void) | null = null;
|
||||
@@ -55,9 +91,10 @@ apiClient.interceptors.request.use(
|
||||
},
|
||||
);
|
||||
|
||||
// Response interceptor: handle 401 with token refresh queue
|
||||
// Response interceptor: normalize OneUptime serialized types then handle 401
|
||||
apiClient.interceptors.response.use(
|
||||
(response: AxiosResponse) => {
|
||||
response.data = normalizeResponseData(response.data);
|
||||
return response;
|
||||
},
|
||||
async (error: AxiosError) => {
|
||||
@@ -97,6 +134,9 @@ apiClient.interceptors.response.use(
|
||||
{
|
||||
refreshToken: tokens.refreshToken,
|
||||
},
|
||||
{
|
||||
timeout: 10000,
|
||||
},
|
||||
);
|
||||
|
||||
const { accessToken, refreshToken, refreshTokenExpiresAt } =
|
||||
|
||||
@@ -6,6 +6,7 @@ import type {
|
||||
IncidentState,
|
||||
StateTimelineItem,
|
||||
NoteItem,
|
||||
FeedItem,
|
||||
} from "./types";
|
||||
|
||||
export async function fetchIncidentEpisodes(
|
||||
@@ -44,6 +45,42 @@ export async function fetchIncidentEpisodes(
|
||||
return response.data;
|
||||
}
|
||||
|
||||
export async function fetchAllIncidentEpisodes(
|
||||
options: { skip?: number; limit?: number; unresolvedOnly?: boolean } = {},
|
||||
): Promise<ListResponse<IncidentEpisodeItem>> {
|
||||
const { skip = 0, limit = 100, unresolvedOnly = false } = options;
|
||||
|
||||
const query: Record<string, unknown> = {};
|
||||
if (unresolvedOnly) {
|
||||
query.currentIncidentState = { isResolvedState: false };
|
||||
}
|
||||
|
||||
const response: AxiosResponse = await apiClient.post(
|
||||
`/api/incident-episode/get-list?skip=${skip}&limit=${limit}`,
|
||||
{
|
||||
query,
|
||||
select: {
|
||||
_id: true,
|
||||
title: true,
|
||||
episodeNumber: true,
|
||||
episodeNumberWithPrefix: true,
|
||||
description: true,
|
||||
createdAt: true,
|
||||
declaredAt: true,
|
||||
incidentCount: true,
|
||||
currentIncidentState: { _id: true, name: true, color: true },
|
||||
incidentSeverity: { _id: true, name: true, color: true },
|
||||
projectId: true,
|
||||
},
|
||||
sort: { createdAt: "DESC" },
|
||||
},
|
||||
{
|
||||
headers: { "is-multi-tenant-query": "true" },
|
||||
},
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
export async function fetchIncidentEpisodeById(
|
||||
projectId: string,
|
||||
episodeId: string,
|
||||
@@ -120,6 +157,31 @@ export async function fetchIncidentEpisodeStateTimeline(
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
export async function fetchIncidentEpisodeFeed(
|
||||
projectId: string,
|
||||
episodeId: string,
|
||||
): Promise<FeedItem[]> {
|
||||
const response: AxiosResponse = await apiClient.post(
|
||||
"/api/incident-episode-feed/get-list?skip=0&limit=50",
|
||||
{
|
||||
query: { incidentEpisodeId: episodeId },
|
||||
select: {
|
||||
_id: true,
|
||||
feedInfoInMarkdown: true,
|
||||
moreInformationInMarkdown: true,
|
||||
displayColor: true,
|
||||
postedAt: true,
|
||||
createdAt: true,
|
||||
},
|
||||
sort: { postedAt: "DESC" },
|
||||
},
|
||||
{
|
||||
headers: { tenantid: projectId },
|
||||
},
|
||||
);
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
export async function changeIncidentEpisodeState(
|
||||
projectId: string,
|
||||
episodeId: string,
|
||||
|
||||
@@ -5,6 +5,7 @@ import type {
|
||||
IncidentItem,
|
||||
IncidentState,
|
||||
StateTimelineItem,
|
||||
FeedItem,
|
||||
} from "./types";
|
||||
|
||||
export async function fetchIncidents(
|
||||
@@ -43,6 +44,42 @@ export async function fetchIncidents(
|
||||
return response.data;
|
||||
}
|
||||
|
||||
export async function fetchAllIncidents(
|
||||
options: { skip?: number; limit?: number; unresolvedOnly?: boolean } = {},
|
||||
): Promise<ListResponse<IncidentItem>> {
|
||||
const { skip = 0, limit = 100, unresolvedOnly = false } = options;
|
||||
|
||||
const query: Record<string, unknown> = {};
|
||||
if (unresolvedOnly) {
|
||||
query.currentIncidentState = { isResolvedState: false };
|
||||
}
|
||||
|
||||
const response: AxiosResponse = await apiClient.post(
|
||||
`/api/incident/get-list?skip=${skip}&limit=${limit}`,
|
||||
{
|
||||
query,
|
||||
select: {
|
||||
_id: true,
|
||||
title: true,
|
||||
incidentNumber: true,
|
||||
incidentNumberWithPrefix: true,
|
||||
description: true,
|
||||
declaredAt: true,
|
||||
createdAt: true,
|
||||
currentIncidentState: { _id: true, name: true, color: true },
|
||||
incidentSeverity: { _id: true, name: true, color: true },
|
||||
monitors: { _id: true, name: true },
|
||||
projectId: true,
|
||||
},
|
||||
sort: { createdAt: "DESC" },
|
||||
},
|
||||
{
|
||||
headers: { "is-multi-tenant-query": "true" },
|
||||
},
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
export async function fetchIncidentById(
|
||||
projectId: string,
|
||||
incidentId: string,
|
||||
@@ -119,6 +156,31 @@ export async function fetchIncidentStateTimeline(
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
export async function fetchIncidentFeed(
|
||||
projectId: string,
|
||||
incidentId: string,
|
||||
): Promise<FeedItem[]> {
|
||||
const response: AxiosResponse = await apiClient.post(
|
||||
"/api/incident-feed/get-list?skip=0&limit=50",
|
||||
{
|
||||
query: { incidentId },
|
||||
select: {
|
||||
_id: true,
|
||||
feedInfoInMarkdown: true,
|
||||
moreInformationInMarkdown: true,
|
||||
displayColor: true,
|
||||
postedAt: true,
|
||||
createdAt: true,
|
||||
},
|
||||
sort: { postedAt: "DESC" },
|
||||
},
|
||||
{
|
||||
headers: { tenantid: projectId },
|
||||
},
|
||||
);
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
export async function changeIncidentState(
|
||||
projectId: string,
|
||||
incidentId: string,
|
||||
|
||||
@@ -12,7 +12,7 @@ export async function fetchProjects(): Promise<ListResponse<ProjectItem>> {
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
// Multi-tenant request — no tenantid needed, user token determines access
|
||||
"is-multi-tenant-query": "true",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
@@ -39,6 +39,7 @@ export interface IncidentItem {
|
||||
currentIncidentState: NamedEntityWithColor;
|
||||
incidentSeverity: NamedEntityWithColor;
|
||||
monitors: NamedEntity[];
|
||||
projectId?: string;
|
||||
}
|
||||
|
||||
export interface AlertItem {
|
||||
@@ -51,6 +52,7 @@ export interface AlertItem {
|
||||
currentAlertState: NamedEntityWithColor;
|
||||
alertSeverity: NamedEntityWithColor;
|
||||
monitor: NamedEntity | null;
|
||||
projectId?: string;
|
||||
}
|
||||
|
||||
export interface IncidentState {
|
||||
@@ -91,6 +93,7 @@ export interface IncidentEpisodeItem {
|
||||
incidentCount: number;
|
||||
currentIncidentState: NamedEntityWithColor;
|
||||
incidentSeverity: NamedEntityWithColor;
|
||||
projectId?: string;
|
||||
}
|
||||
|
||||
export interface AlertEpisodeItem {
|
||||
@@ -103,6 +106,7 @@ export interface AlertEpisodeItem {
|
||||
alertCount: number;
|
||||
currentAlertState: NamedEntityWithColor;
|
||||
alertSeverity: NamedEntityWithColor;
|
||||
projectId?: string;
|
||||
}
|
||||
|
||||
export interface NoteItem {
|
||||
@@ -111,3 +115,23 @@ export interface NoteItem {
|
||||
createdAt: string;
|
||||
createdByUser: { _id: string; name: string } | null;
|
||||
}
|
||||
|
||||
export interface FeedItem {
|
||||
_id: string;
|
||||
feedInfoInMarkdown: string;
|
||||
moreInformationInMarkdown?: string;
|
||||
displayColor: ColorField;
|
||||
postedAt?: string;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
export interface WithProject<T> {
|
||||
item: T;
|
||||
projectId: string;
|
||||
projectName: string;
|
||||
}
|
||||
|
||||
export type ProjectIncidentItem = WithProject<IncidentItem>;
|
||||
export type ProjectAlertItem = WithProject<AlertItem>;
|
||||
export type ProjectIncidentEpisodeItem = WithProject<IncidentEpisodeItem>;
|
||||
export type ProjectAlertEpisodeItem = WithProject<AlertEpisodeItem>;
|
||||
|
||||
@@ -5,12 +5,12 @@ import {
|
||||
TextInput,
|
||||
TouchableOpacity,
|
||||
Modal,
|
||||
ActivityIndicator,
|
||||
StyleSheet,
|
||||
KeyboardAvoidingView,
|
||||
Platform,
|
||||
} from "react-native";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { useTheme } from "../theme";
|
||||
import GradientButton from "./GradientButton";
|
||||
|
||||
interface AddNoteModalProps {
|
||||
visible: boolean;
|
||||
@@ -49,37 +49,63 @@ export default function AddNoteModal({
|
||||
onRequestClose={handleClose}
|
||||
>
|
||||
<KeyboardAvoidingView
|
||||
style={styles.overlay}
|
||||
className="flex-1 justify-end"
|
||||
style={{ backgroundColor: "rgba(0,0,0,0.5)" }}
|
||||
behavior={Platform.OS === "ios" ? "padding" : "height"}
|
||||
>
|
||||
<View
|
||||
style={[
|
||||
styles.container,
|
||||
{
|
||||
backgroundColor: theme.colors.backgroundSecondary,
|
||||
borderColor: theme.colors.borderDefault,
|
||||
},
|
||||
]}
|
||||
className="rounded-t-[28px] p-5 pb-9"
|
||||
style={{
|
||||
backgroundColor: theme.isDark
|
||||
? theme.colors.backgroundElevated
|
||||
: theme.colors.backgroundPrimary,
|
||||
borderWidth: 1,
|
||||
borderBottomWidth: 0,
|
||||
borderColor: theme.colors.borderGlass,
|
||||
shadowColor: "#000",
|
||||
shadowOpacity: 0.2,
|
||||
shadowOffset: { width: 0, height: -8 },
|
||||
shadowRadius: 24,
|
||||
elevation: 16,
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
style={[
|
||||
theme.typography.titleMedium,
|
||||
{ color: theme.colors.textPrimary, marginBottom: 16 },
|
||||
]}
|
||||
>
|
||||
Add Note
|
||||
</Text>
|
||||
{/* Drag Handle */}
|
||||
<View className="items-center pt-1 pb-5">
|
||||
<View
|
||||
className="w-10 h-1.5 rounded-full"
|
||||
style={{ backgroundColor: theme.colors.borderDefault }}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<View className="flex-row items-center mb-5">
|
||||
<View
|
||||
className="w-9 h-9 rounded-lg items-center justify-center mr-3"
|
||||
style={{
|
||||
backgroundColor: theme.colors.iconBackground,
|
||||
}}
|
||||
>
|
||||
<Ionicons
|
||||
name="chatbubble-outline"
|
||||
size={18}
|
||||
color={theme.colors.textPrimary}
|
||||
/>
|
||||
</View>
|
||||
<Text
|
||||
className="text-title-md text-text-primary"
|
||||
style={{ letterSpacing: -0.3 }}
|
||||
>
|
||||
Add Note
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<TextInput
|
||||
style={[
|
||||
styles.input,
|
||||
{
|
||||
backgroundColor: theme.colors.backgroundTertiary,
|
||||
color: theme.colors.textPrimary,
|
||||
borderColor: theme.colors.borderSubtle,
|
||||
},
|
||||
]}
|
||||
placeholder="Add a note..."
|
||||
className="min-h-[120px] rounded-xl p-4 text-[15px] text-text-primary"
|
||||
style={{
|
||||
backgroundColor: theme.colors.backgroundSecondary,
|
||||
borderWidth: 1,
|
||||
borderColor: theme.colors.borderGlass,
|
||||
}}
|
||||
placeholder="Write a note..."
|
||||
placeholderTextColor={theme.colors.textTertiary}
|
||||
value={noteText}
|
||||
onChangeText={setNoteText}
|
||||
@@ -88,105 +114,34 @@ export default function AddNoteModal({
|
||||
editable={!isSubmitting}
|
||||
/>
|
||||
|
||||
<View style={styles.buttonRow}>
|
||||
<View className="flex-row gap-3 mt-5">
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.button,
|
||||
{
|
||||
backgroundColor: theme.colors.backgroundTertiary,
|
||||
borderColor: theme.colors.borderSubtle,
|
||||
borderWidth: 1,
|
||||
},
|
||||
]}
|
||||
className="flex-1 py-3.5 rounded-xl items-center justify-center min-h-[48px]"
|
||||
style={{
|
||||
backgroundColor: theme.colors.backgroundGlass,
|
||||
borderWidth: 1,
|
||||
borderColor: theme.colors.borderGlass,
|
||||
}}
|
||||
onPress={handleClose}
|
||||
disabled={isSubmitting}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<Text
|
||||
style={[
|
||||
styles.buttonText,
|
||||
{ color: theme.colors.textSecondary },
|
||||
]}
|
||||
>
|
||||
<Text className="text-[15px] font-bold text-text-secondary">
|
||||
Cancel
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.button,
|
||||
{
|
||||
backgroundColor:
|
||||
noteText.trim() && !isSubmitting
|
||||
? theme.colors.actionPrimary
|
||||
: theme.colors.backgroundTertiary,
|
||||
},
|
||||
]}
|
||||
onPress={handleSubmit}
|
||||
disabled={!noteText.trim() || isSubmitting}
|
||||
>
|
||||
{isSubmitting ? (
|
||||
<ActivityIndicator
|
||||
size="small"
|
||||
color={theme.colors.textInverse}
|
||||
/>
|
||||
) : (
|
||||
<Text
|
||||
style={[
|
||||
styles.buttonText,
|
||||
{
|
||||
color: noteText.trim()
|
||||
? theme.colors.textInverse
|
||||
: theme.colors.textTertiary,
|
||||
},
|
||||
]}
|
||||
>
|
||||
Submit
|
||||
</Text>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
<View className="flex-1">
|
||||
<GradientButton
|
||||
label="Submit"
|
||||
onPress={handleSubmit}
|
||||
loading={isSubmitting}
|
||||
disabled={!noteText.trim() || isSubmitting}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</KeyboardAvoidingView>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
const styles: ReturnType<typeof StyleSheet.create> = StyleSheet.create({
|
||||
overlay: {
|
||||
flex: 1,
|
||||
backgroundColor: "rgba(0,0,0,0.6)",
|
||||
justifyContent: "flex-end",
|
||||
},
|
||||
container: {
|
||||
borderTopLeftRadius: 20,
|
||||
borderTopRightRadius: 20,
|
||||
borderWidth: 1,
|
||||
borderBottomWidth: 0,
|
||||
padding: 20,
|
||||
paddingBottom: 36,
|
||||
},
|
||||
input: {
|
||||
minHeight: 120,
|
||||
borderRadius: 10,
|
||||
borderWidth: 1,
|
||||
padding: 12,
|
||||
fontSize: 15,
|
||||
},
|
||||
buttonRow: {
|
||||
flexDirection: "row",
|
||||
gap: 12,
|
||||
marginTop: 16,
|
||||
},
|
||||
button: {
|
||||
flex: 1,
|
||||
paddingVertical: 14,
|
||||
borderRadius: 12,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
minHeight: 48,
|
||||
},
|
||||
buttonText: {
|
||||
fontSize: 15,
|
||||
fontWeight: "700",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,18 +1,26 @@
|
||||
import React from "react";
|
||||
import { View, Text, StyleSheet, TouchableOpacity } from "react-native";
|
||||
import { View, Text, TouchableOpacity } from "react-native";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { LinearGradient } from "expo-linear-gradient";
|
||||
import { useTheme } from "../theme";
|
||||
import { rgbToHex } from "../utils/color";
|
||||
import { formatRelativeTime } from "../utils/date";
|
||||
import ProjectBadge from "./ProjectBadge";
|
||||
import GlassCard from "./GlassCard";
|
||||
import type { AlertItem } from "../api/types";
|
||||
|
||||
interface AlertCardProps {
|
||||
alert: AlertItem;
|
||||
onPress: () => void;
|
||||
projectName?: string;
|
||||
muted?: boolean;
|
||||
}
|
||||
|
||||
export default function AlertCard({
|
||||
alert,
|
||||
onPress,
|
||||
projectName,
|
||||
muted,
|
||||
}: AlertCardProps): React.JSX.Element {
|
||||
const { theme } = useTheme();
|
||||
|
||||
@@ -28,122 +36,102 @@ export default function AlertCard({
|
||||
|
||||
return (
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.card,
|
||||
{
|
||||
backgroundColor: theme.colors.backgroundSecondary,
|
||||
borderColor: theme.colors.borderSubtle,
|
||||
},
|
||||
]}
|
||||
className="mb-3"
|
||||
style={{
|
||||
opacity: muted ? 0.55 : 1,
|
||||
}}
|
||||
onPress={onPress}
|
||||
activeOpacity={0.7}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel={`Alert ${alert.alertNumberWithPrefix || alert.alertNumber}, ${alert.title}. State: ${alert.currentAlertState?.name ?? "unknown"}. Severity: ${alert.alertSeverity?.name ?? "unknown"}.`}
|
||||
>
|
||||
<View style={styles.topRow}>
|
||||
<Text style={[styles.number, { color: theme.colors.textTertiary }]}>
|
||||
{alert.alertNumberWithPrefix || `#${alert.alertNumber}`}
|
||||
</Text>
|
||||
<Text style={[styles.time, { color: theme.colors.textTertiary }]}>
|
||||
{timeString}
|
||||
</Text>
|
||||
</View>
|
||||
<GlassCard opaque>
|
||||
<View className="flex-row">
|
||||
<LinearGradient
|
||||
colors={[stateColor, stateColor + "40"]}
|
||||
start={{ x: 0.5, y: 0 }}
|
||||
end={{ x: 0.5, y: 1 }}
|
||||
style={{ width: 3 }}
|
||||
/>
|
||||
<View className="flex-1 p-4">
|
||||
{projectName ? (
|
||||
<View className="mb-2">
|
||||
<ProjectBadge name={projectName} />
|
||||
</View>
|
||||
) : null}
|
||||
<View className="flex-row justify-between items-center mb-2">
|
||||
<View
|
||||
className="px-2.5 py-0.5 rounded-full"
|
||||
style={{ backgroundColor: theme.colors.backgroundTertiary }}
|
||||
>
|
||||
<Text className="text-[12px] font-semibold text-text-tertiary">
|
||||
{alert.alertNumberWithPrefix || `#${alert.alertNumber}`}
|
||||
</Text>
|
||||
</View>
|
||||
<Text className="text-[12px] text-text-tertiary">
|
||||
{timeString}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<Text
|
||||
style={[
|
||||
theme.typography.bodyLarge,
|
||||
{ color: theme.colors.textPrimary, fontWeight: "600" },
|
||||
]}
|
||||
numberOfLines={2}
|
||||
>
|
||||
{alert.title}
|
||||
</Text>
|
||||
|
||||
<View style={styles.badgeRow}>
|
||||
{alert.currentAlertState ? (
|
||||
<View
|
||||
style={[
|
||||
styles.badge,
|
||||
{ backgroundColor: theme.colors.backgroundTertiary },
|
||||
]}
|
||||
>
|
||||
<View style={[styles.dot, { backgroundColor: stateColor }]} />
|
||||
<Text
|
||||
style={[styles.badgeText, { color: theme.colors.textPrimary }]}
|
||||
className="text-body-lg text-text-primary font-semibold mt-0.5"
|
||||
numberOfLines={2}
|
||||
>
|
||||
{alert.currentAlertState.name}
|
||||
{alert.title}
|
||||
</Text>
|
||||
</View>
|
||||
) : null}
|
||||
|
||||
{alert.alertSeverity ? (
|
||||
<View
|
||||
style={[styles.badge, { backgroundColor: severityColor + "26" }]}
|
||||
>
|
||||
<Text style={[styles.badgeText, { color: severityColor }]}>
|
||||
{alert.alertSeverity.name}
|
||||
</Text>
|
||||
</View>
|
||||
) : null}
|
||||
</View>
|
||||
<View className="flex-row flex-wrap gap-2 mt-3">
|
||||
{alert.currentAlertState ? (
|
||||
<View
|
||||
className="flex-row items-center px-2.5 py-1 rounded-full"
|
||||
style={{
|
||||
backgroundColor: theme.colors.backgroundTertiary,
|
||||
}}
|
||||
>
|
||||
<View
|
||||
className="w-2 h-2 rounded-full mr-1.5"
|
||||
style={{ backgroundColor: stateColor }}
|
||||
/>
|
||||
<Text className="text-[12px] font-semibold text-text-primary">
|
||||
{alert.currentAlertState.name}
|
||||
</Text>
|
||||
</View>
|
||||
) : null}
|
||||
|
||||
{alert.monitor ? (
|
||||
<Text
|
||||
style={[styles.monitor, { color: theme.colors.textSecondary }]}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{alert.monitor.name}
|
||||
</Text>
|
||||
) : null}
|
||||
{alert.alertSeverity ? (
|
||||
<View
|
||||
className="flex-row items-center px-2.5 py-1 rounded-full"
|
||||
style={{ backgroundColor: severityColor + "15" }}
|
||||
>
|
||||
<Text
|
||||
className="text-[12px] font-semibold"
|
||||
style={{ color: severityColor }}
|
||||
>
|
||||
{alert.alertSeverity.name}
|
||||
</Text>
|
||||
</View>
|
||||
) : null}
|
||||
</View>
|
||||
|
||||
{alert.monitor ? (
|
||||
<View className="flex-row items-center mt-3">
|
||||
<Ionicons
|
||||
name="desktop-outline"
|
||||
size={12}
|
||||
color={theme.colors.textTertiary}
|
||||
style={{ marginRight: 5 }}
|
||||
/>
|
||||
<Text
|
||||
className="text-[12px] text-text-secondary flex-1"
|
||||
numberOfLines={1}
|
||||
>
|
||||
{alert.monitor.name}
|
||||
</Text>
|
||||
</View>
|
||||
) : null}
|
||||
</View>
|
||||
</View>
|
||||
</GlassCard>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
||||
|
||||
const styles: ReturnType<typeof StyleSheet.create> = StyleSheet.create({
|
||||
card: {
|
||||
padding: 16,
|
||||
borderRadius: 12,
|
||||
borderWidth: 1,
|
||||
marginBottom: 12,
|
||||
},
|
||||
topRow: {
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
marginBottom: 6,
|
||||
},
|
||||
number: {
|
||||
fontSize: 13,
|
||||
fontWeight: "600",
|
||||
},
|
||||
time: {
|
||||
fontSize: 12,
|
||||
},
|
||||
badgeRow: {
|
||||
flexDirection: "row",
|
||||
flexWrap: "wrap",
|
||||
gap: 8,
|
||||
marginTop: 10,
|
||||
},
|
||||
badge: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 8,
|
||||
paddingVertical: 4,
|
||||
borderRadius: 6,
|
||||
},
|
||||
dot: {
|
||||
width: 8,
|
||||
height: 8,
|
||||
borderRadius: 4,
|
||||
marginRight: 6,
|
||||
},
|
||||
badgeText: {
|
||||
fontSize: 12,
|
||||
fontWeight: "600",
|
||||
},
|
||||
monitor: {
|
||||
fontSize: 12,
|
||||
marginTop: 8,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import React from "react";
|
||||
import { View, Text, StyleSheet } from "react-native";
|
||||
import { View, Text } from "react-native";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { useTheme } from "../theme";
|
||||
import GradientButton from "./GradientButton";
|
||||
|
||||
type EmptyIcon = "incidents" | "alerts" | "episodes" | "notes" | "default";
|
||||
|
||||
@@ -8,178 +10,75 @@ interface EmptyStateProps {
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
icon?: EmptyIcon;
|
||||
actionLabel?: string;
|
||||
onAction?: () => void;
|
||||
}
|
||||
|
||||
function EmptyIcon({
|
||||
icon,
|
||||
color,
|
||||
}: {
|
||||
icon: EmptyIcon;
|
||||
color: string;
|
||||
}): React.JSX.Element {
|
||||
/*
|
||||
* Simple geometric SVG-style icons using View primitives
|
||||
* Monochrome, clean, professional — not cartoon/playful
|
||||
*/
|
||||
if (icon === "incidents") {
|
||||
return (
|
||||
<View style={styles.iconContainer}>
|
||||
<View style={[styles.iconShield, { borderColor: color }]}>
|
||||
<View style={[styles.iconCheckmark, { backgroundColor: color }]} />
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
if (icon === "alerts") {
|
||||
return (
|
||||
<View style={styles.iconContainer}>
|
||||
<View style={[styles.iconBell, { borderColor: color }]}>
|
||||
<View style={[styles.iconBellClapper, { backgroundColor: color }]} />
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
if (icon === "episodes") {
|
||||
return (
|
||||
<View style={styles.iconContainer}>
|
||||
<View style={[styles.iconStack, { borderColor: color }]} />
|
||||
<View
|
||||
style={[styles.iconStackBack, { borderColor: color, opacity: 0.4 }]}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
// Default: simple circle with line through it
|
||||
return (
|
||||
<View style={styles.iconContainer}>
|
||||
<View style={[styles.iconCircle, { borderColor: color }]}>
|
||||
<View style={[styles.iconLine, { backgroundColor: color }]} />
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
const iconMap: Record<EmptyIcon, keyof typeof Ionicons.glyphMap> = {
|
||||
incidents: "warning-outline",
|
||||
alerts: "notifications-outline",
|
||||
episodes: "layers-outline",
|
||||
notes: "document-text-outline",
|
||||
default: "remove-circle-outline",
|
||||
};
|
||||
|
||||
export default function EmptyState({
|
||||
title,
|
||||
subtitle,
|
||||
icon = "default",
|
||||
actionLabel,
|
||||
onAction,
|
||||
}: EmptyStateProps): React.JSX.Element {
|
||||
const { theme } = useTheme();
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<EmptyIcon icon={icon} color={theme.colors.textTertiary} />
|
||||
<View className="flex-1 items-center justify-center px-10 py-28">
|
||||
{/* Outer gradient glow ring */}
|
||||
<View className="w-28 h-28 rounded-full items-center justify-center overflow-hidden">
|
||||
<View
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
backgroundColor: theme.colors.surfaceGlow,
|
||||
borderRadius: 56,
|
||||
}}
|
||||
/>
|
||||
{/* Inner icon container */}
|
||||
<View
|
||||
className="w-20 h-20 rounded-full items-center justify-center"
|
||||
style={{
|
||||
backgroundColor: theme.colors.backgroundTertiary,
|
||||
}}
|
||||
>
|
||||
<Ionicons
|
||||
name={iconMap[icon]}
|
||||
size={36}
|
||||
color={theme.colors.textSecondary}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<Text
|
||||
style={[
|
||||
theme.typography.titleSmall,
|
||||
{
|
||||
color: theme.colors.textPrimary,
|
||||
textAlign: "center",
|
||||
marginTop: 20,
|
||||
},
|
||||
]}
|
||||
className="text-title-md text-text-primary text-center mt-7"
|
||||
style={{ letterSpacing: -0.3 }}
|
||||
>
|
||||
{title}
|
||||
</Text>
|
||||
|
||||
{subtitle ? (
|
||||
<Text
|
||||
style={[
|
||||
theme.typography.bodyMedium,
|
||||
{
|
||||
color: theme.colors.textSecondary,
|
||||
textAlign: "center",
|
||||
marginTop: theme.spacing.sm,
|
||||
lineHeight: 20,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Text className="text-body-md text-text-secondary text-center mt-2.5 leading-6 max-w-[280px]">
|
||||
{subtitle}
|
||||
</Text>
|
||||
) : null}
|
||||
|
||||
{actionLabel && onAction ? (
|
||||
<View className="mt-6 w-[200px]">
|
||||
<GradientButton label={actionLabel} onPress={onAction} />
|
||||
</View>
|
||||
) : null}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles: ReturnType<typeof StyleSheet.create> = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
paddingHorizontal: 40,
|
||||
paddingVertical: 60,
|
||||
},
|
||||
iconContainer: {
|
||||
width: 64,
|
||||
height: 64,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
},
|
||||
// Shield icon (incidents)
|
||||
iconShield: {
|
||||
width: 44,
|
||||
height: 52,
|
||||
borderWidth: 2,
|
||||
borderRadius: 6,
|
||||
borderBottomLeftRadius: 22,
|
||||
borderBottomRightRadius: 22,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
},
|
||||
iconCheckmark: {
|
||||
width: 16,
|
||||
height: 3,
|
||||
borderRadius: 1.5,
|
||||
transform: [{ rotate: "-45deg" }],
|
||||
},
|
||||
// Bell icon (alerts)
|
||||
iconBell: {
|
||||
width: 36,
|
||||
height: 36,
|
||||
borderWidth: 2,
|
||||
borderRadius: 18,
|
||||
borderBottomLeftRadius: 4,
|
||||
borderBottomRightRadius: 4,
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-end",
|
||||
paddingBottom: 4,
|
||||
},
|
||||
iconBellClapper: {
|
||||
width: 8,
|
||||
height: 8,
|
||||
borderRadius: 4,
|
||||
},
|
||||
// Stack icon (episodes)
|
||||
iconStack: {
|
||||
width: 40,
|
||||
height: 32,
|
||||
borderWidth: 2,
|
||||
borderRadius: 8,
|
||||
position: "absolute",
|
||||
top: 12,
|
||||
},
|
||||
iconStackBack: {
|
||||
width: 32,
|
||||
height: 28,
|
||||
borderWidth: 2,
|
||||
borderRadius: 6,
|
||||
position: "absolute",
|
||||
top: 6,
|
||||
},
|
||||
// Default circle icon
|
||||
iconCircle: {
|
||||
width: 48,
|
||||
height: 48,
|
||||
borderWidth: 2,
|
||||
borderRadius: 24,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
},
|
||||
iconLine: {
|
||||
width: 20,
|
||||
height: 2,
|
||||
borderRadius: 1,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import React from "react";
|
||||
import { View, Text, StyleSheet, TouchableOpacity } from "react-native";
|
||||
import { View, Text, TouchableOpacity } from "react-native";
|
||||
import { LinearGradient } from "expo-linear-gradient";
|
||||
import { useTheme } from "../theme";
|
||||
import { rgbToHex } from "../utils/color";
|
||||
import { formatRelativeTime } from "../utils/date";
|
||||
import ProjectBadge from "./ProjectBadge";
|
||||
import GlassCard from "./GlassCard";
|
||||
import type {
|
||||
IncidentEpisodeItem,
|
||||
AlertEpisodeItem,
|
||||
@@ -14,17 +17,21 @@ type EpisodeCardProps =
|
||||
episode: IncidentEpisodeItem;
|
||||
type: "incident";
|
||||
onPress: () => void;
|
||||
projectName?: string;
|
||||
muted?: boolean;
|
||||
}
|
||||
| {
|
||||
episode: AlertEpisodeItem;
|
||||
type: "alert";
|
||||
onPress: () => void;
|
||||
projectName?: string;
|
||||
muted?: boolean;
|
||||
};
|
||||
|
||||
export default function EpisodeCard(
|
||||
props: EpisodeCardProps,
|
||||
): React.JSX.Element {
|
||||
const { episode, type, onPress } = props;
|
||||
const { episode, type, onPress, projectName, muted } = props;
|
||||
const { theme } = useTheme();
|
||||
|
||||
const state: NamedEntityWithColor =
|
||||
@@ -56,120 +63,96 @@ export default function EpisodeCard(
|
||||
|
||||
return (
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.card,
|
||||
{
|
||||
backgroundColor: theme.colors.backgroundSecondary,
|
||||
borderColor: theme.colors.borderSubtle,
|
||||
},
|
||||
]}
|
||||
className="mb-3"
|
||||
style={{
|
||||
opacity: muted ? 0.55 : 1,
|
||||
}}
|
||||
onPress={onPress}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<View style={styles.topRow}>
|
||||
<Text style={[styles.number, { color: theme.colors.textTertiary }]}>
|
||||
{episode.episodeNumberWithPrefix || `#${episode.episodeNumber}`}
|
||||
</Text>
|
||||
<Text style={[styles.time, { color: theme.colors.textTertiary }]}>
|
||||
{timeString}
|
||||
</Text>
|
||||
</View>
|
||||
<GlassCard opaque>
|
||||
<View className="flex-row">
|
||||
<LinearGradient
|
||||
colors={[stateColor, stateColor + "40"]}
|
||||
start={{ x: 0.5, y: 0 }}
|
||||
end={{ x: 0.5, y: 1 }}
|
||||
style={{ width: 3 }}
|
||||
/>
|
||||
<View className="flex-1 p-4">
|
||||
{projectName ? (
|
||||
<View className="mb-2">
|
||||
<ProjectBadge name={projectName} />
|
||||
</View>
|
||||
) : null}
|
||||
<View className="flex-row justify-between items-center mb-2">
|
||||
<View
|
||||
className="px-2.5 py-0.5 rounded-full"
|
||||
style={{ backgroundColor: theme.colors.backgroundTertiary }}
|
||||
>
|
||||
<Text className="text-[12px] font-semibold text-text-tertiary">
|
||||
{episode.episodeNumberWithPrefix ||
|
||||
`#${episode.episodeNumber}`}
|
||||
</Text>
|
||||
</View>
|
||||
<Text className="text-[12px] text-text-tertiary">
|
||||
{timeString}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<Text
|
||||
style={[
|
||||
theme.typography.bodyLarge,
|
||||
{ color: theme.colors.textPrimary, fontWeight: "600" },
|
||||
]}
|
||||
numberOfLines={2}
|
||||
>
|
||||
{episode.title}
|
||||
</Text>
|
||||
|
||||
<View style={styles.badgeRow}>
|
||||
{state ? (
|
||||
<View
|
||||
style={[
|
||||
styles.badge,
|
||||
{ backgroundColor: theme.colors.backgroundTertiary },
|
||||
]}
|
||||
>
|
||||
<View style={[styles.dot, { backgroundColor: stateColor }]} />
|
||||
<Text
|
||||
style={[styles.badgeText, { color: theme.colors.textPrimary }]}
|
||||
className="text-body-lg text-text-primary font-semibold mt-0.5"
|
||||
numberOfLines={2}
|
||||
>
|
||||
{state.name}
|
||||
{episode.title}
|
||||
</Text>
|
||||
</View>
|
||||
) : null}
|
||||
|
||||
{severity ? (
|
||||
<View
|
||||
style={[styles.badge, { backgroundColor: severityColor + "26" }]}
|
||||
>
|
||||
<Text style={[styles.badgeText, { color: severityColor }]}>
|
||||
{severity.name}
|
||||
</Text>
|
||||
</View>
|
||||
) : null}
|
||||
</View>
|
||||
<View className="flex-row flex-wrap gap-2 mt-3">
|
||||
{state ? (
|
||||
<View
|
||||
className="flex-row items-center px-2.5 py-1 rounded-full"
|
||||
style={{
|
||||
backgroundColor: theme.colors.backgroundTertiary,
|
||||
}}
|
||||
>
|
||||
<View
|
||||
className="w-2 h-2 rounded-full mr-1.5"
|
||||
style={{ backgroundColor: stateColor }}
|
||||
/>
|
||||
<Text className="text-[12px] font-semibold text-text-primary">
|
||||
{state.name}
|
||||
</Text>
|
||||
</View>
|
||||
) : null}
|
||||
|
||||
{childCount > 0 ? (
|
||||
<Text
|
||||
style={[styles.childCount, { color: theme.colors.textSecondary }]}
|
||||
>
|
||||
{childCount} {type === "incident" ? "incident" : "alert"}
|
||||
{childCount !== 1 ? "s" : ""}
|
||||
</Text>
|
||||
) : null}
|
||||
{severity ? (
|
||||
<View
|
||||
className="flex-row items-center px-2.5 py-1 rounded-full"
|
||||
style={{ backgroundColor: severityColor + "15" }}
|
||||
>
|
||||
<Text
|
||||
className="text-[12px] font-semibold"
|
||||
style={{ color: severityColor }}
|
||||
>
|
||||
{severity.name}
|
||||
</Text>
|
||||
</View>
|
||||
) : null}
|
||||
|
||||
{childCount > 0 ? (
|
||||
<View
|
||||
className="flex-row items-center px-2.5 py-1 rounded-full"
|
||||
style={{ backgroundColor: theme.colors.backgroundTertiary }}
|
||||
>
|
||||
<Text className="text-[12px] font-semibold text-text-secondary">
|
||||
{childCount} {type === "incident" ? "incident" : "alert"}
|
||||
{childCount !== 1 ? "s" : ""}
|
||||
</Text>
|
||||
</View>
|
||||
) : null}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</GlassCard>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
||||
|
||||
const styles: ReturnType<typeof StyleSheet.create> = StyleSheet.create({
|
||||
card: {
|
||||
padding: 16,
|
||||
borderRadius: 12,
|
||||
borderWidth: 1,
|
||||
marginBottom: 12,
|
||||
},
|
||||
topRow: {
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
marginBottom: 6,
|
||||
},
|
||||
number: {
|
||||
fontSize: 13,
|
||||
fontWeight: "600",
|
||||
},
|
||||
time: {
|
||||
fontSize: 12,
|
||||
},
|
||||
badgeRow: {
|
||||
flexDirection: "row",
|
||||
flexWrap: "wrap",
|
||||
gap: 8,
|
||||
marginTop: 10,
|
||||
},
|
||||
badge: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 8,
|
||||
paddingVertical: 4,
|
||||
borderRadius: 6,
|
||||
},
|
||||
dot: {
|
||||
width: 8,
|
||||
height: 8,
|
||||
borderRadius: 4,
|
||||
marginRight: 6,
|
||||
},
|
||||
badgeText: {
|
||||
fontSize: 12,
|
||||
fontWeight: "600",
|
||||
},
|
||||
childCount: {
|
||||
fontSize: 12,
|
||||
marginTop: 8,
|
||||
},
|
||||
});
|
||||
|
||||
89
MobileApp/src/components/FeedTimeline.tsx
Normal file
89
MobileApp/src/components/FeedTimeline.tsx
Normal file
@@ -0,0 +1,89 @@
|
||||
import React from "react";
|
||||
import { View, Text } from "react-native";
|
||||
import { useTheme } from "../theme";
|
||||
import { rgbToHex } from "../utils/color";
|
||||
import { formatDateTime } from "../utils/date";
|
||||
import type { FeedItem } from "../api/types";
|
||||
|
||||
interface FeedTimelineProps {
|
||||
feed: FeedItem[];
|
||||
}
|
||||
|
||||
function stripMarkdown(md: string): string {
|
||||
return md
|
||||
.replace(/\*\*(.*?)\*\*/g, "$1")
|
||||
.replace(/\*(.*?)\*/g, "$1")
|
||||
.replace(/`(.*?)`/g, "$1")
|
||||
.replace(/#{1,6}\s/g, "")
|
||||
.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1")
|
||||
.replace(/\n{2,}/g, "\n")
|
||||
.trim();
|
||||
}
|
||||
|
||||
export default function FeedTimeline({
|
||||
feed,
|
||||
}: FeedTimelineProps): React.JSX.Element {
|
||||
const { theme } = useTheme();
|
||||
|
||||
return (
|
||||
<View className="ml-1">
|
||||
{feed.map((entry: FeedItem, index: number) => {
|
||||
const entryColor: string = entry.displayColor
|
||||
? rgbToHex(entry.displayColor)
|
||||
: theme.colors.textTertiary;
|
||||
const isLast: boolean = index === feed.length - 1;
|
||||
const timeString: string = formatDateTime(
|
||||
entry.postedAt || entry.createdAt,
|
||||
);
|
||||
const mainText: string = stripMarkdown(entry.feedInfoInMarkdown);
|
||||
const moreText: string | undefined = entry.moreInformationInMarkdown
|
||||
? stripMarkdown(entry.moreInformationInMarkdown)
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<View key={entry._id} className="flex-row">
|
||||
{/* Timeline connector */}
|
||||
<View className="items-center mr-3.5">
|
||||
<View
|
||||
className="w-3 h-3 rounded-full mt-0.5"
|
||||
style={{
|
||||
backgroundColor: entryColor,
|
||||
shadowColor: entryColor,
|
||||
shadowOpacity: 0.3,
|
||||
shadowOffset: { width: 0, height: 1 },
|
||||
shadowRadius: 4,
|
||||
elevation: 2,
|
||||
}}
|
||||
/>
|
||||
{!isLast ? (
|
||||
<View
|
||||
className="w-0.5 flex-1 my-1.5"
|
||||
style={{
|
||||
backgroundColor: theme.colors.borderDefault,
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
</View>
|
||||
{/* Content */}
|
||||
<View className="flex-1 pb-5">
|
||||
<Text className="text-body-md text-text-primary leading-5">
|
||||
{mainText}
|
||||
</Text>
|
||||
{moreText ? (
|
||||
<Text
|
||||
className="text-body-sm text-text-secondary mt-1.5 leading-5"
|
||||
numberOfLines={3}
|
||||
>
|
||||
{moreText}
|
||||
</Text>
|
||||
) : null}
|
||||
<Text className="text-body-sm text-text-tertiary mt-1.5">
|
||||
{timeString}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
40
MobileApp/src/components/GlassCard.tsx
Normal file
40
MobileApp/src/components/GlassCard.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
import React from "react";
|
||||
import { View, ViewStyle } from "react-native";
|
||||
import { useTheme } from "../theme";
|
||||
|
||||
interface GlassCardProps {
|
||||
children: React.ReactNode;
|
||||
style?: ViewStyle;
|
||||
opaque?: boolean;
|
||||
}
|
||||
|
||||
export default function GlassCard({
|
||||
children,
|
||||
style,
|
||||
opaque = false,
|
||||
}: GlassCardProps): React.JSX.Element {
|
||||
const { theme } = useTheme();
|
||||
|
||||
return (
|
||||
<View
|
||||
className="rounded-2xl overflow-hidden"
|
||||
style={[
|
||||
{
|
||||
backgroundColor: opaque
|
||||
? theme.colors.backgroundElevated
|
||||
: theme.colors.backgroundGlass,
|
||||
borderWidth: 1,
|
||||
borderColor: theme.colors.borderGlass,
|
||||
shadowColor: "#000000",
|
||||
shadowOpacity: theme.isDark ? 0.3 : 0.08,
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
shadowRadius: 12,
|
||||
elevation: 3,
|
||||
},
|
||||
style,
|
||||
]}
|
||||
>
|
||||
{children}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
127
MobileApp/src/components/GradientButton.tsx
Normal file
127
MobileApp/src/components/GradientButton.tsx
Normal file
@@ -0,0 +1,127 @@
|
||||
import React from "react";
|
||||
import {
|
||||
TouchableOpacity,
|
||||
Text,
|
||||
ActivityIndicator,
|
||||
View,
|
||||
ViewStyle,
|
||||
} from "react-native";
|
||||
import { LinearGradient } from "expo-linear-gradient";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { useTheme } from "../theme";
|
||||
|
||||
interface GradientButtonProps {
|
||||
label: string;
|
||||
onPress: () => void;
|
||||
loading?: boolean;
|
||||
disabled?: boolean;
|
||||
icon?: keyof typeof Ionicons.glyphMap;
|
||||
variant?: "primary" | "secondary";
|
||||
style?: ViewStyle;
|
||||
}
|
||||
|
||||
export default function GradientButton({
|
||||
label,
|
||||
onPress,
|
||||
loading = false,
|
||||
disabled = false,
|
||||
icon,
|
||||
variant = "primary",
|
||||
style,
|
||||
}: GradientButtonProps): React.JSX.Element {
|
||||
const { theme } = useTheme();
|
||||
|
||||
if (variant === "secondary") {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
className="h-[52px] rounded-xl items-center justify-center overflow-hidden"
|
||||
style={[
|
||||
{
|
||||
backgroundColor: theme.colors.backgroundGlass,
|
||||
borderWidth: 1,
|
||||
borderColor: theme.colors.borderGlass,
|
||||
opacity: disabled || loading ? 0.6 : 1,
|
||||
},
|
||||
style,
|
||||
]}
|
||||
onPress={onPress}
|
||||
disabled={disabled || loading}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<View className="flex-row items-center">
|
||||
{loading ? (
|
||||
<ActivityIndicator color={theme.colors.textPrimary} />
|
||||
) : (
|
||||
<>
|
||||
{icon ? (
|
||||
<Ionicons
|
||||
name={icon}
|
||||
size={18}
|
||||
color={theme.colors.textPrimary}
|
||||
style={{ marginRight: 8 }}
|
||||
/>
|
||||
) : null}
|
||||
<Text
|
||||
className="text-[16px] font-bold"
|
||||
style={{ color: theme.colors.textPrimary }}
|
||||
>
|
||||
{label}
|
||||
</Text>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<TouchableOpacity
|
||||
className="h-[52px] rounded-xl overflow-hidden"
|
||||
style={[
|
||||
{
|
||||
opacity: disabled || loading ? 0.6 : 1,
|
||||
shadowColor: theme.colors.accentGradientStart,
|
||||
shadowOpacity: theme.isDark ? 0.15 : 0.2,
|
||||
shadowOffset: { width: 0, height: 4 },
|
||||
shadowRadius: 12,
|
||||
elevation: 4,
|
||||
},
|
||||
style,
|
||||
]}
|
||||
onPress={onPress}
|
||||
disabled={disabled || loading}
|
||||
activeOpacity={0.85}
|
||||
>
|
||||
<LinearGradient
|
||||
colors={[
|
||||
theme.colors.accentGradientStart,
|
||||
theme.colors.accentGradientEnd,
|
||||
]}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
className="flex-1 items-center justify-center flex-row"
|
||||
>
|
||||
{loading ? (
|
||||
<ActivityIndicator color={theme.colors.textInverse} />
|
||||
) : (
|
||||
<>
|
||||
{icon ? (
|
||||
<Ionicons
|
||||
name={icon}
|
||||
size={18}
|
||||
color={theme.colors.textInverse}
|
||||
style={{ marginRight: 8 }}
|
||||
/>
|
||||
) : null}
|
||||
<Text
|
||||
className="text-[16px] font-bold"
|
||||
style={{ color: theme.colors.textInverse }}
|
||||
>
|
||||
{label}
|
||||
</Text>
|
||||
</>
|
||||
)}
|
||||
</LinearGradient>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
||||
32
MobileApp/src/components/GradientHeader.tsx
Normal file
32
MobileApp/src/components/GradientHeader.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
import React from "react";
|
||||
import { LinearGradient } from "expo-linear-gradient";
|
||||
import { useTheme } from "../theme";
|
||||
|
||||
interface GradientHeaderProps {
|
||||
height?: number;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export default function GradientHeader({
|
||||
height = 320,
|
||||
children,
|
||||
}: GradientHeaderProps): React.JSX.Element {
|
||||
const { theme } = useTheme();
|
||||
|
||||
return (
|
||||
<LinearGradient
|
||||
colors={[theme.colors.gradientStart, theme.colors.gradientEnd]}
|
||||
start={{ x: 0.5, y: 0 }}
|
||||
end={{ x: 0.5, y: 1 }}
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
height,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</LinearGradient>
|
||||
);
|
||||
}
|
||||
@@ -1,18 +1,26 @@
|
||||
import React from "react";
|
||||
import { View, Text, StyleSheet, TouchableOpacity } from "react-native";
|
||||
import { View, Text, TouchableOpacity } from "react-native";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { LinearGradient } from "expo-linear-gradient";
|
||||
import { useTheme } from "../theme";
|
||||
import { rgbToHex } from "../utils/color";
|
||||
import { formatRelativeTime } from "../utils/date";
|
||||
import ProjectBadge from "./ProjectBadge";
|
||||
import GlassCard from "./GlassCard";
|
||||
import type { IncidentItem, NamedEntity } from "../api/types";
|
||||
|
||||
interface IncidentCardProps {
|
||||
incident: IncidentItem;
|
||||
onPress: () => void;
|
||||
projectName?: string;
|
||||
muted?: boolean;
|
||||
}
|
||||
|
||||
export default function IncidentCard({
|
||||
incident,
|
||||
onPress,
|
||||
projectName,
|
||||
muted,
|
||||
}: IncidentCardProps): React.JSX.Element {
|
||||
const { theme } = useTheme();
|
||||
|
||||
@@ -31,126 +39,107 @@ export default function IncidentCard({
|
||||
|
||||
return (
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.card,
|
||||
{
|
||||
backgroundColor: theme.colors.backgroundSecondary,
|
||||
borderColor: theme.colors.borderSubtle,
|
||||
},
|
||||
]}
|
||||
className="mb-3"
|
||||
style={{
|
||||
opacity: muted ? 0.55 : 1,
|
||||
}}
|
||||
onPress={onPress}
|
||||
activeOpacity={0.7}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel={`Incident ${incident.incidentNumberWithPrefix || incident.incidentNumber}, ${incident.title}. State: ${incident.currentIncidentState?.name ?? "unknown"}. Severity: ${incident.incidentSeverity?.name ?? "unknown"}.`}
|
||||
>
|
||||
<View style={styles.topRow}>
|
||||
<Text style={[styles.number, { color: theme.colors.textTertiary }]}>
|
||||
{incident.incidentNumberWithPrefix || `#${incident.incidentNumber}`}
|
||||
</Text>
|
||||
<Text style={[styles.time, { color: theme.colors.textTertiary }]}>
|
||||
{timeString}
|
||||
</Text>
|
||||
</View>
|
||||
<GlassCard opaque>
|
||||
<View className="flex-row">
|
||||
<LinearGradient
|
||||
colors={[stateColor, stateColor + "40"]}
|
||||
start={{ x: 0.5, y: 0 }}
|
||||
end={{ x: 0.5, y: 1 }}
|
||||
style={{ width: 3 }}
|
||||
/>
|
||||
<View className="flex-1 p-4">
|
||||
{projectName ? (
|
||||
<View className="mb-2">
|
||||
<ProjectBadge name={projectName} />
|
||||
</View>
|
||||
) : null}
|
||||
<View className="flex-row justify-between items-center mb-2">
|
||||
<View
|
||||
className="px-2.5 py-0.5 rounded-full"
|
||||
style={{ backgroundColor: theme.colors.backgroundTertiary }}
|
||||
>
|
||||
<Text className="text-[12px] font-semibold text-text-tertiary">
|
||||
{incident.incidentNumberWithPrefix ||
|
||||
`#${incident.incidentNumber}`}
|
||||
</Text>
|
||||
</View>
|
||||
<Text className="text-[12px] text-text-tertiary">
|
||||
{timeString}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<Text
|
||||
style={[
|
||||
theme.typography.bodyLarge,
|
||||
{ color: theme.colors.textPrimary, fontWeight: "600" },
|
||||
]}
|
||||
numberOfLines={2}
|
||||
>
|
||||
{incident.title}
|
||||
</Text>
|
||||
|
||||
<View style={styles.badgeRow}>
|
||||
{incident.currentIncidentState ? (
|
||||
<View
|
||||
style={[
|
||||
styles.badge,
|
||||
{ backgroundColor: theme.colors.backgroundTertiary },
|
||||
]}
|
||||
>
|
||||
<View style={[styles.dot, { backgroundColor: stateColor }]} />
|
||||
<Text
|
||||
style={[styles.badgeText, { color: theme.colors.textPrimary }]}
|
||||
className="text-body-lg text-text-primary font-semibold mt-0.5"
|
||||
numberOfLines={2}
|
||||
>
|
||||
{incident.currentIncidentState.name}
|
||||
{incident.title}
|
||||
</Text>
|
||||
</View>
|
||||
) : null}
|
||||
|
||||
{incident.incidentSeverity ? (
|
||||
<View
|
||||
style={[styles.badge, { backgroundColor: severityColor + "26" }]}
|
||||
>
|
||||
<Text style={[styles.badgeText, { color: severityColor }]}>
|
||||
{incident.incidentSeverity.name}
|
||||
</Text>
|
||||
</View>
|
||||
) : null}
|
||||
</View>
|
||||
<View className="flex-row flex-wrap gap-2 mt-3">
|
||||
{incident.currentIncidentState ? (
|
||||
<View
|
||||
className="flex-row items-center px-2.5 py-1 rounded-full"
|
||||
style={{
|
||||
backgroundColor: theme.colors.backgroundTertiary,
|
||||
}}
|
||||
>
|
||||
<View
|
||||
className="w-2 h-2 rounded-full mr-1.5"
|
||||
style={{ backgroundColor: stateColor }}
|
||||
/>
|
||||
<Text className="text-[12px] font-semibold text-text-primary">
|
||||
{incident.currentIncidentState.name}
|
||||
</Text>
|
||||
</View>
|
||||
) : null}
|
||||
|
||||
{monitorCount > 0 ? (
|
||||
<Text
|
||||
style={[styles.monitors, { color: theme.colors.textSecondary }]}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{incident.monitors
|
||||
.map((m: NamedEntity) => {
|
||||
return m.name;
|
||||
})
|
||||
.join(", ")}
|
||||
</Text>
|
||||
) : null}
|
||||
{incident.incidentSeverity ? (
|
||||
<View
|
||||
className="flex-row items-center px-2.5 py-1 rounded-full"
|
||||
style={{ backgroundColor: severityColor + "15" }}
|
||||
>
|
||||
<Text
|
||||
className="text-[12px] font-semibold"
|
||||
style={{ color: severityColor }}
|
||||
>
|
||||
{incident.incidentSeverity.name}
|
||||
</Text>
|
||||
</View>
|
||||
) : null}
|
||||
</View>
|
||||
|
||||
{monitorCount > 0 ? (
|
||||
<View className="flex-row items-center mt-3">
|
||||
<Ionicons
|
||||
name="desktop-outline"
|
||||
size={12}
|
||||
color={theme.colors.textTertiary}
|
||||
style={{ marginRight: 5 }}
|
||||
/>
|
||||
<Text
|
||||
className="text-[12px] text-text-secondary flex-1"
|
||||
numberOfLines={1}
|
||||
>
|
||||
{incident.monitors
|
||||
.map((m: NamedEntity) => {
|
||||
return m.name;
|
||||
})
|
||||
.join(", ")}
|
||||
</Text>
|
||||
</View>
|
||||
) : null}
|
||||
</View>
|
||||
</View>
|
||||
</GlassCard>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
||||
|
||||
const styles: ReturnType<typeof StyleSheet.create> = StyleSheet.create({
|
||||
card: {
|
||||
padding: 16,
|
||||
borderRadius: 12,
|
||||
borderWidth: 1,
|
||||
marginBottom: 12,
|
||||
},
|
||||
topRow: {
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
marginBottom: 6,
|
||||
},
|
||||
number: {
|
||||
fontSize: 13,
|
||||
fontWeight: "600",
|
||||
},
|
||||
time: {
|
||||
fontSize: 12,
|
||||
},
|
||||
badgeRow: {
|
||||
flexDirection: "row",
|
||||
flexWrap: "wrap",
|
||||
gap: 8,
|
||||
marginTop: 10,
|
||||
},
|
||||
badge: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 8,
|
||||
paddingVertical: 4,
|
||||
borderRadius: 6,
|
||||
},
|
||||
dot: {
|
||||
width: 8,
|
||||
height: 8,
|
||||
borderRadius: 4,
|
||||
marginRight: 6,
|
||||
},
|
||||
badgeText: {
|
||||
fontSize: 12,
|
||||
fontWeight: "600",
|
||||
},
|
||||
monitors: {
|
||||
fontSize: 12,
|
||||
marginTop: 8,
|
||||
},
|
||||
});
|
||||
|
||||
30
MobileApp/src/components/Logo.tsx
Normal file
30
MobileApp/src/components/Logo.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
import React from "react";
|
||||
import { ViewStyle } from "react-native";
|
||||
import Svg, { Path } from "react-native-svg";
|
||||
|
||||
interface LogoProps {
|
||||
size?: number;
|
||||
style?: ViewStyle;
|
||||
}
|
||||
|
||||
export default function Logo({
|
||||
size = 32,
|
||||
style,
|
||||
}: LogoProps): React.JSX.Element {
|
||||
return (
|
||||
<Svg width={size} height={size} viewBox="0 0 24 24" style={style}>
|
||||
<Path
|
||||
fill="#c1c0ff"
|
||||
d="M12,14.19531c-0.17551-0.00004-0.34793-0.04618-0.5-0.13379l-9-5.19726C2.02161,8.58794,1.85779,7.97612,2.13411,7.49773C2.22187,7.34579,2.34806,7.2196,2.5,7.13184l9-5.19336c0.30964-0.17774,0.69036-0.17774,1,0l9,5.19336c0.4784,0.27632,0.64221,0.88814,0.36589,1.36653C21.77813,8.65031,21.65194,8.7765,21.5,8.86426l-9,5.19726C12.34793,14.14913,12.17551,14.19527,12,14.19531z"
|
||||
/>
|
||||
<Path
|
||||
fill="#a2a1ff"
|
||||
d="M21.5,11.13184l-1.96411-1.13337L12.5,14.06152c-0.30947,0.17839-0.69053,0.17839-1,0L4.46411,9.99847L2.5,11.13184c-0.47839,0.27632-0.64221,0.88814-0.36589,1.36653C2.22187,12.65031,2.34806,12.7765,2.5,12.86426l9,5.19726c0.30947,0.17838,0.69053,0.17838,1,0l9-5.19726c0.4784-0.27632,0.64221-0.88814,0.36589-1.36653C21.77813,11.34579,21.65194,11.2196,21.5,11.13184z"
|
||||
/>
|
||||
<Path
|
||||
fill="#6563ff"
|
||||
d="M21.5,15.13184l-1.96411-1.13337L12.5,18.06152c-0.30947,0.17838-0.69053,0.17838-1,0l-7.03589-4.06305L2.5,15.13184c-0.47839,0.27632-0.64221,0.88814-0.36589,1.36653C2.22187,16.65031,2.34806,16.7765,2.5,16.86426l9,5.19726c0.30947,0.17838,0.69053,0.17838,1,0l9-5.19726c0.4784-0.27632,0.64221-0.88814,0.36589-1.36653C21.77813,15.34579,21.65194,15.2196,21.5,15.13184z"
|
||||
/>
|
||||
</Svg>
|
||||
);
|
||||
}
|
||||
109
MobileApp/src/components/NotesSection.tsx
Normal file
109
MobileApp/src/components/NotesSection.tsx
Normal file
@@ -0,0 +1,109 @@
|
||||
import React from "react";
|
||||
import { View, Text, TouchableOpacity } from "react-native";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { LinearGradient } from "expo-linear-gradient";
|
||||
import { useTheme } from "../theme";
|
||||
import { formatDateTime } from "../utils/date";
|
||||
import GlassCard from "./GlassCard";
|
||||
import type { NoteItem } from "../api/types";
|
||||
|
||||
interface NotesSectionProps {
|
||||
notes: NoteItem[] | undefined;
|
||||
setNoteModalVisible: (visible: boolean) => void;
|
||||
}
|
||||
|
||||
export default function NotesSection({
|
||||
notes,
|
||||
setNoteModalVisible,
|
||||
}: NotesSectionProps): React.JSX.Element {
|
||||
const { theme } = useTheme();
|
||||
|
||||
return (
|
||||
<View className="mb-2">
|
||||
<View className="flex-row justify-between items-center mb-3">
|
||||
<View className="flex-row items-center">
|
||||
<Ionicons
|
||||
name="chatbubble-outline"
|
||||
size={15}
|
||||
color={theme.colors.textSecondary}
|
||||
style={{ marginRight: 6 }}
|
||||
/>
|
||||
<Text className="text-[13px] font-semibold uppercase tracking-wide text-text-secondary">
|
||||
Internal Notes
|
||||
</Text>
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
className="flex-row items-center rounded-lg overflow-hidden"
|
||||
onPress={() => {
|
||||
return setNoteModalVisible(true);
|
||||
}}
|
||||
activeOpacity={0.85}
|
||||
>
|
||||
<LinearGradient
|
||||
colors={[
|
||||
theme.colors.accentGradientStart,
|
||||
theme.colors.accentGradientEnd,
|
||||
]}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
className="flex-row items-center px-3.5 py-2"
|
||||
>
|
||||
<Ionicons
|
||||
name="add"
|
||||
size={16}
|
||||
color={theme.colors.textInverse}
|
||||
style={{ marginRight: 4 }}
|
||||
/>
|
||||
<Text
|
||||
className="text-[13px] font-semibold"
|
||||
style={{ color: theme.colors.textInverse }}
|
||||
>
|
||||
Add Note
|
||||
</Text>
|
||||
</LinearGradient>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{notes && notes.length > 0
|
||||
? notes.map((note: NoteItem) => {
|
||||
return (
|
||||
<GlassCard
|
||||
key={note._id}
|
||||
style={{
|
||||
marginBottom: 10,
|
||||
borderTopWidth: 2,
|
||||
borderTopColor: theme.colors.accentGradientStart + "30",
|
||||
}}
|
||||
>
|
||||
<View className="p-4">
|
||||
<Text className="text-body-md text-text-primary leading-6">
|
||||
{note.note}
|
||||
</Text>
|
||||
<View className="flex-row justify-between mt-2.5">
|
||||
{note.createdByUser ? (
|
||||
<Text className="text-body-sm text-text-tertiary">
|
||||
{note.createdByUser.name}
|
||||
</Text>
|
||||
) : null}
|
||||
<Text className="text-body-sm text-text-tertiary">
|
||||
{formatDateTime(note.createdAt)}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</GlassCard>
|
||||
);
|
||||
})
|
||||
: null}
|
||||
|
||||
{notes && notes.length === 0 ? (
|
||||
<GlassCard>
|
||||
<View className="p-4 items-center">
|
||||
<Text className="text-body-sm text-text-tertiary">
|
||||
No notes yet.
|
||||
</Text>
|
||||
</View>
|
||||
</GlassCard>
|
||||
) : null}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import { View, Text, StyleSheet, Animated } from "react-native";
|
||||
import { View, Text, Animated } from "react-native";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { useTheme } from "../theme";
|
||||
import { useNetworkStatus } from "../hooks/useNetworkStatus";
|
||||
|
||||
@@ -25,51 +26,28 @@ export default function OfflineBanner(): React.JSX.Element | null {
|
||||
|
||||
return (
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.container,
|
||||
{
|
||||
backgroundColor: theme.colors.statusError,
|
||||
transform: [{ translateY: slideAnim }],
|
||||
},
|
||||
]}
|
||||
className="absolute top-0 left-0 right-0 z-[100] pt-[50px] pb-2.5 px-4"
|
||||
style={{
|
||||
backgroundColor: theme.colors.statusError,
|
||||
transform: [{ translateY: slideAnim }],
|
||||
shadowColor: theme.colors.statusError,
|
||||
shadowOpacity: 0.3,
|
||||
shadowOffset: { width: 0, height: 4 },
|
||||
shadowRadius: 12,
|
||||
elevation: 8,
|
||||
}}
|
||||
>
|
||||
<View style={styles.content}>
|
||||
<View style={styles.dot} />
|
||||
<Text style={[styles.text, { color: "#FFFFFF" }]}>
|
||||
<View className="flex-row items-center justify-center">
|
||||
<Ionicons
|
||||
name="cloud-offline-outline"
|
||||
size={16}
|
||||
color="#FFFFFF"
|
||||
style={{ marginRight: 8, opacity: 0.9 }}
|
||||
/>
|
||||
<Text className="text-[13px] font-semibold tracking-tight text-white">
|
||||
No internet connection
|
||||
</Text>
|
||||
</View>
|
||||
</Animated.View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles: ReturnType<typeof StyleSheet.create> = StyleSheet.create({
|
||||
container: {
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
zIndex: 100,
|
||||
paddingTop: 50,
|
||||
paddingBottom: 8,
|
||||
paddingHorizontal: 16,
|
||||
},
|
||||
content: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
},
|
||||
dot: {
|
||||
width: 6,
|
||||
height: 6,
|
||||
borderRadius: 3,
|
||||
backgroundColor: "#FFFFFF",
|
||||
marginRight: 8,
|
||||
opacity: 0.8,
|
||||
},
|
||||
text: {
|
||||
fontSize: 13,
|
||||
fontWeight: "600",
|
||||
letterSpacing: 0.2,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React from "react";
|
||||
import { View, Text, StyleSheet } from "react-native";
|
||||
import { useTheme } from "../theme";
|
||||
import { View, Text } from "react-native";
|
||||
|
||||
interface ProjectBadgeProps {
|
||||
name: string;
|
||||
@@ -11,35 +10,15 @@ export default function ProjectBadge({
|
||||
name,
|
||||
color,
|
||||
}: ProjectBadgeProps): React.JSX.Element {
|
||||
const { theme } = useTheme();
|
||||
|
||||
const dotColor: string = color || theme.colors.actionPrimary;
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={[styles.dot, { backgroundColor: dotColor }]} />
|
||||
<Text
|
||||
style={[
|
||||
theme.typography.bodySmall,
|
||||
{ color: theme.colors.textSecondary },
|
||||
]}
|
||||
numberOfLines={1}
|
||||
>
|
||||
<View className="flex-row items-center">
|
||||
<View
|
||||
className="w-2 h-2 rounded-full mr-1.5"
|
||||
style={color ? { backgroundColor: color } : undefined}
|
||||
/>
|
||||
<Text className="text-body-sm text-text-secondary" numberOfLines={1}>
|
||||
{name}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles: ReturnType<typeof StyleSheet.create> = StyleSheet.create({
|
||||
container: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
},
|
||||
dot: {
|
||||
width: 8,
|
||||
height: 8,
|
||||
borderRadius: 4,
|
||||
marginRight: 6,
|
||||
},
|
||||
});
|
||||
|
||||
29
MobileApp/src/components/SectionHeader.tsx
Normal file
29
MobileApp/src/components/SectionHeader.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import React from "react";
|
||||
import { View, Text } from "react-native";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { useTheme } from "../theme";
|
||||
|
||||
interface SectionHeaderProps {
|
||||
title: string;
|
||||
iconName: keyof typeof Ionicons.glyphMap;
|
||||
}
|
||||
|
||||
export default function SectionHeader({
|
||||
title,
|
||||
iconName,
|
||||
}: SectionHeaderProps): React.JSX.Element {
|
||||
const { theme } = useTheme();
|
||||
return (
|
||||
<View className="flex-row items-center mb-3">
|
||||
<Ionicons
|
||||
name={iconName}
|
||||
size={15}
|
||||
color={theme.colors.textSecondary}
|
||||
style={{ marginRight: 6 }}
|
||||
/>
|
||||
<Text className="text-[13px] font-semibold uppercase tracking-wide text-text-secondary">
|
||||
{title}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
83
MobileApp/src/components/SegmentedControl.tsx
Normal file
83
MobileApp/src/components/SegmentedControl.tsx
Normal file
@@ -0,0 +1,83 @@
|
||||
import React from "react";
|
||||
import { View, TouchableOpacity, Text } from "react-native";
|
||||
import { LinearGradient } from "expo-linear-gradient";
|
||||
import { useTheme } from "../theme";
|
||||
|
||||
interface Segment<T extends string> {
|
||||
key: T;
|
||||
label: string;
|
||||
}
|
||||
|
||||
interface SegmentedControlProps<T extends string> {
|
||||
segments: [Segment<T>, Segment<T>];
|
||||
selected: T;
|
||||
onSelect: (key: T) => void;
|
||||
}
|
||||
|
||||
export default function SegmentedControl<T extends string>({
|
||||
segments,
|
||||
selected,
|
||||
onSelect,
|
||||
}: SegmentedControlProps<T>): React.JSX.Element {
|
||||
const { theme } = useTheme();
|
||||
|
||||
return (
|
||||
<View
|
||||
className="flex-row mx-4 mt-3 mb-1 rounded-xl p-1"
|
||||
style={{ backgroundColor: theme.colors.backgroundSecondary }}
|
||||
>
|
||||
{segments.map((segment: Segment<T>) => {
|
||||
const isActive: boolean = segment.key === selected;
|
||||
return (
|
||||
<TouchableOpacity
|
||||
key={segment.key}
|
||||
className="flex-1 items-center py-2.5 rounded-[10px] overflow-hidden"
|
||||
style={
|
||||
isActive
|
||||
? {
|
||||
shadowColor: "#000000",
|
||||
shadowOpacity: theme.isDark ? 0.4 : 0.15,
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
shadowRadius: 6,
|
||||
elevation: 3,
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
onPress={() => {
|
||||
return onSelect(segment.key);
|
||||
}}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
{isActive ? (
|
||||
<LinearGradient
|
||||
colors={[
|
||||
theme.colors.accentGradientStart,
|
||||
theme.colors.accentGradientEnd,
|
||||
]}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
<Text
|
||||
className="text-body-sm font-semibold"
|
||||
style={{
|
||||
color: isActive
|
||||
? theme.colors.textInverse
|
||||
: theme.colors.textTertiary,
|
||||
}}
|
||||
>
|
||||
{segment.label}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from "react";
|
||||
import { View, Text, StyleSheet } from "react-native";
|
||||
import { View, Text } from "react-native";
|
||||
import { useTheme } from "../theme";
|
||||
|
||||
export type SeverityLevel = "critical" | "major" | "minor" | "warning" | "info";
|
||||
@@ -42,24 +42,16 @@ export default function SeverityBadge({
|
||||
const displayLabel: string = label || severity;
|
||||
|
||||
return (
|
||||
<View style={[styles.badge, { backgroundColor: colors.bg }]}>
|
||||
<Text style={[styles.text, { color: colors.text }]}>
|
||||
<View
|
||||
className="px-2 py-1 rounded-md self-start"
|
||||
style={{ backgroundColor: colors.bg }}
|
||||
>
|
||||
<Text
|
||||
className="text-xs font-semibold tracking-wide"
|
||||
style={{ color: colors.text }}
|
||||
>
|
||||
{displayLabel.toUpperCase()}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles: ReturnType<typeof StyleSheet.create> = StyleSheet.create({
|
||||
badge: {
|
||||
paddingHorizontal: 8,
|
||||
paddingVertical: 4,
|
||||
borderRadius: 6,
|
||||
alignSelf: "flex-start",
|
||||
},
|
||||
text: {
|
||||
fontSize: 12,
|
||||
fontWeight: "600",
|
||||
letterSpacing: 0.5,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import {
|
||||
View,
|
||||
StyleSheet,
|
||||
Animated,
|
||||
DimensionValue,
|
||||
AccessibilityInfo,
|
||||
@@ -36,13 +35,13 @@ export default function SkeletonCard({
|
||||
const animation: Animated.CompositeAnimation = Animated.loop(
|
||||
Animated.sequence([
|
||||
Animated.timing(opacity, {
|
||||
toValue: 0.7,
|
||||
duration: 1000,
|
||||
toValue: 0.6,
|
||||
duration: 900,
|
||||
useNativeDriver: true,
|
||||
}),
|
||||
Animated.timing(opacity, {
|
||||
toValue: 0.3,
|
||||
duration: 1000,
|
||||
toValue: 0.25,
|
||||
duration: 900,
|
||||
useNativeDriver: true,
|
||||
}),
|
||||
]),
|
||||
@@ -60,37 +59,38 @@ export default function SkeletonCard({
|
||||
if (variant === "compact") {
|
||||
return (
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.card,
|
||||
{
|
||||
backgroundColor: theme.colors.backgroundSecondary,
|
||||
borderColor: theme.colors.borderSubtle,
|
||||
opacity,
|
||||
},
|
||||
]}
|
||||
className="rounded-2xl mb-3 overflow-hidden"
|
||||
style={{
|
||||
backgroundColor: theme.colors.backgroundElevated,
|
||||
borderWidth: 1,
|
||||
borderColor: theme.colors.borderSubtle,
|
||||
opacity,
|
||||
}}
|
||||
accessibilityLabel="Loading content"
|
||||
accessibilityRole="progressbar"
|
||||
>
|
||||
<View style={styles.compactRow}>
|
||||
<View className="flex-row">
|
||||
<View
|
||||
style={[
|
||||
styles.compactBadge,
|
||||
{ backgroundColor: theme.colors.backgroundTertiary },
|
||||
]}
|
||||
/>
|
||||
<View
|
||||
style={[
|
||||
styles.compactTime,
|
||||
{ backgroundColor: theme.colors.backgroundTertiary },
|
||||
]}
|
||||
className="w-1"
|
||||
style={{ backgroundColor: theme.colors.backgroundTertiary }}
|
||||
/>
|
||||
<View className="flex-1 p-4">
|
||||
<View className="flex-row justify-between items-center mb-2.5">
|
||||
<View
|
||||
className="h-4 w-14 rounded-full"
|
||||
style={{ backgroundColor: theme.colors.backgroundTertiary }}
|
||||
/>
|
||||
<View
|
||||
className="h-3 w-8 rounded"
|
||||
style={{ backgroundColor: theme.colors.backgroundTertiary }}
|
||||
/>
|
||||
</View>
|
||||
<View
|
||||
className="h-[18px] rounded w-3/4 mb-3"
|
||||
style={{ backgroundColor: theme.colors.backgroundTertiary }}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<View
|
||||
style={[
|
||||
styles.titleLine,
|
||||
{ backgroundColor: theme.colors.backgroundTertiary, width: "75%" },
|
||||
]}
|
||||
/>
|
||||
</Animated.View>
|
||||
);
|
||||
}
|
||||
@@ -98,56 +98,56 @@ export default function SkeletonCard({
|
||||
if (variant === "detail") {
|
||||
return (
|
||||
<Animated.View
|
||||
style={[styles.detailContainer, { opacity }]}
|
||||
className="p-5"
|
||||
style={{ opacity }}
|
||||
accessibilityLabel="Loading content"
|
||||
accessibilityRole="progressbar"
|
||||
>
|
||||
{/* Badge row */}
|
||||
<View style={styles.badgeRow}>
|
||||
{/* Header area */}
|
||||
<View
|
||||
className="rounded-2xl p-5 mb-5"
|
||||
style={{ backgroundColor: theme.colors.surfaceGlow }}
|
||||
>
|
||||
<View className="flex-row gap-2 mb-3">
|
||||
<View
|
||||
className="h-7 w-20 rounded-full"
|
||||
style={{ backgroundColor: theme.colors.backgroundTertiary }}
|
||||
/>
|
||||
</View>
|
||||
<View
|
||||
style={[
|
||||
styles.badgeSkeleton,
|
||||
{ backgroundColor: theme.colors.backgroundTertiary },
|
||||
]}
|
||||
/>
|
||||
<View
|
||||
style={[
|
||||
styles.badgeSkeleton,
|
||||
{ backgroundColor: theme.colors.backgroundTertiary, width: 64 },
|
||||
]}
|
||||
className="h-7 w-4/5 rounded mb-3"
|
||||
style={{ backgroundColor: theme.colors.backgroundTertiary }}
|
||||
/>
|
||||
<View className="flex-row gap-2">
|
||||
<View
|
||||
className="h-7 w-24 rounded-full"
|
||||
style={{ backgroundColor: theme.colors.backgroundTertiary }}
|
||||
/>
|
||||
<View
|
||||
className="h-7 w-16 rounded-full"
|
||||
style={{ backgroundColor: theme.colors.backgroundTertiary }}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
{/* Title */}
|
||||
{/* Details card */}
|
||||
<View
|
||||
style={[
|
||||
styles.detailTitle,
|
||||
{ backgroundColor: theme.colors.backgroundTertiary },
|
||||
]}
|
||||
/>
|
||||
{/* Detail card */}
|
||||
<View
|
||||
style={[
|
||||
styles.detailCard,
|
||||
{
|
||||
backgroundColor: theme.colors.backgroundSecondary,
|
||||
borderColor: theme.colors.borderSubtle,
|
||||
},
|
||||
]}
|
||||
className="rounded-2xl p-4"
|
||||
style={{
|
||||
backgroundColor: theme.colors.backgroundElevated,
|
||||
borderWidth: 1,
|
||||
borderColor: theme.colors.borderSubtle,
|
||||
}}
|
||||
>
|
||||
{Array.from({ length: 3 }).map((_: unknown, index: number) => {
|
||||
return (
|
||||
<View key={index} style={styles.detailRow}>
|
||||
<View key={index} className="flex-row mb-3">
|
||||
<View
|
||||
style={[
|
||||
styles.detailLabel,
|
||||
{ backgroundColor: theme.colors.backgroundTertiary },
|
||||
]}
|
||||
className="h-3.5 w-20 rounded mr-4"
|
||||
style={{ backgroundColor: theme.colors.backgroundTertiary }}
|
||||
/>
|
||||
<View
|
||||
style={[
|
||||
styles.detailValue,
|
||||
{ backgroundColor: theme.colors.backgroundTertiary },
|
||||
]}
|
||||
className="h-3.5 w-[120px] rounded"
|
||||
style={{ backgroundColor: theme.colors.backgroundTertiary }}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
@@ -159,164 +159,62 @@ export default function SkeletonCard({
|
||||
|
||||
return (
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.card,
|
||||
{
|
||||
backgroundColor: theme.colors.backgroundSecondary,
|
||||
borderColor: theme.colors.borderSubtle,
|
||||
opacity,
|
||||
},
|
||||
]}
|
||||
className="rounded-2xl mb-3 overflow-hidden"
|
||||
style={{
|
||||
backgroundColor: theme.colors.backgroundElevated,
|
||||
borderWidth: 1,
|
||||
borderColor: theme.colors.borderSubtle,
|
||||
opacity,
|
||||
}}
|
||||
accessibilityLabel="Loading content"
|
||||
accessibilityRole="progressbar"
|
||||
>
|
||||
{/* Top row: badge + time */}
|
||||
<View style={styles.topRow}>
|
||||
<View className="flex-row">
|
||||
<View
|
||||
style={[
|
||||
styles.numberSkeleton,
|
||||
{ backgroundColor: theme.colors.backgroundTertiary },
|
||||
]}
|
||||
className="w-1"
|
||||
style={{ backgroundColor: theme.colors.backgroundTertiary }}
|
||||
/>
|
||||
<View
|
||||
style={[
|
||||
styles.timeSkeleton,
|
||||
{ backgroundColor: theme.colors.backgroundTertiary },
|
||||
]}
|
||||
/>
|
||||
</View>
|
||||
{/* Title */}
|
||||
<View
|
||||
style={[
|
||||
styles.titleLine,
|
||||
{ backgroundColor: theme.colors.backgroundTertiary },
|
||||
]}
|
||||
/>
|
||||
{/* Badge row */}
|
||||
<View style={styles.badgeRow}>
|
||||
<View
|
||||
style={[
|
||||
styles.badgeSkeleton,
|
||||
{ backgroundColor: theme.colors.backgroundTertiary },
|
||||
]}
|
||||
/>
|
||||
<View
|
||||
style={[
|
||||
styles.badgeSkeleton,
|
||||
{ backgroundColor: theme.colors.backgroundTertiary, width: 56 },
|
||||
]}
|
||||
/>
|
||||
</View>
|
||||
{/* Body lines */}
|
||||
{Array.from({ length: Math.max(lines - 1, 1) }).map(
|
||||
(_: unknown, index: number) => {
|
||||
return (
|
||||
<View className="flex-1 p-4">
|
||||
<View className="flex-row justify-between items-center mb-3">
|
||||
<View
|
||||
key={index}
|
||||
style={[
|
||||
styles.line,
|
||||
{
|
||||
backgroundColor: theme.colors.backgroundTertiary,
|
||||
width: lineWidths[index % lineWidths.length],
|
||||
},
|
||||
]}
|
||||
className="h-4 w-14 rounded-full"
|
||||
style={{ backgroundColor: theme.colors.backgroundTertiary }}
|
||||
/>
|
||||
);
|
||||
},
|
||||
)}
|
||||
<View
|
||||
className="h-3 w-10 rounded"
|
||||
style={{ backgroundColor: theme.colors.backgroundTertiary }}
|
||||
/>
|
||||
</View>
|
||||
<View
|
||||
className="h-[18px] rounded w-[70%] mb-3"
|
||||
style={{ backgroundColor: theme.colors.backgroundTertiary }}
|
||||
/>
|
||||
<View className="flex-row gap-2 mb-3">
|
||||
<View
|
||||
className="h-7 w-24 rounded-full"
|
||||
style={{ backgroundColor: theme.colors.backgroundTertiary }}
|
||||
/>
|
||||
<View
|
||||
className="h-7 w-16 rounded-full"
|
||||
style={{ backgroundColor: theme.colors.backgroundTertiary }}
|
||||
/>
|
||||
</View>
|
||||
{Array.from({ length: Math.max(lines - 1, 1) }).map(
|
||||
(_: unknown, index: number) => {
|
||||
return (
|
||||
<View
|
||||
key={index}
|
||||
className="h-3 rounded mb-2"
|
||||
style={{
|
||||
width: lineWidths[index % lineWidths.length],
|
||||
backgroundColor: theme.colors.backgroundTertiary,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</Animated.View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles: ReturnType<typeof StyleSheet.create> = StyleSheet.create({
|
||||
card: {
|
||||
padding: 16,
|
||||
borderRadius: 12,
|
||||
borderWidth: 1,
|
||||
marginBottom: 12,
|
||||
},
|
||||
topRow: {
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
marginBottom: 12,
|
||||
},
|
||||
numberSkeleton: {
|
||||
height: 14,
|
||||
width: 48,
|
||||
borderRadius: 4,
|
||||
},
|
||||
timeSkeleton: {
|
||||
height: 12,
|
||||
width: 36,
|
||||
borderRadius: 4,
|
||||
},
|
||||
titleLine: {
|
||||
height: 18,
|
||||
borderRadius: 4,
|
||||
width: "70%",
|
||||
marginBottom: 12,
|
||||
},
|
||||
badgeRow: {
|
||||
flexDirection: "row",
|
||||
gap: 8,
|
||||
marginBottom: 12,
|
||||
},
|
||||
badgeSkeleton: {
|
||||
height: 24,
|
||||
width: 80,
|
||||
borderRadius: 6,
|
||||
},
|
||||
line: {
|
||||
height: 12,
|
||||
borderRadius: 4,
|
||||
marginBottom: 8,
|
||||
},
|
||||
// Compact variant
|
||||
compactRow: {
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
marginBottom: 10,
|
||||
},
|
||||
compactBadge: {
|
||||
height: 14,
|
||||
width: 48,
|
||||
borderRadius: 4,
|
||||
},
|
||||
compactTime: {
|
||||
height: 12,
|
||||
width: 32,
|
||||
borderRadius: 4,
|
||||
},
|
||||
// Detail variant
|
||||
detailContainer: {
|
||||
padding: 20,
|
||||
},
|
||||
detailTitle: {
|
||||
height: 24,
|
||||
width: "80%",
|
||||
borderRadius: 4,
|
||||
marginBottom: 20,
|
||||
},
|
||||
detailCard: {
|
||||
borderRadius: 12,
|
||||
borderWidth: 1,
|
||||
padding: 16,
|
||||
},
|
||||
detailRow: {
|
||||
flexDirection: "row",
|
||||
marginBottom: 12,
|
||||
},
|
||||
detailLabel: {
|
||||
height: 14,
|
||||
width: 80,
|
||||
borderRadius: 4,
|
||||
marginRight: 16,
|
||||
},
|
||||
detailValue: {
|
||||
height: 14,
|
||||
width: 120,
|
||||
borderRadius: 4,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from "react";
|
||||
import { View, Text, StyleSheet } from "react-native";
|
||||
import { View, Text } from "react-native";
|
||||
import { useTheme } from "../theme";
|
||||
|
||||
export type StateType =
|
||||
@@ -32,39 +32,14 @@ export default function StateBadge({
|
||||
const displayLabel: string = label || state;
|
||||
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
styles.badge,
|
||||
{
|
||||
backgroundColor: theme.colors.backgroundTertiary,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<View style={[styles.dot, { backgroundColor: color }]} />
|
||||
<Text style={[styles.text, { color: theme.colors.textPrimary }]}>
|
||||
<View className="flex-row items-center px-2 py-1 rounded-md self-start bg-bg-tertiary">
|
||||
<View
|
||||
className="w-2 h-2 rounded-full mr-1.5"
|
||||
style={{ backgroundColor: color }}
|
||||
/>
|
||||
<Text className="text-xs font-semibold text-text-primary">
|
||||
{displayLabel.charAt(0).toUpperCase() + displayLabel.slice(1)}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles: ReturnType<typeof StyleSheet.create> = StyleSheet.create({
|
||||
badge: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 8,
|
||||
paddingVertical: 4,
|
||||
borderRadius: 6,
|
||||
alignSelf: "flex-start",
|
||||
},
|
||||
dot: {
|
||||
width: 8,
|
||||
height: 8,
|
||||
borderRadius: 4,
|
||||
marginRight: 6,
|
||||
},
|
||||
text: {
|
||||
fontSize: 12,
|
||||
fontWeight: "600",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -2,7 +2,6 @@ import React, { useRef } from "react";
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
Animated,
|
||||
PanResponder,
|
||||
type GestureResponderEvent,
|
||||
@@ -48,7 +47,6 @@ export default function SwipeableCard({
|
||||
_: GestureResponderEvent,
|
||||
gestureState: PanResponderGestureState,
|
||||
) => {
|
||||
// Limit swipe range
|
||||
const maxSwipe: number = 120;
|
||||
let dx: number = gestureState.dx;
|
||||
if (!rightAction && dx < 0) {
|
||||
@@ -60,7 +58,6 @@ export default function SwipeableCard({
|
||||
dx = Math.max(-maxSwipe, Math.min(maxSwipe, dx));
|
||||
translateX.setValue(dx);
|
||||
|
||||
// Haptic feedback at threshold
|
||||
if (Math.abs(dx) >= SWIPE_THRESHOLD && !hasTriggeredHaptic.current) {
|
||||
hasTriggeredHaptic.current = true;
|
||||
mediumImpact();
|
||||
@@ -97,34 +94,38 @@ export default function SwipeableCard({
|
||||
).current;
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View className="overflow-hidden rounded-xl">
|
||||
{/* Background actions */}
|
||||
<View style={styles.actionsContainer}>
|
||||
<View className="absolute inset-0 flex-row justify-between items-center">
|
||||
{leftAction ? (
|
||||
<View
|
||||
style={[styles.actionLeft, { backgroundColor: leftAction.color }]}
|
||||
className="flex-1 h-full justify-center pl-5 rounded-xl"
|
||||
style={{ backgroundColor: leftAction.color }}
|
||||
>
|
||||
<Text style={styles.actionText}>{leftAction.label}</Text>
|
||||
<Text className="text-white text-sm font-bold tracking-tight">
|
||||
{leftAction.label}
|
||||
</Text>
|
||||
</View>
|
||||
) : null}
|
||||
{rightAction ? (
|
||||
<View
|
||||
style={[styles.actionRight, { backgroundColor: rightAction.color }]}
|
||||
className="flex-1 h-full justify-center items-end pr-5 rounded-xl"
|
||||
style={{ backgroundColor: rightAction.color }}
|
||||
>
|
||||
<Text style={styles.actionText}>{rightAction.label}</Text>
|
||||
<Text className="text-white text-sm font-bold tracking-tight">
|
||||
{rightAction.label}
|
||||
</Text>
|
||||
</View>
|
||||
) : null}
|
||||
</View>
|
||||
|
||||
{/* Foreground content */}
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.foreground,
|
||||
{
|
||||
backgroundColor: theme.colors.backgroundPrimary,
|
||||
transform: [{ translateX }],
|
||||
},
|
||||
]}
|
||||
className="z-[1]"
|
||||
style={{
|
||||
transform: [{ translateX }],
|
||||
backgroundColor: theme.colors.backgroundPrimary,
|
||||
}}
|
||||
{...panResponder.panHandlers}
|
||||
>
|
||||
{children}
|
||||
@@ -132,40 +133,3 @@ export default function SwipeableCard({
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles: ReturnType<typeof StyleSheet.create> = StyleSheet.create({
|
||||
container: {
|
||||
overflow: "hidden",
|
||||
borderRadius: 12,
|
||||
},
|
||||
actionsContainer: {
|
||||
...StyleSheet.absoluteFillObject,
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
},
|
||||
actionLeft: {
|
||||
flex: 1,
|
||||
height: "100%",
|
||||
justifyContent: "center",
|
||||
paddingLeft: 20,
|
||||
borderRadius: 12,
|
||||
},
|
||||
actionRight: {
|
||||
flex: 1,
|
||||
height: "100%",
|
||||
justifyContent: "center",
|
||||
alignItems: "flex-end",
|
||||
paddingRight: 20,
|
||||
borderRadius: 12,
|
||||
},
|
||||
actionText: {
|
||||
color: "#FFFFFF",
|
||||
fontSize: 14,
|
||||
fontWeight: "700",
|
||||
letterSpacing: 0.3,
|
||||
},
|
||||
foreground: {
|
||||
zIndex: 1,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -3,8 +3,14 @@ import {
|
||||
fetchAlertById,
|
||||
fetchAlertStates,
|
||||
fetchAlertStateTimeline,
|
||||
fetchAlertFeed,
|
||||
} from "../api/alerts";
|
||||
import type { AlertItem, AlertState, StateTimelineItem } from "../api/types";
|
||||
import type {
|
||||
AlertItem,
|
||||
AlertState,
|
||||
StateTimelineItem,
|
||||
FeedItem,
|
||||
} from "../api/types";
|
||||
|
||||
export function useAlertDetail(
|
||||
projectId: string,
|
||||
@@ -43,3 +49,16 @@ export function useAlertStateTimeline(
|
||||
enabled: Boolean(projectId) && Boolean(alertId),
|
||||
});
|
||||
}
|
||||
|
||||
export function useAlertFeed(
|
||||
projectId: string,
|
||||
alertId: string,
|
||||
): UseQueryResult<FeedItem[], Error> {
|
||||
return useQuery({
|
||||
queryKey: ["alert-feed", projectId, alertId],
|
||||
queryFn: () => {
|
||||
return fetchAlertFeed(projectId, alertId);
|
||||
},
|
||||
enabled: Boolean(projectId) && Boolean(alertId),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,12 +4,14 @@ import {
|
||||
fetchAlertEpisodeStates,
|
||||
fetchAlertEpisodeStateTimeline,
|
||||
fetchAlertEpisodeNotes,
|
||||
fetchAlertEpisodeFeed,
|
||||
} from "../api/alertEpisodes";
|
||||
import type {
|
||||
AlertEpisodeItem,
|
||||
AlertState,
|
||||
StateTimelineItem,
|
||||
NoteItem,
|
||||
FeedItem,
|
||||
} from "../api/types";
|
||||
|
||||
export function useAlertEpisodeDetail(
|
||||
@@ -62,3 +64,16 @@ export function useAlertEpisodeNotes(
|
||||
enabled: Boolean(projectId) && Boolean(episodeId),
|
||||
});
|
||||
}
|
||||
|
||||
export function useAlertEpisodeFeed(
|
||||
projectId: string,
|
||||
episodeId: string,
|
||||
): UseQueryResult<FeedItem[], Error> {
|
||||
return useQuery({
|
||||
queryKey: ["alert-episode-feed", projectId, episodeId],
|
||||
queryFn: () => {
|
||||
return fetchAlertEpisodeFeed(projectId, episodeId);
|
||||
},
|
||||
enabled: Boolean(projectId) && Boolean(episodeId),
|
||||
});
|
||||
}
|
||||
|
||||
68
MobileApp/src/hooks/useAllProjectAlertEpisodes.ts
Normal file
68
MobileApp/src/hooks/useAllProjectAlertEpisodes.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import { useMemo } from "react";
|
||||
import { useQuery, UseQueryResult } from "@tanstack/react-query";
|
||||
import { useProject } from "./useProject";
|
||||
import { fetchAllAlertEpisodes } from "../api/alertEpisodes";
|
||||
import type {
|
||||
ListResponse,
|
||||
AlertEpisodeItem,
|
||||
ProjectAlertEpisodeItem,
|
||||
ProjectItem,
|
||||
} from "../api/types";
|
||||
|
||||
const FETCH_LIMIT: number = 100;
|
||||
|
||||
interface UseAllProjectAlertEpisodesResult {
|
||||
items: ProjectAlertEpisodeItem[];
|
||||
isLoading: boolean;
|
||||
isError: boolean;
|
||||
refetch: () => Promise<void>;
|
||||
}
|
||||
|
||||
export function useAllProjectAlertEpisodes(): UseAllProjectAlertEpisodesResult {
|
||||
const { projectList } = useProject();
|
||||
|
||||
const query: UseQueryResult<ListResponse<AlertEpisodeItem>, Error> = useQuery(
|
||||
{
|
||||
queryKey: ["alert-episodes", "all-projects"],
|
||||
queryFn: () => {
|
||||
return fetchAllAlertEpisodes({ skip: 0, limit: FETCH_LIMIT });
|
||||
},
|
||||
enabled: projectList.length > 0,
|
||||
},
|
||||
);
|
||||
|
||||
const projectMap: Map<string, string> = useMemo(() => {
|
||||
const map: Map<string, string> = new Map();
|
||||
projectList.forEach((p: ProjectItem) => {
|
||||
map.set(p._id, p.name);
|
||||
});
|
||||
return map;
|
||||
}, [projectList]);
|
||||
|
||||
const items: ProjectAlertEpisodeItem[] = useMemo(() => {
|
||||
if (!query.data) {
|
||||
return [];
|
||||
}
|
||||
return query.data.data.map(
|
||||
(item: AlertEpisodeItem): ProjectAlertEpisodeItem => {
|
||||
const pid: string = item.projectId ?? "";
|
||||
return {
|
||||
item,
|
||||
projectId: pid,
|
||||
projectName: projectMap.get(pid) ?? "",
|
||||
};
|
||||
},
|
||||
);
|
||||
}, [query.data, projectMap]);
|
||||
|
||||
const refetch: () => Promise<void> = async (): Promise<void> => {
|
||||
await query.refetch();
|
||||
};
|
||||
|
||||
return {
|
||||
items,
|
||||
isLoading: query.isPending,
|
||||
isError: query.isError,
|
||||
refetch,
|
||||
};
|
||||
}
|
||||
45
MobileApp/src/hooks/useAllProjectAlertStates.ts
Normal file
45
MobileApp/src/hooks/useAllProjectAlertStates.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { useMemo } from "react";
|
||||
import { useQueries, UseQueryResult } from "@tanstack/react-query";
|
||||
import { useProject } from "./useProject";
|
||||
import { fetchAlertStates } from "../api/alerts";
|
||||
import type { AlertState, ProjectItem } from "../api/types";
|
||||
|
||||
interface UseAllProjectAlertStatesResult {
|
||||
statesMap: Map<string, AlertState[]>;
|
||||
isLoading: boolean;
|
||||
}
|
||||
|
||||
export function useAllProjectAlertStates(): UseAllProjectAlertStatesResult {
|
||||
const { projectList } = useProject();
|
||||
|
||||
const queries: UseQueryResult<AlertState[], Error>[] = useQueries({
|
||||
queries: projectList.map((project: ProjectItem) => {
|
||||
return {
|
||||
queryKey: ["alert-states", project._id],
|
||||
queryFn: () => {
|
||||
return fetchAlertStates(project._id);
|
||||
},
|
||||
enabled: Boolean(project._id),
|
||||
};
|
||||
}),
|
||||
});
|
||||
|
||||
const isLoading: boolean = queries.some(
|
||||
(q: UseQueryResult<AlertState[], Error>) => {
|
||||
return q.isLoading;
|
||||
},
|
||||
);
|
||||
|
||||
const statesMap: Map<string, AlertState[]> = useMemo(() => {
|
||||
const map: Map<string, AlertState[]> = new Map();
|
||||
queries.forEach((q: UseQueryResult<AlertState[], Error>, index: number) => {
|
||||
const project: ProjectItem | undefined = projectList[index];
|
||||
if (project && q.data) {
|
||||
map.set(project._id, q.data);
|
||||
}
|
||||
});
|
||||
return map;
|
||||
}, [queries, projectList]);
|
||||
|
||||
return { statesMap, isLoading };
|
||||
}
|
||||
64
MobileApp/src/hooks/useAllProjectAlerts.ts
Normal file
64
MobileApp/src/hooks/useAllProjectAlerts.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import { useMemo } from "react";
|
||||
import { useQuery, UseQueryResult } from "@tanstack/react-query";
|
||||
import { useProject } from "./useProject";
|
||||
import { fetchAllAlerts } from "../api/alerts";
|
||||
import type {
|
||||
ListResponse,
|
||||
AlertItem,
|
||||
ProjectAlertItem,
|
||||
ProjectItem,
|
||||
} from "../api/types";
|
||||
|
||||
const FETCH_LIMIT: number = 100;
|
||||
|
||||
interface UseAllProjectAlertsResult {
|
||||
items: ProjectAlertItem[];
|
||||
isLoading: boolean;
|
||||
isError: boolean;
|
||||
refetch: () => Promise<void>;
|
||||
}
|
||||
|
||||
export function useAllProjectAlerts(): UseAllProjectAlertsResult {
|
||||
const { projectList } = useProject();
|
||||
|
||||
const query: UseQueryResult<ListResponse<AlertItem>, Error> = useQuery({
|
||||
queryKey: ["alerts", "all-projects"],
|
||||
queryFn: () => {
|
||||
return fetchAllAlerts({ skip: 0, limit: FETCH_LIMIT });
|
||||
},
|
||||
enabled: projectList.length > 0,
|
||||
});
|
||||
|
||||
const projectMap: Map<string, string> = useMemo(() => {
|
||||
const map: Map<string, string> = new Map();
|
||||
projectList.forEach((p: ProjectItem) => {
|
||||
map.set(p._id, p.name);
|
||||
});
|
||||
return map;
|
||||
}, [projectList]);
|
||||
|
||||
const items: ProjectAlertItem[] = useMemo(() => {
|
||||
if (!query.data) {
|
||||
return [];
|
||||
}
|
||||
return query.data.data.map((item: AlertItem): ProjectAlertItem => {
|
||||
const pid: string = item.projectId ?? "";
|
||||
return {
|
||||
item,
|
||||
projectId: pid,
|
||||
projectName: projectMap.get(pid) ?? "",
|
||||
};
|
||||
});
|
||||
}, [query.data, projectMap]);
|
||||
|
||||
const refetch: () => Promise<void> = async (): Promise<void> => {
|
||||
await query.refetch();
|
||||
};
|
||||
|
||||
return {
|
||||
items,
|
||||
isLoading: query.isPending,
|
||||
isError: query.isError,
|
||||
refetch,
|
||||
};
|
||||
}
|
||||
104
MobileApp/src/hooks/useAllProjectCounts.ts
Normal file
104
MobileApp/src/hooks/useAllProjectCounts.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
import { useQuery, UseQueryResult } from "@tanstack/react-query";
|
||||
import { useProject } from "./useProject";
|
||||
import { fetchAllIncidents } from "../api/incidents";
|
||||
import { fetchAllAlerts } from "../api/alerts";
|
||||
import { fetchAllIncidentEpisodes } from "../api/incidentEpisodes";
|
||||
import { fetchAllAlertEpisodes } from "../api/alertEpisodes";
|
||||
import type {
|
||||
ListResponse,
|
||||
IncidentItem,
|
||||
AlertItem,
|
||||
IncidentEpisodeItem,
|
||||
AlertEpisodeItem,
|
||||
} from "../api/types";
|
||||
|
||||
interface UseAllProjectCountsResult {
|
||||
incidentCount: number;
|
||||
alertCount: number;
|
||||
incidentEpisodeCount: number;
|
||||
alertEpisodeCount: number;
|
||||
isLoading: boolean;
|
||||
refetch: () => Promise<void>;
|
||||
}
|
||||
|
||||
export function useAllProjectCounts(): UseAllProjectCountsResult {
|
||||
const { projectList } = useProject();
|
||||
const enabled: boolean = projectList.length > 0;
|
||||
|
||||
const incidentQuery: UseQueryResult<
|
||||
ListResponse<IncidentItem>,
|
||||
Error
|
||||
> = useQuery({
|
||||
queryKey: ["incidents", "unresolved-count", "all-projects"],
|
||||
queryFn: () => {
|
||||
return fetchAllIncidents({
|
||||
skip: 0,
|
||||
limit: 1,
|
||||
unresolvedOnly: true,
|
||||
});
|
||||
},
|
||||
enabled,
|
||||
});
|
||||
|
||||
const alertQuery: UseQueryResult<ListResponse<AlertItem>, Error> = useQuery({
|
||||
queryKey: ["alerts", "unresolved-count", "all-projects"],
|
||||
queryFn: () => {
|
||||
return fetchAllAlerts({ skip: 0, limit: 1, unresolvedOnly: true });
|
||||
},
|
||||
enabled,
|
||||
});
|
||||
|
||||
const incidentEpisodeQuery: UseQueryResult<
|
||||
ListResponse<IncidentEpisodeItem>,
|
||||
Error
|
||||
> = useQuery({
|
||||
queryKey: ["incident-episodes", "unresolved-count", "all-projects"],
|
||||
queryFn: () => {
|
||||
return fetchAllIncidentEpisodes({
|
||||
skip: 0,
|
||||
limit: 1,
|
||||
unresolvedOnly: true,
|
||||
});
|
||||
},
|
||||
enabled,
|
||||
});
|
||||
|
||||
const alertEpisodeQuery: UseQueryResult<
|
||||
ListResponse<AlertEpisodeItem>,
|
||||
Error
|
||||
> = useQuery({
|
||||
queryKey: ["alert-episodes", "unresolved-count", "all-projects"],
|
||||
queryFn: () => {
|
||||
return fetchAllAlertEpisodes({
|
||||
skip: 0,
|
||||
limit: 1,
|
||||
unresolvedOnly: true,
|
||||
});
|
||||
},
|
||||
enabled,
|
||||
});
|
||||
|
||||
const isLoading: boolean =
|
||||
incidentQuery.isPending ||
|
||||
alertQuery.isPending ||
|
||||
incidentEpisodeQuery.isPending ||
|
||||
alertEpisodeQuery.isPending;
|
||||
|
||||
const refetch: () => Promise<void> = async (): Promise<void> => {
|
||||
await Promise.all([
|
||||
incidentQuery.refetch(),
|
||||
alertQuery.refetch(),
|
||||
incidentEpisodeQuery.refetch(),
|
||||
alertEpisodeQuery.refetch(),
|
||||
]);
|
||||
};
|
||||
|
||||
return {
|
||||
incidentCount: incidentQuery.data?.count ?? 0,
|
||||
alertCount: alertQuery.data?.count ?? 0,
|
||||
incidentEpisodeCount: incidentEpisodeQuery.data?.count ?? 0,
|
||||
alertEpisodeCount: alertEpisodeQuery.data?.count ?? 0,
|
||||
isLoading,
|
||||
refetch,
|
||||
};
|
||||
}
|
||||
69
MobileApp/src/hooks/useAllProjectIncidentEpisodes.ts
Normal file
69
MobileApp/src/hooks/useAllProjectIncidentEpisodes.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import { useMemo } from "react";
|
||||
import { useQuery, UseQueryResult } from "@tanstack/react-query";
|
||||
import { useProject } from "./useProject";
|
||||
import { fetchAllIncidentEpisodes } from "../api/incidentEpisodes";
|
||||
import type {
|
||||
ListResponse,
|
||||
IncidentEpisodeItem,
|
||||
ProjectIncidentEpisodeItem,
|
||||
ProjectItem,
|
||||
} from "../api/types";
|
||||
|
||||
const FETCH_LIMIT: number = 100;
|
||||
|
||||
interface UseAllProjectIncidentEpisodesResult {
|
||||
items: ProjectIncidentEpisodeItem[];
|
||||
isLoading: boolean;
|
||||
isError: boolean;
|
||||
refetch: () => Promise<void>;
|
||||
}
|
||||
|
||||
export function useAllProjectIncidentEpisodes(): UseAllProjectIncidentEpisodesResult {
|
||||
const { projectList } = useProject();
|
||||
|
||||
const query: UseQueryResult<
|
||||
ListResponse<IncidentEpisodeItem>,
|
||||
Error
|
||||
> = useQuery({
|
||||
queryKey: ["incident-episodes", "all-projects"],
|
||||
queryFn: () => {
|
||||
return fetchAllIncidentEpisodes({ skip: 0, limit: FETCH_LIMIT });
|
||||
},
|
||||
enabled: projectList.length > 0,
|
||||
});
|
||||
|
||||
const projectMap: Map<string, string> = useMemo(() => {
|
||||
const map: Map<string, string> = new Map();
|
||||
projectList.forEach((p: ProjectItem) => {
|
||||
map.set(p._id, p.name);
|
||||
});
|
||||
return map;
|
||||
}, [projectList]);
|
||||
|
||||
const items: ProjectIncidentEpisodeItem[] = useMemo(() => {
|
||||
if (!query.data) {
|
||||
return [];
|
||||
}
|
||||
return query.data.data.map(
|
||||
(item: IncidentEpisodeItem): ProjectIncidentEpisodeItem => {
|
||||
const pid: string = item.projectId ?? "";
|
||||
return {
|
||||
item,
|
||||
projectId: pid,
|
||||
projectName: projectMap.get(pid) ?? "",
|
||||
};
|
||||
},
|
||||
);
|
||||
}, [query.data, projectMap]);
|
||||
|
||||
const refetch: () => Promise<void> = async (): Promise<void> => {
|
||||
await query.refetch();
|
||||
};
|
||||
|
||||
return {
|
||||
items,
|
||||
isLoading: query.isPending,
|
||||
isError: query.isError,
|
||||
refetch,
|
||||
};
|
||||
}
|
||||
47
MobileApp/src/hooks/useAllProjectIncidentStates.ts
Normal file
47
MobileApp/src/hooks/useAllProjectIncidentStates.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { useMemo } from "react";
|
||||
import { useQueries, UseQueryResult } from "@tanstack/react-query";
|
||||
import { useProject } from "./useProject";
|
||||
import { fetchIncidentStates } from "../api/incidents";
|
||||
import type { IncidentState, ProjectItem } from "../api/types";
|
||||
|
||||
interface UseAllProjectIncidentStatesResult {
|
||||
statesMap: Map<string, IncidentState[]>;
|
||||
isLoading: boolean;
|
||||
}
|
||||
|
||||
export function useAllProjectIncidentStates(): UseAllProjectIncidentStatesResult {
|
||||
const { projectList } = useProject();
|
||||
|
||||
const queries: UseQueryResult<IncidentState[], Error>[] = useQueries({
|
||||
queries: projectList.map((project: ProjectItem) => {
|
||||
return {
|
||||
queryKey: ["incident-states", project._id],
|
||||
queryFn: () => {
|
||||
return fetchIncidentStates(project._id);
|
||||
},
|
||||
enabled: Boolean(project._id),
|
||||
};
|
||||
}),
|
||||
});
|
||||
|
||||
const isLoading: boolean = queries.some(
|
||||
(q: UseQueryResult<IncidentState[], Error>) => {
|
||||
return q.isLoading;
|
||||
},
|
||||
);
|
||||
|
||||
const statesMap: Map<string, IncidentState[]> = useMemo(() => {
|
||||
const map: Map<string, IncidentState[]> = new Map();
|
||||
queries.forEach(
|
||||
(q: UseQueryResult<IncidentState[], Error>, index: number) => {
|
||||
const project: ProjectItem | undefined = projectList[index];
|
||||
if (project && q.data) {
|
||||
map.set(project._id, q.data);
|
||||
}
|
||||
},
|
||||
);
|
||||
return map;
|
||||
}, [queries, projectList]);
|
||||
|
||||
return { statesMap, isLoading };
|
||||
}
|
||||
64
MobileApp/src/hooks/useAllProjectIncidents.ts
Normal file
64
MobileApp/src/hooks/useAllProjectIncidents.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import { useMemo } from "react";
|
||||
import { useQuery, UseQueryResult } from "@tanstack/react-query";
|
||||
import { useProject } from "./useProject";
|
||||
import { fetchAllIncidents } from "../api/incidents";
|
||||
import type {
|
||||
ListResponse,
|
||||
IncidentItem,
|
||||
ProjectIncidentItem,
|
||||
ProjectItem,
|
||||
} from "../api/types";
|
||||
|
||||
const FETCH_LIMIT: number = 100;
|
||||
|
||||
interface UseAllProjectIncidentsResult {
|
||||
items: ProjectIncidentItem[];
|
||||
isLoading: boolean;
|
||||
isError: boolean;
|
||||
refetch: () => Promise<void>;
|
||||
}
|
||||
|
||||
export function useAllProjectIncidents(): UseAllProjectIncidentsResult {
|
||||
const { projectList } = useProject();
|
||||
|
||||
const query: UseQueryResult<ListResponse<IncidentItem>, Error> = useQuery({
|
||||
queryKey: ["incidents", "all-projects"],
|
||||
queryFn: () => {
|
||||
return fetchAllIncidents({ skip: 0, limit: FETCH_LIMIT });
|
||||
},
|
||||
enabled: projectList.length > 0,
|
||||
});
|
||||
|
||||
const projectMap: Map<string, string> = useMemo(() => {
|
||||
const map: Map<string, string> = new Map();
|
||||
projectList.forEach((p: ProjectItem) => {
|
||||
map.set(p._id, p.name);
|
||||
});
|
||||
return map;
|
||||
}, [projectList]);
|
||||
|
||||
const items: ProjectIncidentItem[] = useMemo(() => {
|
||||
if (!query.data) {
|
||||
return [];
|
||||
}
|
||||
return query.data.data.map((item: IncidentItem): ProjectIncidentItem => {
|
||||
const pid: string = item.projectId ?? "";
|
||||
return {
|
||||
item,
|
||||
projectId: pid,
|
||||
projectName: projectMap.get(pid) ?? "",
|
||||
};
|
||||
});
|
||||
}, [query.data, projectMap]);
|
||||
|
||||
const refetch: () => Promise<void> = async (): Promise<void> => {
|
||||
await query.refetch();
|
||||
};
|
||||
|
||||
return {
|
||||
items,
|
||||
isLoading: query.isPending,
|
||||
isError: query.isError,
|
||||
refetch,
|
||||
};
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user