review changes
This commit is contained in:
parent
9a317edf17
commit
407b2f6904
|
@ -1,4 +1,4 @@
|
||||||
# Microsoft 365 Services Health
|
# Service Health for Microsoft 365
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
|
@ -38,7 +38,18 @@ For more information about SPFx compatibility, please refer to <https://aka.ms/s
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
> Any special pre-requisites?
|
- SharePoint Online tenant
|
||||||
|
- You have to provide permission in SharePoint admin for accessing Graph API on behalf of your solution. You can do it before deployment as proactive steps, or after deployment. You can refer to [steps about how to do this post-deployment](https://learn.microsoft.com/sharepoint/dev/spfx/use-aad-tutorial#deploy-the-solution-and-grant-permissions). You have to use API Access Page of SharePoint admin and add below permission for our use case.
|
||||||
|
|
||||||
|
```
|
||||||
|
"webApiPermissionRequests": [
|
||||||
|
{
|
||||||
|
"resource": "Microsoft Graph",
|
||||||
|
"scope": "ServiceHealth.Read.All"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
## Contributors
|
## Contributors
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,12 @@
|
||||||
{
|
{
|
||||||
"name": "pnp-sp-dev-spfx-web-parts-react-m365-services-health",
|
"name": "pnp-sp-dev-spfx-web-parts-react-m365-services-health",
|
||||||
"source": "pnp",
|
"source": "pnp",
|
||||||
"title": "Microsoft 365 Services Health",
|
"title": "Service Health for Microsoft 365",
|
||||||
"shortDescription": "M365 Services Health solution show the health status for all the Microsoft 365 services",
|
"shortDescription": "Service Health for Microsoft 365 solution show the health status for all the Microsoft 365 services",
|
||||||
"url": "https://github.com/pnp/sp-dev-fx-webparts/tree/main/samples/react-m365-services-health",
|
"url": "https://github.com/pnp/sp-dev-fx-webparts/tree/main/samples/react-m365-services-health",
|
||||||
"downloadUrl": "https://pnp.github.io/download-partial/?url=https://github.com/pnp/sp-dev-fx-webparts/tree/main/samples/react-m365-services-health",
|
"downloadUrl": "https://pnp.github.io/download-partial/?url=https://github.com/pnp/sp-dev-fx-webparts/tree/main/samples/react-m365-services-health",
|
||||||
"longDescription": [
|
"longDescription": [
|
||||||
"M365 Services Health solution show the health status for all the M365 services"
|
"Service Health for Microsoft 365 solution show the health status for all the M365 services"
|
||||||
],
|
],
|
||||||
"creationDateTime": "2023-02-03",
|
"creationDateTime": "2023-02-03",
|
||||||
"updateDateTime": "2023-02-03",
|
"updateDateTime": "2023-02-03",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
|
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
|
||||||
"solution": {
|
"solution": {
|
||||||
"name": "M365 Services Health",
|
"name": "Service Health for Microsoft 365",
|
||||||
"id": "f4d4b329-f1c6-49c9-a2fa-12a9816ac717",
|
"id": "f4d4b329-f1c6-49c9-a2fa-12a9816ac717",
|
||||||
"version": "1.0.0.0",
|
"version": "1.0.0.0",
|
||||||
"includeClientSideAssets": true,
|
"includeClientSideAssets": true,
|
||||||
|
@ -22,10 +22,10 @@
|
||||||
],
|
],
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"shortDescription": {
|
"shortDescription": {
|
||||||
"default": "M365 Services health"
|
"default": "Service Health for Microsoft 365"
|
||||||
},
|
},
|
||||||
"longDescription": {
|
"longDescription": {
|
||||||
"default": "M365 Services health"
|
"default": "Service Health for Microsoft 365"
|
||||||
},
|
},
|
||||||
"screenshotPaths": [],
|
"screenshotPaths": [],
|
||||||
"videoUrl": "",
|
"videoUrl": "",
|
||||||
|
@ -34,7 +34,7 @@
|
||||||
},
|
},
|
||||||
"features": [
|
"features": [
|
||||||
{
|
{
|
||||||
"title": "M365 Services Health Feature",
|
"title": "Service Health for Microsoft 365 Feature",
|
||||||
"description": "The feature that activates elements of the react-m-365-services-health solution.",
|
"description": "The feature that activates elements of the react-m-365-services-health solution.",
|
||||||
"id": "9d9e7584-45be-4df4-8023-5c271402cf87",
|
"id": "9d9e7584-45be-4df4-8023-5c271402cf87",
|
||||||
"version": "1.0.0.0"
|
"version": "1.0.0.0"
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { ServiceHealth } from "@microsoft/microsoft-graph-types";
|
||||||
import { MSGraphClientV3, GraphRequest } from "@microsoft/sp-http-msgraph";
|
import { MSGraphClientV3, GraphRequest } from "@microsoft/sp-http-msgraph";
|
||||||
import { WebPartContext } from "@microsoft/sp-webpart-base";
|
import { WebPartContext } from "@microsoft/sp-webpart-base";
|
||||||
|
|
||||||
|
@ -12,11 +13,10 @@ export class GraphService {
|
||||||
return await this.context.msGraphClientFactory.getClient("3");
|
return await this.context.msGraphClientFactory.getClient("3");
|
||||||
};
|
};
|
||||||
|
|
||||||
public getHealthOverviews = async (): Promise<any> => {
|
public getHealthOverviews = async (): Promise<ServiceHealth[]> => {
|
||||||
const client = await this.getClient();
|
const client = await this.getClient();
|
||||||
const request: GraphRequest = client.api("/admin/serviceAnnouncement/healthOverviews");
|
const request: GraphRequest = client.api("/admin/serviceAnnouncement/healthOverviews");
|
||||||
|
|
||||||
const response = await request.expand("issues").get();
|
const response = await request.expand("issues").get();
|
||||||
return Promise.resolve(response.value);
|
return Promise.resolve(response.value as ServiceHealth[]);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,93 +1,91 @@
|
||||||
export namespace HelperService {
|
export const getFormattedDateTime = (value: string): string => {
|
||||||
export const getFormattedDateTime = (value: string): string => {
|
const date = new Date(value);
|
||||||
const date = new Date(value);
|
const dateString = date.toLocaleDateString("en-US", {
|
||||||
const dateString = date.toLocaleDateString("en-US", {
|
month: "long",
|
||||||
month: "long",
|
day: "numeric",
|
||||||
day: "numeric",
|
year: "numeric",
|
||||||
year: "numeric",
|
});
|
||||||
});
|
const timeString = date.toLocaleTimeString("en-US", {
|
||||||
const timeString = date.toLocaleTimeString("en-US", {
|
hour: "numeric",
|
||||||
hour: "numeric",
|
minute: "numeric",
|
||||||
minute: "numeric",
|
hour12: true,
|
||||||
hour12: true,
|
});
|
||||||
});
|
return `${dateString} ${timeString}`;
|
||||||
return `${dateString} ${timeString}`;
|
};
|
||||||
};
|
|
||||||
|
|
||||||
export const getProductIcon = (value: string): string => {
|
export const getProductIcon = (value: string): string => {
|
||||||
let icon: string = "Product";
|
let icon: string = "Product";
|
||||||
switch (value?.toLowerCase()) {
|
switch (value?.toLowerCase()) {
|
||||||
case "microsoft intune":
|
case "microsoft intune":
|
||||||
case "mobile device management for office 365":
|
case "mobile device management for office 365":
|
||||||
case "identity service":
|
case "identity service":
|
||||||
case "microsoft 365 apps":
|
case "microsoft 365 apps":
|
||||||
case "microsoft 365 defender":
|
case "microsoft 365 defender":
|
||||||
case "microsoft 365 for the web":
|
case "microsoft 365 for the web":
|
||||||
case "microsoft mefender for cloud apps":
|
case "microsoft defender for cloud apps":
|
||||||
case "privileged access":
|
case "privileged access":
|
||||||
icon = "Product";
|
icon = "Product";
|
||||||
break;
|
break;
|
||||||
case "exchange online":
|
case "exchange online":
|
||||||
icon = "ExchangeLogo";
|
icon = "ExchangeLogo";
|
||||||
break;
|
break;
|
||||||
case "microsoft 365 suite":
|
case "microsoft 365 suite":
|
||||||
icon = "AdminALogoInverse32";
|
icon = "AdminALogoInverse32";
|
||||||
break;
|
break;
|
||||||
case "microsoft teams":
|
case "microsoft teams":
|
||||||
icon = "TeamsLogo";
|
icon = "TeamsLogo";
|
||||||
break;
|
break;
|
||||||
case "sharepoint online":
|
case "sharepoint online":
|
||||||
case "microsoft viva":
|
case "microsoft viva":
|
||||||
icon = "SharepointLogo";
|
icon = "SharepointLogo";
|
||||||
break;
|
break;
|
||||||
case "azure information protection":
|
case "azure information protection":
|
||||||
icon = "AzureLogo";
|
icon = "AzureLogo";
|
||||||
break;
|
break;
|
||||||
case "dynamics 365 apps":
|
case "dynamics 365 apps":
|
||||||
icon = "Dynamics365Logo";
|
icon = "Dynamics365Logo";
|
||||||
break;
|
break;
|
||||||
case "microsoft bookings":
|
case "microsoft bookings":
|
||||||
icon = "BookingsLogo";
|
icon = "BookingsLogo";
|
||||||
break;
|
break;
|
||||||
case "microsoft forms":
|
case "microsoft forms":
|
||||||
icon = "OfficeFormsLogo";
|
icon = "OfficeFormsLogo";
|
||||||
break;
|
break;
|
||||||
case "microsoft power automate":
|
case "microsoft power automate":
|
||||||
case "microsoft power automate in microsoft 365":
|
case "microsoft power automate in microsoft 365":
|
||||||
icon = "MicrosoftFlowLogo";
|
icon = "MicrosoftFlowLogo";
|
||||||
break;
|
break;
|
||||||
case "microsoft staffHub":
|
case "microsoft staffHub":
|
||||||
icon = "MicrosoftStaffhubLogo";
|
icon = "MicrosoftStaffhubLogo";
|
||||||
break;
|
break;
|
||||||
case "microsoft stream":
|
case "microsoft stream":
|
||||||
icon = "StreamLogo";
|
icon = "StreamLogo";
|
||||||
break;
|
break;
|
||||||
case "onedrive for business":
|
case "onedrive for business":
|
||||||
icon = "OneDriveLogo";
|
icon = "OneDriveLogo";
|
||||||
break;
|
break;
|
||||||
case "planner":
|
case "planner":
|
||||||
icon = "PlannerLogo";
|
icon = "PlannerLogo";
|
||||||
break;
|
break;
|
||||||
case "power apps":
|
case "power apps":
|
||||||
case "power apps in microsoft 365":
|
case "power apps in microsoft 365":
|
||||||
icon = "PowerAppsLogo";
|
icon = "PowerAppsLogo";
|
||||||
break;
|
break;
|
||||||
case "power bi":
|
case "power bi":
|
||||||
icon = "PowerBILogo";
|
icon = "PowerBILogo";
|
||||||
break;
|
break;
|
||||||
case "project for the web":
|
case "project for the web":
|
||||||
icon = "ProjectLogoInverse";
|
icon = "ProjectLogoInverse";
|
||||||
break;
|
break;
|
||||||
case "skype for Business":
|
case "skype for Business":
|
||||||
icon = "SkypeForBusinessLogo";
|
icon = "SkypeForBusinessLogo";
|
||||||
break;
|
break;
|
||||||
case "sway":
|
case "sway":
|
||||||
icon = "SwayLogoInverse";
|
icon = "SwayLogoInverse";
|
||||||
break;
|
break;
|
||||||
case "Yammer Enterprise":
|
case "Yammer Enterprise":
|
||||||
icon = "YammerLogo";
|
icon = "YammerLogo";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return icon;
|
return icon;
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
"preconfiguredEntries": [{
|
"preconfiguredEntries": [{
|
||||||
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Advanced
|
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Advanced
|
||||||
"group": { "default": "Advanced" },
|
"group": { "default": "Advanced" },
|
||||||
"title": { "default": "M365 Services Health" },
|
"title": { "default": "Service Health for Microsoft 365" },
|
||||||
"description": { "default": "m365-services-health description" },
|
"description": { "default": "m365-services-health description" },
|
||||||
"officeFabricIconFontName": "HealthSolid",
|
"officeFabricIconFontName": "HealthSolid",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { ServiceHealthIssuePost } from "@microsoft/microsoft-graph-types";
|
import { ServiceHealthIssuePost } from "@microsoft/microsoft-graph-types";
|
||||||
import Style from "./IssueDetail.module.scss";
|
import Style from "./IssueDetail.module.scss";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { HelperService } from "../../../../../common/services/HelperService";
|
import * as HelperService from "../../../../../common/services/HelperService";
|
||||||
import { Icon, Label } from "@fluentui/react";
|
import { Icon, Label } from "@fluentui/react";
|
||||||
import { IIssueDetailProps } from "../../../interfaces/ServiceHealthModels";
|
import { IIssueDetailProps } from "../../../interfaces/ServiceHealthModels";
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { DefaultButton, DetailsList, IColumn, IPanelProps, IRenderFunction, Pane
|
||||||
import { ServiceHealth, ServiceHealthIssue } from "@microsoft/microsoft-graph-types";
|
import { ServiceHealth, ServiceHealthIssue } from "@microsoft/microsoft-graph-types";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { IServiceHealthOverviewItem, IServiceHealthOverviewProps, IServiceHealthOverviewState } from "../../interfaces/ServiceHealthModels";
|
import { IServiceHealthOverviewItem, IServiceHealthOverviewProps, IServiceHealthOverviewState } from "../../interfaces/ServiceHealthModels";
|
||||||
import { ListViewHelperService } from "../../services/ListViewHelperService";
|
import * as ListViewHelperService from "../../services/ListViewHelperService";
|
||||||
import { backButtonStyles, cancelButtonStyle, issueDetailPanelStyles, issueListPanelStyles } from "./Constant";
|
import { backButtonStyles, cancelButtonStyle, issueDetailPanelStyles, issueListPanelStyles } from "./Constant";
|
||||||
import { IssueDetail } from "./IssueDetail/IssueDetail";
|
import { IssueDetail } from "./IssueDetail/IssueDetail";
|
||||||
import { IssueList } from "./IssueList/IssueList";
|
import { IssueList } from "./IssueList/IssueList";
|
||||||
|
|
|
@ -2,64 +2,62 @@ import { IServiceHealthOverviewItem } from "./../interfaces/ServiceHealthModels"
|
||||||
import { IColumn } from "@fluentui/react";
|
import { IColumn } from "@fluentui/react";
|
||||||
import { ServiceHealth, ServiceHealthIssue } from "@microsoft/microsoft-graph-types";
|
import { ServiceHealth, ServiceHealthIssue } from "@microsoft/microsoft-graph-types";
|
||||||
|
|
||||||
export namespace ListViewHelperService {
|
export const getOverviewListViewColumns = (): IColumn[] => {
|
||||||
export const getOverviewListViewColumns = (): IColumn[] => {
|
const viewColumnsSchema: IColumn[] = [
|
||||||
const viewColumnsSchema: IColumn[] = [
|
{
|
||||||
{
|
key: "Service",
|
||||||
key: "Service",
|
name: "Service",
|
||||||
name: "Service",
|
fieldName: "Service",
|
||||||
fieldName: "Service",
|
minWidth: 80,
|
||||||
minWidth: 80,
|
maxWidth: 300,
|
||||||
maxWidth: 300,
|
isResizable: true,
|
||||||
isResizable: true,
|
},
|
||||||
},
|
{
|
||||||
{
|
key: "Status",
|
||||||
key: "Status",
|
name: "Status",
|
||||||
name: "Status",
|
fieldName: "Status",
|
||||||
fieldName: "Status",
|
minWidth: 120,
|
||||||
minWidth: 120,
|
},
|
||||||
},
|
];
|
||||||
];
|
return viewColumnsSchema;
|
||||||
return viewColumnsSchema;
|
};
|
||||||
};
|
|
||||||
|
|
||||||
export const getListViewItemsForOverview = (response: ServiceHealth[]): IServiceHealthOverviewItem[] => {
|
export const getListViewItemsForOverview = (response: ServiceHealth[]): IServiceHealthOverviewItem[] => {
|
||||||
const overviewItems: IServiceHealthOverviewItem[] = [];
|
const overviewItems: IServiceHealthOverviewItem[] = [];
|
||||||
for (let i = 0; i < response.length; i++) {
|
for (let i = 0; i < response.length; i++) {
|
||||||
const value = response[i];
|
const value = response[i];
|
||||||
const overviewItem = {} as IServiceHealthOverviewItem;
|
const overviewItem = {} as IServiceHealthOverviewItem;
|
||||||
overviewItem.Service = value.service;
|
overviewItem.Service = value.service;
|
||||||
const inProgressIssues: ServiceHealthIssue[] = value.issues.filter((issue) => !issue.isResolved);
|
const inProgressIssues: ServiceHealthIssue[] = value.issues.filter((issue) => !issue.isResolved);
|
||||||
if (inProgressIssues.length > 0) {
|
if (inProgressIssues.length > 0) {
|
||||||
const counts = inProgressIssues.reduce(
|
const counts = inProgressIssues.reduce(
|
||||||
(acc, curr) => {
|
(acc, curr) => {
|
||||||
if (curr.classification === "advisory") {
|
if (curr.classification === "advisory") {
|
||||||
acc.advisoryCount++;
|
acc.advisoryCount++;
|
||||||
} else if (curr.classification === "incident" || curr.classification === "unknownFutureValue") {
|
} else if (curr.classification === "incident" || curr.classification === "unknownFutureValue") {
|
||||||
acc.incidentCount++;
|
acc.incidentCount++;
|
||||||
}
|
}
|
||||||
return acc;
|
return acc;
|
||||||
},
|
},
|
||||||
{ advisoryCount: 0, incidentCount: 0 }
|
{ advisoryCount: 0, incidentCount: 0 }
|
||||||
);
|
);
|
||||||
|
|
||||||
const status: string[] = [];
|
const status: string[] = [];
|
||||||
if (counts.advisoryCount > 0) {
|
if (counts.advisoryCount > 0) {
|
||||||
status.push(`${counts.advisoryCount} ${counts.advisoryCount === 1 ? "advisory" : "advisories"}`);
|
status.push(`${counts.advisoryCount} ${counts.advisoryCount === 1 ? "advisory" : "advisories"}`);
|
||||||
}
|
|
||||||
if (counts.incidentCount > 0) {
|
|
||||||
status.push(`${counts.incidentCount} ${counts.incidentCount === 1 ? "incident" : "incidents"}`);
|
|
||||||
}
|
|
||||||
overviewItem.Status = status.join(",");
|
|
||||||
overviewItem.InProgressItems = inProgressIssues;
|
|
||||||
} else {
|
|
||||||
overviewItem.Status = "Healthy";
|
|
||||||
overviewItem.InProgressItems = [];
|
|
||||||
}
|
}
|
||||||
overviewItems.push(overviewItem);
|
if (counts.incidentCount > 0) {
|
||||||
|
status.push(`${counts.incidentCount} ${counts.incidentCount === 1 ? "incident" : "incidents"}`);
|
||||||
|
}
|
||||||
|
overviewItem.Status = status.join(",");
|
||||||
|
overviewItem.InProgressItems = inProgressIssues;
|
||||||
|
} else {
|
||||||
|
overviewItem.Status = "Healthy";
|
||||||
|
overviewItem.InProgressItems = [];
|
||||||
}
|
}
|
||||||
|
overviewItems.push(overviewItem);
|
||||||
|
}
|
||||||
|
|
||||||
overviewItems.sort((a, b) => a.Status.localeCompare(b.Status));
|
overviewItems.sort((a, b) => a.Status.localeCompare(b.Status));
|
||||||
return overviewItems;
|
return overviewItems;
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue