PCORE-2143: Showing incidents for each service (#30)

* feat: added incidents for each service

* feat: fixed linting

* feat: fixed linting

* feat: fixed linting

* fix: style changes

* fix: removed commented code

* fix: removed commented code and issue summary
pull/1113/head
Smit Patel 2022-08-10 12:35:15 +05:30 committed by GitHub
parent 609796d782
commit b86b998808
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 317 additions and 284 deletions

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="col-12 mb-3 pb-2 border-bottom" role="alert"> <div class="col-12 mb-3 pb-2 border-bottom" role="alert">
<span class="font-weight-bold text-capitalize" :class="{'text-success': update.type.toLowerCase()==='resolved', 'text-danger': update.type.toLowerCase()==='investigating', 'text-warning': update.type.toLowerCase()==='update'}">{{update.type}}</span> <span class="font-weight-bold text-capitalize" :class="{'text-success': update.type.toLowerCase()==='resolved', 'text-danger': update.type.toLowerCase()==='issue summary', 'text-warning': update.type.toLowerCase()==='update'}">{{update.type}}</span>
<span class="text-muted">- {{update.message}} <span class="text-muted">- {{update.message}}
<button v-if="admin" @click="delete_update(update)" type="button" class="close"> <button v-if="admin" @click="delete_update(update)" type="button" class="close">
<span aria-hidden="true">&times;</span> <span aria-hidden="true">&times;</span>

View File

@ -41,7 +41,7 @@ export default {
return "badge-success" return "badge-success"
case "update": case "update":
return "badge-info" return "badge-info"
case "investigating": case "issue summary":
return "badge-danger" return "badge-danger"
} }
}, },

View File

@ -12,9 +12,8 @@
<form class="row" @submit.prevent="createIncidentUpdate"> <form class="row" @submit.prevent="createIncidentUpdate">
<div class="col-12 col-md-3 mb-3 mb-md-0"> <div class="col-12 col-md-3 mb-3 mb-md-0">
<select v-model="incident_update.type" class="form-control"> <select v-model="incident_update.type" class="form-control">
<option value="Investigating">Investigating</option> <option value="Issue summary">Issue summary</option>
<option value="Update">Update</option> <option value="Update">Update</option>
<option value="Unknown">Unknown</option>
<option value="Resolved">Resolved</option> <option value="Resolved">Resolved</option>
</select> </select>
</div> </div>
@ -53,7 +52,7 @@
incident_update: { incident_update: {
incident: this.incident.id, incident: this.incident.id,
message: "", message: "",
type: "Investigating" // TODO: default to something.. theres is no error checking for blank submission... type: "Issue summary"
} }
} }
}, },
@ -74,7 +73,7 @@
this.incident_update = { this.incident_update = {
incident: this.incident.id, incident: this.incident.id,
message: "", message: "",
type: "Investigating" type: "Issue summary"
} }
}, },

View File

@ -1,5 +1,4 @@
import React from "react"; import React from "react";
// import { groups } from "../utils/data";
import GroupItem from "./GroupItem"; import GroupItem from "./GroupItem";
import { isObject, isObjectEmpty } from "../utils/helper"; import { isObject, isObjectEmpty } from "../utils/helper";
@ -17,9 +16,6 @@ function showPlus(service) {
} }
const Group = ({ services }) => { const Group = ({ services }) => {
// const data = groups.sort((a, b) => a.order_id - b.order_id);
// if (!data.length > 0) return <></>;
return ( return (
<div className="list-group"> <div className="list-group">
{services?.map((service) => { {services?.map((service) => {

View File

@ -8,6 +8,7 @@ import GroupServiceFailures from "./GroupServiceFailures";
import SubServiceCard from "./SubServiceCard"; import SubServiceCard from "./SubServiceCard";
import infoIcon from "../static/info.svg"; import infoIcon from "../static/info.svg";
import { analyticsTrack } from "../utils/trackers"; import { analyticsTrack } from "../utils/trackers";
import IncidentsBlock from "./IncidentsBlock";
const GroupItem = ({ service, showPlusButton }) => { const GroupItem = ({ service, showPlusButton }) => {
const [collapse, setCollapse] = useState(false); const [collapse, setCollapse] = useState(false);
@ -39,26 +40,26 @@ const GroupItem = ({ service, showPlusButton }) => {
} }
analyticsTrack({ analyticsTrack({
objectName: 'Service Expand', objectName: "Service Expand",
actionName: 'clicked', actionName: "clicked",
screen: 'Home page', screen: "Home page",
properties:{ properties: {
serviceName: event.target.name, serviceName: event.target.name,
} },
}) });
}; };
const closeCollapse = (event) => { const closeCollapse = (event) => {
setCollapse(false); setCollapse(false);
analyticsTrack({ analyticsTrack({
objectName: 'Service Collapse', objectName: "Service Collapse",
actionName: 'clicked', actionName: "clicked",
screen: 'Home page', screen: "Home page",
properties:{ properties: {
serviceName: event.target.name, serviceName: event.target.name,
} },
}) });
}; };
const handleMouseOver = (service) => { const handleMouseOver = (service) => {
@ -68,28 +69,31 @@ const GroupItem = ({ service, showPlusButton }) => {
const handleMouseOut = () => setHoverText(""); const handleMouseOut = () => setHoverText("");
return ( return (
<div className="service-card service_item card-bg pb-0"> <div className="service-parent service-card service_item card-bg">
{/** TODO: change span to navlink */} {/** TODO: change span to navlink */}
<div className="service_item--header mb-3"> <div className="service_item--header mb-3">
<div className="service_item--right"> <div className="service_item--right">
{!loading && showPlusButton && ( {!loading && showPlusButton && (
<> <>
{collapse ? ( {collapse ? (
<button className="square-minus" name={service.name} onClick={closeCollapse} /> <button
className="square-minus"
name={service.name}
onClick={closeCollapse}
/>
) : ( ) : (
<button className="square-plus" name={service.name} onClick={openCollapse} /> <button
className="square-plus"
name={service.name}
onClick={openCollapse}
/>
)} )}
</> </>
)} )}
{loading && <FontAwesomeIcon icon={faCircleNotch} spin />} {loading && <FontAwesomeIcon icon={faCircleNotch} spin />}
<span <span className="subtitle no-decoration mr-1">{service.name}</span>
className="subtitle no-decoration font-14 mr-1"
// to="/service/1"
>
{service.name}
</span>
{service?.description && ( {service?.description && (
<> <>
<ReactTooltip <ReactTooltip
@ -110,89 +114,44 @@ const GroupItem = ({ service, showPlusButton }) => {
</> </>
)} )}
</div> </div>
<div className="service_item--left"> {!collapse && (
<span <div className="service_item--left">
className={`badge float-right font-12 ${ <span
service.online ? "uptime" : "downtime" className={`badge float-right font-12 ${
}`} service.online ? "uptime" : "downtime"
style={{ display: collapse ? "none" : "block" }} }`}>
> {service.online ? langs("online") : langs("offline")}
{service.online ? langs("online") : langs("offline")} </span>
</span> </div>
</div>
</div>
<GroupServiceFailures service={service} collapse={collapse} />
{/*<IncidentsBlock service={service} /> */}
<div
className="list-group online_list"
style={{ display: collapse ? "block" : "none" }}
>
{subServices && subServices?.length > 0 ? (
subServices.map((sub_service, i) => {
return (
<SubServiceCard
key={i}
group={service}
service={sub_service}
collapse={collapse}
/>
);
})
) : (
<div className="subtitle text-align-center">No Services</div>
)} )}
</div> </div>
{!collapse && (
<GroupServiceFailures service={service} collapse={collapse} />
)}
{!collapse && <IncidentsBlock service={service} />}
{collapse && (
<div className="sub-service-wrapper list-group online_list">
{subServices && subServices?.length > 0 ? (
subServices.map((sub_service, i) => {
return (
<SubServiceCard
key={i}
group={service}
service={sub_service}
collapse={collapse}
/>
);
})
) : (
<div className="subtitle text-align-center">No Services</div>
)}
</div>
)}
</div> </div>
); );
}; };
export default React.memo(GroupItem); export default React.memo(GroupItem);
// import React from "react";
// import langs from "../config/langs";
// import { services } from "../data";
// import GroupServiceFailures from "./GroupServiceFailures";
// import IncidentsBlock from "./IncidentsBlock";
// // import DateUtils from "../utils/DateUtils";
// const GroupItem = ({ group }) => {
// const groupServices = services
// .filter((s) => s.group_id === group.id)
// .sort((a, b) => a.order_id - b.order_id);
// if (!groupServices.length > 0) return null;
// return (
// <div className="col-12 full-col-12">
// {group.name !== "Empty Group" && (
// <h4 className="group_header mb-3 mt-4">{group.name}</h4>
// )}
// <div className="list-group online_list mb-4">
// {groupServices.map((service, i) => {
// return (
// <div key={i} className="service-card service-card-action">
// <span
// className="no-decoration font-3"
// // to={DateUtils.serviceLink(service)}
// >
// {service.name}
// </span>
// <span
// className={`badge text-uppercase float-right ${
// service.online ? "bg-success" : "bg-danger"
// }`}
// >
// {service.online ? langs("online") : langs("offline")}
// </span>
// <GroupServiceFailures service={service} />
// <IncidentsBlock service={service} />
// </div>
// );
// })}
// </div>
// </div>
// );
// };
// export default GroupItem;

View File

@ -57,12 +57,6 @@ async function fetchFailureSeries(url) {
} }
const GroupServiceFailures = ({ group = null, service, collapse }) => { const GroupServiceFailures = ({ group = null, service, collapse }) => {
// const [containerRef, isVisible] = useIntersectionObserver({
// root: null,
// rootMargin: "0px",
// threshold: 1.0,
// });
const [hoverText, setHoverText] = useState(""); const [hoverText, setHoverText] = useState("");
const [loaded, setLoaded] = useState(true); const [loaded, setLoaded] = useState(true);
const [failureData, setFailureData] = useState([]); const [failureData, setFailureData] = useState([]);
@ -98,7 +92,7 @@ const GroupServiceFailures = ({ group = null, service, collapse }) => {
} }
} }
fetchData(); fetchData();
}, [service]); }, [service, group]);
const handleTooltip = (d) => { const handleTooltip = (d) => {
let txt = ""; let txt = "";
@ -133,7 +127,6 @@ const GroupServiceFailures = ({ group = null, service, collapse }) => {
if (loaded) return <ServiceLoader text="Loading series.." />; if (loaded) return <ServiceLoader text="Loading series.." />;
return ( return (
// transition div
<div name="fade" style={{ display: collapse ? "none" : "block" }}> <div name="fade" style={{ display: collapse ? "none" : "block" }}>
<div className="block-chart"> <div className="block-chart">
<ReactTooltip <ReactTooltip
@ -150,8 +143,7 @@ const GroupServiceFailures = ({ group = null, service, collapse }) => {
onMouseOver={() => handleMouseOver(d)} onMouseOver={() => handleMouseOver(d)}
onMouseOut={handleMouseOut} onMouseOut={handleMouseOut}
key={i} key={i}
data-tip={hoverText} data-tip={hoverText}>
>
{d.status !== 0 && ( {d.status !== 0 && (
<span className="d-none d-md-block text-center small"></span> <span className="d-none d-md-block text-center small"></span>
)} )}

View File

@ -16,32 +16,31 @@ const IncidentUpdate = ({ update, admin }) => {
}; };
return ( return (
<div className="col-12 mb-3 pb-2 border-bottom" role="alert"> <div className="incident-wrapper mb-3 pb-2 d-flex" role="alert">
<span <div className="time-line mr-2">
className={` <span class="dot"></span>
font-weight-bold text-capitalize </div>
${update.type.toLowerCase() === "resolved" ? "text-success" : ""}
${update.type.toLowerCase() === "investigating" ? "text-danger" : ""} <div>
${update.type.toLowerCase() === "update" ? "text-warning" : ""} <span className="font-14">
`} {update.message}
> {admin && (
{update.type} <button
</span> onClick={deleteUpdate(update)}
<span className="text-muted"> type="button"
- {update.message} className="close">
{admin && ( <span aria-hidden="true">&times;</span>
<button </button>
onClick={deleteUpdate(update)} )}
type="button" </span>
className="close" <span className="d-block small text-muted">
> Posted {DateUtils.ago(update.created_at)} ago.{" "}
<span aria-hidden="true">&times;</span> {DateUtils.format(
</button> DateUtils.parseISO(update.created_at),
)} "MMM d, yyyy - HH:mm"
</span> )}
<span className="d-block small"> </span>
{DateUtils.ago(update.created_at)} ago </div>
</span>
</div> </div>
); );
}; };

View File

@ -3,36 +3,96 @@ import API from "../config/API";
import DateUtils from "../utils/DateUtils"; import DateUtils from "../utils/DateUtils";
import IncidentUpdate from "./IncidentUpdate"; import IncidentUpdate from "./IncidentUpdate";
const IncidentsBlock = ({ service }) => { const IncidentsBlock = ({ service, group }) => {
const [incidents, setIncidents] = useState([]); const [incidents, setIncidents] = useState([]);
const [incidentsShow, setIncidentsShow] = useState(false);
useEffect(() => { useEffect(() => {
async function fetchData() { async function fetchData() {
const data = await API.incidents_service(service.id); let data = [];
setIncidents(data);
if (group?.id) {
data = await API.sub_incidents_service(group.id, service.id);
} else {
data = await API.incidents_service(service.id);
}
setIncidents(data || []);
} }
fetchData(); fetchData();
}, [service.id]); }, [service.id, group?.id]);
const handleIncidentShow = (event) => {
const { id } = event.target;
setIncidentsShow({ ...incidentsShow, [id]: !incidentsShow[id] });
};
return ( return (
<div className="row"> <div className="incidents-wrapper row">
{incidents?.map((incident, i) => { <div className="col-12 mt-2">
return ( {incidents?.length > 0 ? (
<div className="col-12 mt-2" key={i}> incidents?.map((incident) => {
<span className="braker mt-1 mb-3"></span> const { id, title, description, updated_at } = incident;
<h6>
{incident.title} return (
<span className="font-2 float-right"> <>
{DateUtils.niceDate(incident.created_at)} <span className="braker mt-1 mb-3"></span>
</span> <div
</h6> className={`incident-title col-12 ${
<div className="font-2 mb-3" v-html="incident.description"></div> incidentsShow[id] && "mb-3"
{incident.updates.map((update, i) => { }`}>
return <IncidentUpdate key={i} update={update} admin={false} />; {incidentsShow[id] ? (
})} <button
className="square-minus"
type="button"
id={id}
onClick={handleIncidentShow}
/>
) : (
<button
className="square-plus"
type="button"
id={id}
onClick={handleIncidentShow}
/>
)}
<div className="title-wrapper">
<span class="subtitle no-decoration">{title}</span>
<span className="d-block small text-dark">
{description}
</span>
<span className="d-block small text-muted">
Updated {DateUtils.ago(updated_at)} ago.{" "}
{DateUtils.format(
DateUtils.parseISO(updated_at),
"MMM d, yyyy - HH:mm"
)}
</span>
</div>
</div>
{incidentsShow[id] && (
<div className="incident-updates-wrapper col-12">
{incident?.updates.map((update) => {
return (
<IncidentUpdate
key={update.id}
update={update}
admin={false}
/>
);
})}
</div>
)}
</>
);
})
) : (
<div className="col-12">
<span class="font-14 text-muted">No recent incidents</span>
</div> </div>
); )}
})} </div>
</div> </div>
); );
}; };

View File

@ -1,36 +1,26 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
// import { NavLink } from "react-router-dom";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import DateUtils from "../utils/DateUtils";
import Group from "./Group"; import Group from "./Group";
import ContentHeader from "./ContentHeader"; import ContentHeader from "./ContentHeader";
import ServiceLoader from "./ServiceLoader"; import ServiceLoader from "./ServiceLoader";
// import IncidentService from "./IncidentService";
// import MessageBlock from "./MessageBlock";
// import ServiceBlock from "./ServiceBlock";
// import ServicesList from "./ServicesList";
import API from "../config/API"; import API from "../config/API";
import { STATUS_COLOR, STATUS_ICON, STATUS_TEXT } from "../utils/constants";
import { findStatus } from "../utils/helper"; import { findStatus } from "../utils/helper";
import { analyticsTrack } from "../utils/trackers"; import { analyticsTrack } from "../utils/trackers";
const ServicesPage = () => { const ServicesPage = () => {
// const data = messages.filter((m) => inRange(m) && m.service === 0);
const [services, setServices] = useState([]); const [services, setServices] = useState([]);
const [status, setStatus] = useState("uptime"); const [status, setStatus] = useState("uptime");
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [poll, setPolling] = useState(1); const [poll, setPolling] = useState(1);
const today = DateUtils.format(new Date(), "d MMMM yyyy, hh:mm aaa");
useEffect(() => { useEffect(() => {
if(!loading) { if (!loading) {
analyticsTrack({ analyticsTrack({
objectName: 'Status Page', objectName: "Status Page",
actionName: 'displayed', actionName: "displayed",
screen: 'Home page' screen: "Home page",
}) });
} }
}, [loading]) }, [loading]);
useEffect(() => { useEffect(() => {
const timer = setInterval(() => { const timer = setInterval(() => {
@ -59,47 +49,20 @@ const ServicesPage = () => {
return ( return (
<div className="container col-md-7 col-sm-12 sm-container"> <div className="container col-md-7 col-sm-12 sm-container">
<ContentHeader /> <ContentHeader />
<div className="app-content"> <div className="app-content">
<div className="service"> <div className="service">
<h2 className="title font-20 fw-700">Razorpay Payments</h2> <h2 className="title font-20 fw-700">Razorpay Payments</h2>
<div className="d-flex align-items-center subtitle font-12 mt-2">
<FontAwesomeIcon
icon={STATUS_ICON[status]}
style={{
fontSize: "16px",
color: STATUS_COLOR[status],
}}
/>
<span className="mx-1">{STATUS_TEXT[status]}</span>
</div>
<div>
<span className="date font-12">{today}</span>
</div>
</div> </div>
{loading && <ServiceLoader text="Loading Services" />} {loading && <ServiceLoader text="Loading Services" />}
{/* <ServicesList loading={loading} services={services} /> */}
{/* TODO --> Grouped Services to Accordian*/}
{services && services.length > 0 ? ( {services && services.length > 0 ? (
<Group services={services} /> <Group services={services} />
) : ( ) : (
<div className="description text-align-center">No Services</div> <div className="description text-align-center">No Services</div>
)} )}
{/* <div>
{data.map((message) => {
return <MessageBlock key={message.id} message={message} />;
})}
</div>
<div>
{services.map((service) => {
return <ServiceBlock key={service.id} service={service} />;
})}
</div> */}
<div className="app-footer"> <div className="app-footer">
<div className="service-status"> <div className="service-status">
<span className="service-status-badge uptime"></span> <span className="service-status-badge uptime"></span>

View File

@ -2,7 +2,7 @@ import React, { useState } from "react";
import ReactTooltip from "react-tooltip"; import ReactTooltip from "react-tooltip";
import langs from "../config/langs"; import langs from "../config/langs";
import GroupServiceFailures from "./GroupServiceFailures"; import GroupServiceFailures from "./GroupServiceFailures";
// import IncidentsBlock from "./IncidentsBlock"; import IncidentsBlock from "./IncidentsBlock";
import infoIcon from "../static/info.svg"; import infoIcon from "../static/info.svg";
const SubServiceCard = ({ group, service }) => { const SubServiceCard = ({ group, service }) => {
@ -50,15 +50,14 @@ const SubServiceCard = ({ group, service }) => {
<span <span
className={`badge float-right font-12 ${ className={`badge float-right font-12 ${
service.online ? "status-green" : "status-red" service.online ? "status-green" : "status-red"
}`} }`}>
>
{service.online ? langs("online") : langs("offline")} {service.online ? langs("online") : langs("offline")}
</span> </span>
</div> </div>
</div> </div>
<GroupServiceFailures group={group} service={service} /> <GroupServiceFailures group={group} service={service} />
{/* <IncidentsBlock service={service} /> */} <IncidentsBlock group={group} service={service} />
</div> </div>
); );
}; };

View File

@ -213,10 +213,15 @@ class Api {
} }
async incidents_service(id) { async incidents_service(id) {
return incidents[id]; return axios
// return axios .get("/services/" + id + "/active_incidents")
// .get("api/services/" + id + "/incidents") .then((response) => response.data);
// .then((response) => response.data); }
async sub_incidents_service(id, sub_id) {
return axios
.get(`/services/${id}/sub_services/${sub_id}/active_incidents`)
.then((response) => response.data);
} }
async incident_create(service_id, data) { async incident_create(service_id, data) {

View File

@ -13,6 +13,48 @@ a {
color: $text-color; color: $text-color;
} }
.dot {
height: 8px;
width: 8px;
background-color: #bbb;
border-radius: 50%;
display: inline-block;
}
.square-plus,
.square-minus {
color: $blue;
border: 2px solid $blue;
border-radius: 2px;
width: 14px;
height: 14px;
font-size: 8px;
margin-right: 5px;
position: relative;
background-color: $white;
outline: none;
padding: 0;
cursor: pointer;
&:after {
font-size: 12px;
line-height: 10px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-weight: bold;
}
}
.square-plus:after {
content: "+";
}
.square-minus:after {
content: "-";
}
.app-layout { .app-layout {
background: $primary-bg; background: $primary-bg;
min-width: 100vw; min-width: 100vw;
@ -116,25 +158,73 @@ a {
transition-duration: 300ms; transition-duration: 300ms;
} }
.service-card { .list-group .service-parent {
position: relative; border-radius: 4px;
min-height: 130px; margin-bottom: 1rem;
padding: 1.25rem 0;
background-color: $white;
border: 1px solid #eff2f7; border: 1px solid #eff2f7;
border-bottom-width: 0;
overflow: hidden; .sub-service-wrapper {
border-top: 1px solid #eff2f7;
.service-card {
&:last-child {
padding-bottom: 0;
}
}
}
} }
.list-group .service-card:first-child { .service-card {
border-top-left-radius: 4px; position: relative;
border-top-right-radius: 4px; padding: 1.25rem 0;
background-color: $white;
overflow: hidden;
&:not(:last-child) {
border-bottom: 1px solid #eff2f7;
}
.incidents-wrapper {
.incident-title {
display: flex;
.title-wrapper {
flex: 1;
}
.square-plus,
.square-minus {
top: 5px;
}
}
.incident-updates-wrapper {
margin-left: 3px;
.incident-wrapper {
position: relative;
margin-right: 3px;
&:not(:last-child):after {
content: "";
height: 100%;
width: 1px;
top: 21px;
left: 3px;
background-color: #bbb;
position: absolute;
}
&:last-child {
margin-bottom: 0 !important;
}
}
}
}
} }
.list-group .service-card:last-child { .list-group .service-card:last-child {
border-bottom-right-radius: 4px; margin-bottom: 0;
border-bottom-left-radius: 4px;
border-bottom-width: 1px;
} }
.service-card a { .service-card a {
@ -157,40 +247,6 @@ a {
&--right { &--right {
display: flex; display: flex;
align-items: center; align-items: center;
.square-plus,
.square-minus {
color: $blue;
border: 2px solid $blue;
border-radius: 2px;
width: 14px;
height: 14px;
font-size: 8px;
margin-right: 5px;
position: relative;
background-color: $white;
outline: none;
padding: 0;
cursor: pointer;
&:after {
font-size: 12px;
line-height: 10px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-weight: bold;
}
}
.square-plus:after {
content: "+";
}
.square-minus:after {
content: "-";
}
} }
} }
@ -353,10 +409,12 @@ a {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
flex-wrap: wrap;
gap: 10px 15px;
.service-status { .service-status {
display: flex; display: flex;
align-items: center; align-items: center;
margin-right: 1.875rem;
&-badge { &-badge {
width: 0.75rem; width: 0.75rem;

View File

@ -1,5 +1,3 @@
// import DateUtils from "./DateUtils";
export function findStatus(data) { export function findStatus(data) {
if (!Array.isArray(data)) return null; if (!Array.isArray(data)) return null;
if (data.length === 0) return null; if (data.length === 0) return null;
@ -12,15 +10,18 @@ export function findStatus(data) {
return ""; return "";
} }
// export function inRange(message) { export function getIncidentTextType(type) {
// return DateUtils.isBetween( switch (type.toLowerCase()) {
// DateUtils.now(), case "resolved":
// message.start_on, return "text-success";
// message.start_on === message.end_on case "issue summary":
// ? DateUtils.maxDate().toISOString() return "text-danger";
// : message.end_on case "update":
// ); return "text-warning";
// } default:
return "";
}
}
export const isObject = (obj) => { export const isObject = (obj) => {
if (Object.prototype.toString.call(obj) === "[object Object]") { if (Object.prototype.toString.call(obj) === "[object Object]") {
@ -59,13 +60,15 @@ export const calcPer = (uptime, downtime) => {
// } // }
export const setUerId = (id) => { export const setUerId = (id) => {
localStorage.setItem('stat_user_id',id); localStorage.setItem("stat_user_id", id);
} };
export const getUserId = () => { export const getUserId = () => {
return localStorage.getItem('stat_user_id'); return localStorage.getItem("stat_user_id");
} };
export const generateUUID = (length) => { export const generateUUID = (length) => {
return Array.from(Array(length), () => Math.floor(Math.random() * 36).toString(36)).join('') return Array.from(Array(length), () =>
} Math.floor(Math.random() * 36).toString(36)
).join("");
};