diff --git a/backend/applications.js b/backend/applications.js new file mode 100644 index 00000000..8010750e --- /dev/null +++ b/backend/applications.js @@ -0,0 +1,18 @@ +// utils/applications.js + +import fs from 'fs'; +import path from 'path'; + +export function getApplications() { + const filePath = path.join(process.cwd(), 'content/applications/applications.json'); + const fileContents = fs.readFileSync(filePath, 'utf8'); + const data = JSON.parse(fileContents); + + return data.applications; // Assuming the "applications" key holds the array of applications +} + +export function getApplicationById(id) { + const applications = getApplications(); + const application = applications.find(app => app.app_id === id); + return application; +} diff --git a/content/applications/applications.json b/content/applications/applications.json new file mode 100644 index 00000000..4125279f --- /dev/null +++ b/content/applications/applications.json @@ -0,0 +1,35 @@ +{ + "applications": [ + { + "name": "Airview", + "app_id": "APP1", + "description": "Documentation, Compliance and Control for Cloud.", + "environments": { + "development": "subscription-1234", + "staging": "subscription-5678", + "production": "subscription-9012" + } + }, + { + "name": "CoolTool", + "app_id": "APP2", + "description": "A powerful tool for creative professionals.", + "environments": { + "development": "subscription-3456", + "staging": "subscription-7890", + "production": "subscription-2345" + } + }, + { + "name": "InnovativeApp", + "app_id": "APP3", + "description": "A cutting-edge application with advanced features.", + "environments": { + "development": "subscription-6789", + "staging": "subscription-0123", + "production": "subscription-4567" + } + } + ] + } + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 0a3e6d1d..016fe4f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,7 @@ "@mui/icons-material": "^5.11.11", "@mui/material": "^5.11.7", "@mui/utils": "^5.13.1", + "@mui/x-date-pickers": "^6.5.0", "@next/mdx": "^13.4.3", "@sentry/nextjs": "^7.52.1", "ahooks": "^3.7.7", @@ -1094,6 +1095,71 @@ "react": "^17.0.0 || ^18.0.0" } }, + "node_modules/@mui/x-date-pickers": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-6.5.0.tgz", + "integrity": "sha512-dRCO1mzHjfOqsa4LdKxiXQnV0cuGiAkliyxSDCdRn6clK2WdF9Oj+1+4Mkx7fcJA61SV1eP4Yg29s0/VDsZKZw==", + "dependencies": { + "@babel/runtime": "^7.21.0", + "@mui/utils": "^5.12.3", + "@types/react-transition-group": "^4.4.6", + "clsx": "^1.2.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@emotion/react": "^11.9.0", + "@emotion/styled": "^11.8.1", + "@mui/base": "^5.0.0-alpha.87", + "@mui/material": "^5.8.6", + "@mui/system": "^5.8.0", + "date-fns": "^2.25.0", + "date-fns-jalali": "^2.13.0-0", + "dayjs": "^1.10.7", + "luxon": "^3.0.2", + "moment": "^2.29.4", + "moment-hijri": "^2.1.2", + "moment-jalaali": "^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0", + "react": "^17.0.2 || ^18.0.0", + "react-dom": "^17.0.2 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "date-fns": { + "optional": true + }, + "date-fns-jalali": { + "optional": true + }, + "dayjs": { + "optional": true + }, + "luxon": { + "optional": true + }, + "moment": { + "optional": true + }, + "moment-hijri": { + "optional": true + }, + "moment-jalaali": { + "optional": true + } + } + }, "node_modules/@next/env": { "version": "13.4.3", "resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.3.tgz", diff --git a/package.json b/package.json index 58069209..9bb97542 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "@mui/icons-material": "^5.11.11", "@mui/material": "^5.11.7", "@mui/utils": "^5.13.1", + "@mui/x-date-pickers": "^6.5.0", "@next/mdx": "^13.4.3", "@sentry/nextjs": "^7.52.1", "ahooks": "^3.7.7", diff --git a/pages/api/applications/[id].js b/pages/api/applications/[id].js new file mode 100644 index 00000000..6d080903 --- /dev/null +++ b/pages/api/applications/[id].js @@ -0,0 +1,19 @@ +// pages/api/applications/[id].js + +import { getApplicationById } from '../../../utils/applications'; + +export default function handler(req, res) { + if (req.method === 'GET') { + const { id } = req.query; + const application = getApplicationById(id); + + if (application) { + res.status(200).json(application); + } else { + res.status(404).json({ error: 'Application not found' }); + } + } else { + res.setHeader('Allow', ['GET']); + res.status(405).end(`Method ${req.method} Not Allowed`); + } +} diff --git a/pages/api/applications/index.js b/pages/api/applications/index.js new file mode 100644 index 00000000..6ad82bab --- /dev/null +++ b/pages/api/applications/index.js @@ -0,0 +1,11 @@ +import { getApplications } from '../../../backend/applications'; + +export default function handler(req, res) { + if (req.method === 'GET') { + const applications = getApplications(); + res.status(200).json(applications); + } else { + res.setHeader('Allow', ['GET']); + res.status(405).end(`Method ${req.method} Not Allowed`); + } +} diff --git a/pages/applications/[app_id].jsx b/pages/applications/[app_id].jsx new file mode 100644 index 00000000..aa97f6e0 --- /dev/null +++ b/pages/applications/[app_id].jsx @@ -0,0 +1,163 @@ +import React from "react"; + +import { Typography, Box } from "@mui/material"; + +import Topbar from '../../components/TopBar'; +import { theme } from '../../constants/baseTheme'; +import { ThemeProvider } from '@mui/material/styles'; +import CssBaseline from '@mui/material/CssBaseline'; +import Grid from '@mui/material/Grid'; +import { getApplications, getApplicationById } from '../../backend/applications'; + +import { ComplianceTable } from "../../components/airview-compliance-ui/features/compliance-table"; +import { ControlOverview, useControlOverviewController, } from "../../components/airview-compliance-ui/features/control-overview"; +import dynamic from 'next/dynamic' + +// temporary data +import { applicationsData } from "../../components/airview-compliance-ui/stories/compliance-table/applications-data"; +import { groups, controls, resources } from "../../components/airview-compliance-ui/stories/control-overview/data"; +/// + +export default dynamic(() => Promise.resolve(Page), { + ssr: false, + }); + +function Page({app}) { + const topBarHeight = 64; + + const noDataMessage={ + title: "No issues", + message: "There are no issues to display for this application", + }; + const invalidPermissionsMessage = { + title: "Notice", + message: "You do not have the required permissions to view the data for this application", + }; + + return ( + + + +
+ {app && app.name && {app.name}} + {app && app.description && {app.description}} + {/* */} + + + + + + ; + + {/* */} + +
+
+ ) +} + + +export async function getStaticPaths() { + let pages = []; + let location = 'services'; + try { + const apps = await getApplications() + const pages = apps.map((file) => { + return '/applications/' + file.id + }) + return { + fallback: true, + paths: pages + } + } catch (error) { + console.error(error) + return { + fallback: true, + paths: pages + } + } + + +} +export async function getStaticProps(context) { + try { + const app = await getApplicationById(context.params.app_id); + return { + props: { + app: app + }, + }; + } catch (error) { + console.error(error); + return { + props: { + app: {} + }, + }; + } +} + + +const ApplicationControls = () => { + const [state, setControlsData, setResourcesData] = + useControlOverviewController(() => { + return new Promise((resolve) => { + setTimeout(() => { + resolve(groups); + }, [500]); + }); + }, 1); + + const handleOnRequestOfControlsData = (id) => { + setControlsData(id, () => { + return new Promise((resolve) => { + setTimeout(() => { + if (id === 3) resolve("error"); + + resolve(controls[id]); + }, [500]); + }); + }); + }; + + const handleOnRequestOfResourcesData = (id) => { + setResourcesData(id, () => { + return new Promise((resolve) => { + setTimeout(() => { + if (id === 3) resolve("error"); + + resolve(resources[id]); + }, [500]); + }); + }); + }; + + const handleOnResourceExemptionDelete = () => { + return new Promise((resolve) => { + setTimeout(() => { + resolve(); + }, [1000]); + }); + }; + + const handleOnResourceExemptionSave = () => { + return new Promise((resolve) => { + setTimeout(() => { + resolve(); + }, [1000]); + }); + }; + + return ( + + ); + }; + \ No newline at end of file