From df27d5619bbd0741cb32fb3c9b32cd7de715d0dd Mon Sep 17 00:00:00 2001 From: woksin Date: Tue, 22 Nov 2022 22:43:24 +0100 Subject: [PATCH 01/11] Get microservice build results management tab up and running. Currently only by proxying the endpoint to the local runtime --- .../microserviceView/management/View.tsx | 28 +++++ .../buildResults/ArtifactsResults.tsx | 101 ++++++++++++++++++ .../management/buildResults/BuildResults.ts | 43 ++++++++ .../management/buildResults/View.tsx | 47 ++++++++ .../buildResults/useBuildResults.ts | 54 ++++++++++ .../management/useRuntimeManagement.ts | 43 ++++++++ .../microserviceView/microserviceView.tsx | 17 +++ Source/SelfService/Web/package.json | 1 + Source/SelfService/Web/webpack.config.ts | 7 +- 9 files changed, 340 insertions(+), 1 deletion(-) create mode 100644 Source/SelfService/Web/microservice/microserviceView/management/View.tsx create mode 100644 Source/SelfService/Web/microservice/microserviceView/management/buildResults/ArtifactsResults.tsx create mode 100644 Source/SelfService/Web/microservice/microserviceView/management/buildResults/BuildResults.ts create mode 100644 Source/SelfService/Web/microservice/microserviceView/management/buildResults/View.tsx create mode 100644 Source/SelfService/Web/microservice/microserviceView/management/buildResults/useBuildResults.ts create mode 100644 Source/SelfService/Web/microservice/microserviceView/management/useRuntimeManagement.ts diff --git a/Source/SelfService/Web/microservice/microserviceView/management/View.tsx b/Source/SelfService/Web/microservice/microserviceView/management/View.tsx new file mode 100644 index 000000000..444a84f7c --- /dev/null +++ b/Source/SelfService/Web/microservice/microserviceView/management/View.tsx @@ -0,0 +1,28 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +import React, {} from 'react'; + +import { Tabs } from '@dolittle/design-system/atoms/Tabs/Tabs'; +import { useBuildResults } from './buildResults/useBuildResults'; +import { View as BuildResults} from './buildResults/View'; + +export type ViewProps = { + applicationId: string; + environment: string; + microserviceId: string; +}; + +export const View = (props: ViewProps) => { + const tabs = [ + { + label: 'Build Results', + render: () => + } + ]; + return ( + <> + + + ); +}; diff --git a/Source/SelfService/Web/microservice/microserviceView/management/buildResults/ArtifactsResults.tsx b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/ArtifactsResults.tsx new file mode 100644 index 000000000..73ad22db8 --- /dev/null +++ b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/ArtifactsResults.tsx @@ -0,0 +1,101 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +import React, {} from 'react'; +import { Typography, IconButton } from '@mui/material'; +import { KeyboardArrowUp, KeyboardArrowDown } from '@mui/icons-material'; +import Table from '@mui/material/Table'; +import TableBody from '@mui/material/TableBody'; +import TableCell from '@mui/material/TableCell'; +import TableContainer from '@mui/material/TableContainer'; +import TableHead from '@mui/material/TableHead'; +import TableRow from '@mui/material/TableRow'; + +import { ArtifactResults, BuildResult } from './BuildResults'; + +export type ArtifactsResultsProps = { + results: ArtifactResults, + type: string +}; + + +function toGroupedResults(results: ArtifactResults) { + // TODO: The generation should be a part of the key here. + const result = new Map(); + results.forEach(_ => { + let item = result.get(_.artifact.id); + if (item === undefined) { + item = {alias: _.alias, generation: _.artifact.generation, buildResults: []}; + } + item.buildResults.push(_.buildResult); + result.set(_.artifact.id, item); + }); + return result; +} + +const ExpandableRow = ({children, expandComponent}: {children: JSX.Element[], expandComponent: JSX.Element}) => { + const [isExpanded, setIsExpanded] = React.useState(false); + + return ( + <> + + + setIsExpanded(!isExpanded)}> + {isExpanded ? : } + + + {children} + + {isExpanded && ( + + + {expandComponent} + + )} + + ); +}; +export const ArtifactsResultsView = (props: ArtifactsResultsProps) => { + if (!props.results?.length) { + return <>; + } + + const results = toGroupedResults(props.results); + return ( + <> + {props.type} + + + + + + Alias + Id + Generation + Build Messages + + + + {Array.from(results, ([id, {alias, generation, buildResults}]) => ( + + {buildResults.map((result, i) => ( + {`${result.type}: ${result.message}`} + ))} + } + > + _.isFailed) === -1 ? undefined : 'red'}} align="left">{alias ?? 'No Alias'} + {id} + {generation} + {buildResults.length} + + ))} + +
+
+ + ); +}; + diff --git a/Source/SelfService/Web/microservice/microserviceView/management/buildResults/BuildResults.ts b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/BuildResults.ts new file mode 100644 index 000000000..d56dd1db1 --- /dev/null +++ b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/BuildResults.ts @@ -0,0 +1,43 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +export type BuildResults = { + other: OtherResults; + eventTypes: ArtifactResults; + aggregateRoots: ArtifactResults; + eventHandlers: ArtifactResults; + projections: ArtifactResults; + embeddings: ArtifactResults; + filters: ArtifactResults; +}; + +export type BuildResult = { + type: string, + message: string, + isFailed: boolean +}; + +export type Artifact = { + id: string, + generation: number +}; + +export type OtherResults = BuildResult[]; + +export type ArtifactResult = { + alias: string | '', + buildResult: BuildResult, + artifact: Artifact +}; + +export type ArtifactResults = ArtifactResult[]; + +export const emptyBuildResults: BuildResults = { + other: [], + aggregateRoots: [], + embeddings: [], + eventHandlers: [], + eventTypes: [], + filters: [], + projections: [] +}; diff --git a/Source/SelfService/Web/microservice/microserviceView/management/buildResults/View.tsx b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/View.tsx new file mode 100644 index 000000000..f7f992fa0 --- /dev/null +++ b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/View.tsx @@ -0,0 +1,47 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +import React, {useState} from 'react'; +import { LoadingSpinner } from '@dolittle/design-system/atoms/LoadingSpinner/LoadingSpinner'; +import { Button } from '@dolittle/design-system/atoms/Button/Button'; +import { Typography } from '@mui/material'; +import { DataTable } from '../../../dataTable'; +import { DeployButton } from '../../../deployButton'; +import { NoMicroservices } from '../../../noMicroservices'; + +import { useBuildResults } from './useBuildResults'; +import { ListView } from 'Source/SelfService/Web/backup/listView'; +import { ArtifactsResultsView } from './ArtifactsResults'; + +export type ViewProps = { + applicationId: string; + environment: string; + microserviceId: string; +}; + +const tabs = [ + { + label: 'Build Results', + render: () =>

HEllo

+ } +]; + +export const View = (props: ViewProps) => { + const buildResults = useBuildResults(props.applicationId, props.environment, props.microserviceId); + console.log(buildResults); + + if (buildResults === undefined) { + return <>; + } + return ( + <> + + + + + + + + ); +}; + diff --git a/Source/SelfService/Web/microservice/microserviceView/management/buildResults/useBuildResults.ts b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/useBuildResults.ts new file mode 100644 index 000000000..357bc7565 --- /dev/null +++ b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/useBuildResults.ts @@ -0,0 +1,54 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +import { ClientPromiseClient } from '@dolittle/contracts.web/Runtime/Management/Client/Client_grpc_web_pb'; +import { GetBuildResultsRequest } from '@dolittle/contracts.web/Runtime/Management/Client/Client_pb'; +import { BuildResult as PbBuildResult, ArtifactBuildResult as PbArtifactBuildResult, } from '@dolittle/contracts.web/Runtime/Client/BuildResult_pb'; +import { Guid } from '@dolittle/rudiments'; +import { useState, useEffect } from 'react'; +import { useRuntimeManagementUrl } from '../useRuntimeManagement'; +import { ArtifactResult, BuildResult, BuildResults, emptyBuildResults, } from './BuildResults'; + +export const useBuildResults = (applicationId: string, environment: string, microserviceId: string): BuildResults => { + const url = useRuntimeManagementUrl(applicationId, environment, microserviceId); + const [buildResults, setBuildResults] = useState({} as BuildResults); + useEffect(() => { + const client = new ClientPromiseClient(url); + client.getBuildResults(new GetBuildResultsRequest()) + .then(resp => { + const results = resp.getBuildresults()!; + setBuildResults({ + other: results.getOtherList().map(toBuildResult), + aggregateRoots: results.getAggregaterootsList().map(toArtifactResult), + embeddings: results.getEmbeddingsList().map(toArtifactResult), + eventHandlers: results.getEventhandlersList().map(toArtifactResult), + eventTypes: results.getEventtypesList().map(toArtifactResult), + filters: results.getFiltersList().map(toArtifactResult), + projections: results.getProjectionsList().map(toArtifactResult), + }); + }) + .catch(err => { + console.error(err); + setBuildResults(emptyBuildResults); + }); + }, [url]); + + return buildResults; +}; + +function toBuildResult(pb: PbBuildResult): BuildResult { + const typeString = Object.entries(PbBuildResult.Type).find(_ => _[1] === pb.getType())?.[0]!; + return { + message: pb.getMessage(), + type: typeString, + isFailed: pb.getType() !== PbBuildResult.Type.INFORMATION + }; +} +function toArtifactResult(pb: PbArtifactBuildResult): ArtifactResult { + return { + buildResult: toBuildResult(pb.getBuildresult()!), + alias: pb.getAlias(), + artifact: {generation: pb.getAritfact()!.getGeneration(), id: new Guid(pb.getAritfact()!.getId()!.getValue_asU8()).toString()}, + }; +} + diff --git a/Source/SelfService/Web/microservice/microserviceView/management/useRuntimeManagement.ts b/Source/SelfService/Web/microservice/microserviceView/management/useRuntimeManagement.ts new file mode 100644 index 000000000..42b9e8fd1 --- /dev/null +++ b/Source/SelfService/Web/microservice/microserviceView/management/useRuntimeManagement.ts @@ -0,0 +1,43 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +import { useMemo, useState, useEffect } from 'react'; + +export const useRuntimeManagementUrl = (applicationId: string, environment: string, microserviceId: string): string => { + const url = useMemo( + () => `/proxy/${applicationId}/${environment}/${microserviceId}/runtime-management`, + [applicationId, environment, microserviceId]); + + return url; +}; + +export const useRuntimeManagementAvailable = (applicationId: string, environment: string, microserviceId: string): boolean => { + const url = useRuntimeManagementUrl(applicationId, environment, microserviceId); + const [available, setAvailable] = useState(false); + useEffect(() => { + let aborted = false; + isAvailable(url) + .then(available => { + if (aborted) return; + setAvailable(available); + }) + .catch(() => { + if (aborted) return; + setAvailable(false); + }); + + return () => { aborted = true; }; + }, [url]); + + return available; +}; + +async function isAvailable(url: string) { + try { + const response = await fetch(`${url}`); + console.log('response', response); + return response.status !== 404; + } catch (error) { + throw new Error(`Failed to fetch token ${error}`); + } +} diff --git a/Source/SelfService/Web/microservice/microserviceView/microserviceView.tsx b/Source/SelfService/Web/microservice/microserviceView/microserviceView.tsx index f92281812..75f54960e 100644 --- a/Source/SelfService/Web/microservice/microserviceView/microserviceView.tsx +++ b/Source/SelfService/Web/microservice/microserviceView/microserviceView.tsx @@ -17,6 +17,8 @@ import { HealthStatus } from './healthStatus/healthStatus'; import { ContainerHealthStatus } from '../microserviceStatus'; import { useTerminalAvailable } from './terminal/useTerminal'; import { View as Terminal } from './terminal/View'; +import { View as Management } from './management/View'; +import { useRuntimeManagementAvailable } from './management/useRuntimeManagement'; type MicroserviceViewProps = { application: HttpResponseApplication; @@ -125,6 +127,21 @@ export const MicroserviceView = ({ application, microserviceId, environment, pod ); } + // const managementAvailable = useRuntimeManagementAvailable(applicationId, environment, microserviceId); + // console.log('management available', managementAvailable); + if (true) { + tabs.push( + { + label: 'Management', + render: () => + } + ); + } + return ( <> diff --git a/Source/SelfService/Web/package.json b/Source/SelfService/Web/package.json index cecf97018..c92e24e07 100644 --- a/Source/SelfService/Web/package.json +++ b/Source/SelfService/Web/package.json @@ -18,6 +18,7 @@ "@date-io/date-fns": "2.15.0", "@dolittle/design-system": "1.0.0", "@dolittle/rudiments": "5.0.1", + "@dolittle/contracts.web": "7.5.0-boromir.0", "@monaco-editor/react": "4.4.5", "@shared/styling": "1.0.0", "@shared/web": "1.0.0", diff --git a/Source/SelfService/Web/webpack.config.ts b/Source/SelfService/Web/webpack.config.ts index 5abb8361b..166c87b15 100644 --- a/Source/SelfService/Web/webpack.config.ts +++ b/Source/SelfService/Web/webpack.config.ts @@ -101,10 +101,15 @@ function webpack(env: Args, argv: Args) { }, ws: true, }, + '/proxy/11b6cf47-5d9f-438f-8116-0d9828654657/Dev/7e78b802-e246-467b-9946-1deabf8042ef/runtime-management': { + target: 'http://localhost:51152', + pathRewrite: { '^/proxy/11b6cf47-5d9f-438f-8116-0d9828654657/Dev/7e78b802-e246-467b-9946-1deabf8042ef/runtime-management': '' }, + }, '/proxy': { target: 'http://localhost:3007', ws: true, - } + }, + }, before: (app, server, compiler) => {} }, From 1d7693f953e1842d7442314b6e0b97132ce34500 Mon Sep 17 00:00:00 2001 From: woksin Date: Tue, 22 Nov 2022 22:59:35 +0100 Subject: [PATCH 02/11] Fix expandable view --- .../buildResults/ArtifactsResults.tsx | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/Source/SelfService/Web/microservice/microserviceView/management/buildResults/ArtifactsResults.tsx b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/ArtifactsResults.tsx index 73ad22db8..e3067ae89 100644 --- a/Source/SelfService/Web/microservice/microserviceView/management/buildResults/ArtifactsResults.tsx +++ b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/ArtifactsResults.tsx @@ -33,7 +33,7 @@ function toGroupedResults(results: ArtifactResults) { return result; } -const ExpandableRow = ({children, expandComponent}: {children: JSX.Element[], expandComponent: JSX.Element}) => { +const ExpandableRow = ({children, buildMessages: buildResults}: {children: JSX.Element[], buildMessages: BuildResult[]}) => { const [isExpanded, setIsExpanded] = React.useState(false); return ( @@ -46,12 +46,12 @@ const ExpandableRow = ({children, expandComponent}: {children: JSX.Element[], ex {children} - {isExpanded && ( - - - {expandComponent} - - )} + {isExpanded && buildResults.map((result, i) => ( + + + {`${result.type}: ${result.message}`} + + ))} ); }; @@ -79,12 +79,7 @@ export const ArtifactsResultsView = (props: ArtifactsResultsProps) => { {Array.from(results, ([id, {alias, generation, buildResults}]) => ( - {buildResults.map((result, i) => ( - {`${result.type}: ${result.message}`} - ))} - } + buildMessages={buildResults} > _.isFailed) === -1 ? undefined : 'red'}} align="left">{alias ?? 'No Alias'} {id} From 030f2b24335010a217a856fcf990e2a09fd06d85 Mon Sep 17 00:00:00 2001 From: woksin Date: Wed, 23 Nov 2022 19:28:27 +0100 Subject: [PATCH 03/11] Mocks for runtime management --- Environment/mock/package.json | 15 +++-- Environment/mock/proxy/index.js | 2 + .../mock/proxy/runtimeManagement/artifacts.js | 13 +++++ .../runtimeManagement/client/buildResults.js | 35 ++++++++++++ .../proxy/runtimeManagement/client/index.js | 57 +++++++++++++++++++ .../mock/proxy/runtimeManagement/guids.js | 13 +++++ .../mock/proxy/runtimeManagement/index.js | 17 ++++++ .../mock/proxy/runtimeManagement/responses.js | 13 +++++ 8 files changed, 160 insertions(+), 5 deletions(-) create mode 100644 Environment/mock/proxy/runtimeManagement/artifacts.js create mode 100644 Environment/mock/proxy/runtimeManagement/client/buildResults.js create mode 100644 Environment/mock/proxy/runtimeManagement/client/index.js create mode 100644 Environment/mock/proxy/runtimeManagement/guids.js create mode 100644 Environment/mock/proxy/runtimeManagement/index.js create mode 100644 Environment/mock/proxy/runtimeManagement/responses.js diff --git a/Environment/mock/package.json b/Environment/mock/package.json index 5f246094c..2c1e726bf 100644 --- a/Environment/mock/package.json +++ b/Environment/mock/package.json @@ -8,13 +8,18 @@ "start": "node index.js" }, "devDependencies": { - "express": "4.18.1", + "@botchris/grpc-web-mock": "0.0.7", + "@dolittle/contracts.web": "7.5.0-boromir.0", + "@dolittle/rudiments": "6.0.0", "@grafana/lezer-logql": "0.1.0", - "@prometheus-io/lezer-promql": "0.37.1", - "@lezer/lr": "1.2.3", "@lezer/highlight": "1.1.0", + "@lezer/lr": "1.2.3", + "@prometheus-io/lezer-promql": "0.37.1", + "express": "4.18.1", "express-ws": "5.0.2", - "node-pty": "0.10.1", - "jabber": "1.4.0" + "jabber": "1.4.0", + "node-pty": "0.10.1" + }, + "dependencies": { } } diff --git a/Environment/mock/proxy/index.js b/Environment/mock/proxy/index.js index d1829cf1a..c90b76ae9 100644 --- a/Environment/mock/proxy/index.js +++ b/Environment/mock/proxy/index.js @@ -4,9 +4,11 @@ const { Router } = require('express'); const shell = require('./shell'); +const runtimeManagement = require('./runtimeManagement'); const ports = Router({ mergeParams: true }); ports.use('/shell', shell); +ports.use('/runtime-management', runtimeManagement); ports.get('/:port/*', (req, res) => { const { applicationId, environment, microserviceId, port } = req.params; diff --git a/Environment/mock/proxy/runtimeManagement/artifacts.js b/Environment/mock/proxy/runtimeManagement/artifacts.js new file mode 100644 index 000000000..5b75e4f5b --- /dev/null +++ b/Environment/mock/proxy/runtimeManagement/artifacts.js @@ -0,0 +1,13 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +const { Artifact } = require('@dolittle/contracts.web/Artifacts/Artifact_pb'); +const { toUuid } = require('./guids') +module.exports = { + pbArtifact: (guidString, generation = 1) => { + const artifact = new Artifact(); + artifact.setId(toUuid(guidString)); + artifact.setGeneration(generation); + return artifact; + } +} \ No newline at end of file diff --git a/Environment/mock/proxy/runtimeManagement/client/buildResults.js b/Environment/mock/proxy/runtimeManagement/client/buildResults.js new file mode 100644 index 000000000..e7d6be896 --- /dev/null +++ b/Environment/mock/proxy/runtimeManagement/client/buildResults.js @@ -0,0 +1,35 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +const { ArtifactBuildResult, BuildResult, BuildResults } = require('@dolittle/contracts.web/Runtime/Client/BuildResult_pb'); +const {GetBuildResultsResponse } = require('@dolittle/contracts.web/Runtime/Management/Client/Client_pb'); +const { pbArtifact } = require('../artifacts') +const { respondWith } = require('../responses') +module.exports = { + emptyBuildResults: () => { + return new BuildResults(); + }, + artifactBuildResult: (idString, alias = '', generation = 1, buildResult = undefined) => { + const result = new ArtifactBuildResult(); + result.setAritfact(pbArtifact(idString, generation)); + result.setAlias(alias); + result.setBuildresult(buildResult); + return result; + }, + buildResult: (message, type) => { + const result = new BuildResult(); + result.setMessage(message); + result.setType(type); + return result; + }, + respondWith: (res, buildResults) => { + const response = new GetBuildResultsResponse(); + response.setBuildresults(buildResults); + respondWith(res, response); + }, + type: { + Information: BuildResult.Type.INFORMATION, + Failure: BuildResult.Type.FAILURE, + Error: BuildResult.Type.ERROR, + } +} \ No newline at end of file diff --git a/Environment/mock/proxy/runtimeManagement/client/index.js b/Environment/mock/proxy/runtimeManagement/client/index.js new file mode 100644 index 000000000..327cbc9c7 --- /dev/null +++ b/Environment/mock/proxy/runtimeManagement/client/index.js @@ -0,0 +1,57 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +const { Router } = require('express'); +const { artifactBuildResult, buildResult, emptyBuildResults, respondWith, type } = require('./buildResults'); +const routes = module.exports = Router({ mergeParams: true }); + +const characters ='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; +function generateString(length) { + let result = ' '; + const charactersLength = characters.length; + for (let i = 0; i < length; i++) { + result += characters.charAt(Math.floor(Math.random() * charactersLength)); + } + + return result; +} + +const messages = { + short: () => generateString(20), + long: () => generateString(200) +} + +const createArtifactBuildResults = () => [ + artifactBuildResult('72426059-f47c-4311-86c8-2a4e47fa2a4a', 'Some Alias', 1, buildResult(messages.short(), type.Information)), + artifactBuildResult('72426059-f47c-4311-86c8-2a4e47fa2a4a', 'Some Alias', 1, buildResult(messages.long(), type.Information)), + artifactBuildResult('b46d86d7-7c10-40dd-a4ee-d9d05259c676', 'With Error', 1, buildResult(messages.short(), type.Information)), + artifactBuildResult('b46d86d7-7c10-40dd-a4ee-d9d05259c676', 'With Error', 1, buildResult(messages.long(), type.Error)), + artifactBuildResult('6eec65ea-71ac-4fe4-b74c-a42de5f9c4b9', 'With Failure', 1, buildResult(messages.short(), type.Information)), + artifactBuildResult('6eec65ea-71ac-4fe4-b74c-a42de5f9c4b9', 'With Failure', 1, buildResult(messages.long(), type.Failure)), + artifactBuildResult('bc226a57-5699-4923-9600-67da7e153784', 'Same Alias As Another', 1, buildResult(messages.short(), type.Information)), + artifactBuildResult('e62f7431-19b3-41f0-a6e3-bced556e510d', 'Same Alias As Another', 1, buildResult(messages.short(), type.Information)), + artifactBuildResult('5b79b500-b43a-4805-84cb-14740317b45d', 'Different Generations', 1, buildResult(messages.short(), type.Information)), + artifactBuildResult('5b79b500-b43a-4805-84cb-14740317b45d', 'Different Generations', 2, buildResult(messages.short(), type.Information)), + artifactBuildResult('31e18f24-aa1a-448a-b0a2-a82f1b825edf', 'Different Aliases1', 1, buildResult(messages.short(), type.Information)), + artifactBuildResult('31e18f24-aa1a-448a-b0a2-a82f1b825edf', 'Different Aliases2', 1, buildResult(messages.short(), type.Information)), +]; + +const other = [ + buildResult(messages.short(), type.Information), + buildResult(messages.short(), type.Error), + buildResult(messages.short(), type.Failure), + buildResult(messages.long(), type.Information), + buildResult(messages.long(), type.Error), + buildResult(messages.long(), type.Failure), +]; +routes.post('/GetBuildResults', (req, res) => { + const buildResults = emptyBuildResults(); + buildResults.setEventtypesList(createArtifactBuildResults()); + buildResults.setAggregaterootsList(createArtifactBuildResults()); + buildResults.setEmbeddingsList(createArtifactBuildResults()); + buildResults.setEventhandlersList(createArtifactBuildResults()); + buildResults.setFiltersList(createArtifactBuildResults()); + buildResults.setProjectionsList(createArtifactBuildResults()); + buildResults.setOtherList(other); + respondWith(res, buildResults); +}); diff --git a/Environment/mock/proxy/runtimeManagement/guids.js b/Environment/mock/proxy/runtimeManagement/guids.js new file mode 100644 index 000000000..e2ef75f7f --- /dev/null +++ b/Environment/mock/proxy/runtimeManagement/guids.js @@ -0,0 +1,13 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +const { Uuid } = require('@dolittle/contracts.web/Protobuf/Uuid_pb'); +const { Guid } = require('@dolittle/rudiments'); + +module.exports = { + toUuid: (guidString) => { + const uuid = new Uuid(); + uuid.setValue(new Uint8Array(Guid.parse(guidString).bytes)); + return uuid; + } +} \ No newline at end of file diff --git a/Environment/mock/proxy/runtimeManagement/index.js b/Environment/mock/proxy/runtimeManagement/index.js new file mode 100644 index 000000000..e2631792f --- /dev/null +++ b/Environment/mock/proxy/runtimeManagement/index.js @@ -0,0 +1,17 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +const { Router } = require('express'); +const routes = module.exports = Router({ mergeParams: true }); +const { ToTextResponse } = require('@botchris/grpc-web-mock'); +const client = require('./client'); + +routes.get('/*', (req, res) => { + console.log('Getting RUntime Management Proxy'); + console.log(req.path); + console.log(req.params); + res.status(200).end(); +}) + +routes.use('/dolittle.runtime.client.management.Client', client); + diff --git a/Environment/mock/proxy/runtimeManagement/responses.js b/Environment/mock/proxy/runtimeManagement/responses.js new file mode 100644 index 000000000..58e5f6cca --- /dev/null +++ b/Environment/mock/proxy/runtimeManagement/responses.js @@ -0,0 +1,13 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +const { ToTextResponse } = require('@botchris/grpc-web-mock'); + +module.exports = { + respondWith: (res, protobuf) => { + const result = ToTextResponse(protobuf); + res.set(result.headers) + .status(result.statusCode) + .send(result.body); + } +} \ No newline at end of file From f4324dc131d32832cbeb632ffa721de117bb50f8 Mon Sep 17 00:00:00 2001 From: woksin Date: Wed, 23 Nov 2022 19:28:42 +0100 Subject: [PATCH 04/11] Comment out proxy to local runtime --- Source/SelfService/Web/webpack.config.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/SelfService/Web/webpack.config.ts b/Source/SelfService/Web/webpack.config.ts index 166c87b15..d77518614 100644 --- a/Source/SelfService/Web/webpack.config.ts +++ b/Source/SelfService/Web/webpack.config.ts @@ -101,10 +101,10 @@ function webpack(env: Args, argv: Args) { }, ws: true, }, - '/proxy/11b6cf47-5d9f-438f-8116-0d9828654657/Dev/7e78b802-e246-467b-9946-1deabf8042ef/runtime-management': { - target: 'http://localhost:51152', - pathRewrite: { '^/proxy/11b6cf47-5d9f-438f-8116-0d9828654657/Dev/7e78b802-e246-467b-9946-1deabf8042ef/runtime-management': '' }, - }, + // '/proxy/11b6cf47-5d9f-438f-8116-0d9828654657/Dev/7e78b802-e246-467b-9946-1deabf8042ef/runtime-management': { + // target: 'http://localhost:51152', + // pathRewrite: { '^/proxy/11b6cf47-5d9f-438f-8116-0d9828654657/Dev/7e78b802-e246-467b-9946-1deabf8042ef/runtime-management': '' }, + // }, '/proxy': { target: 'http://localhost:3007', ws: true, From f3887bb629b9e4f075219965d40df032fed318ec Mon Sep 17 00:00:00 2001 From: woksin Date: Wed, 23 Nov 2022 19:37:44 +0100 Subject: [PATCH 05/11] Complete the build results view functionalities --- .../buildResults/ArtifactsResults.tsx | 16 ++++--- .../management/buildResults/OtherResults.tsx | 44 +++++++++++++++++++ .../management/buildResults/View.tsx | 11 ++--- 3 files changed, 57 insertions(+), 14 deletions(-) create mode 100644 Source/SelfService/Web/microservice/microserviceView/management/buildResults/OtherResults.tsx diff --git a/Source/SelfService/Web/microservice/microserviceView/management/buildResults/ArtifactsResults.tsx b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/ArtifactsResults.tsx index e3067ae89..b133d9ecb 100644 --- a/Source/SelfService/Web/microservice/microserviceView/management/buildResults/ArtifactsResults.tsx +++ b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/ArtifactsResults.tsx @@ -18,17 +18,21 @@ export type ArtifactsResultsProps = { type: string }; +function toCombinedKey(id: string, alias: string, generation: number) { + return `${id}/${alias}/${generation}`; +} function toGroupedResults(results: ArtifactResults) { // TODO: The generation should be a part of the key here. - const result = new Map(); + const result = new Map(); results.forEach(_ => { - let item = result.get(_.artifact.id); + const combinedKey = toCombinedKey(_.artifact.id, _.alias, _.artifact.generation); + let item = result.get(combinedKey); if (item === undefined) { - item = {alias: _.alias, generation: _.artifact.generation, buildResults: []}; + item = {id: _.artifact.id, alias: _.alias, generation: _.artifact.generation, buildResults: []}; } item.buildResults.push(_.buildResult); - result.set(_.artifact.id, item); + result.set(combinedKey, item); }); return result; } @@ -76,9 +80,9 @@ export const ArtifactsResultsView = (props: ArtifactsResultsProps) => { - {Array.from(results, ([id, {alias, generation, buildResults}]) => ( + {Array.from(results, ([combinedKey, {id, alias, generation, buildResults}]) => ( _.isFailed) === -1 ? undefined : 'red'}} align="left">{alias ?? 'No Alias'} diff --git a/Source/SelfService/Web/microservice/microserviceView/management/buildResults/OtherResults.tsx b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/OtherResults.tsx new file mode 100644 index 000000000..9da59feb4 --- /dev/null +++ b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/OtherResults.tsx @@ -0,0 +1,44 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +import React from 'react'; +import { Typography } from '@mui/material'; +import Table from '@mui/material/Table'; +import TableBody from '@mui/material/TableBody'; +import TableCell from '@mui/material/TableCell'; +import TableContainer from '@mui/material/TableContainer'; +import TableRow from '@mui/material/TableRow'; +import { BuildResult } from './BuildResults'; + +export type OtherResultsProps = { + results: BuildResult[] +}; + + +export const OtherResultsView = (props: OtherResultsProps) => { + if (!props.results?.length) { + return <>; + } + const results = props.results; + return ( + <> + Other + + + {/* + + + + */} + + {results.map((result, i) => ( + + {`${result.type}: ${result.message}`} + + ))} + +
+
+ + ); +}; + diff --git a/Source/SelfService/Web/microservice/microserviceView/management/buildResults/View.tsx b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/View.tsx index f7f992fa0..67d318677 100644 --- a/Source/SelfService/Web/microservice/microserviceView/management/buildResults/View.tsx +++ b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/View.tsx @@ -1,17 +1,11 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -import React, {useState} from 'react'; -import { LoadingSpinner } from '@dolittle/design-system/atoms/LoadingSpinner/LoadingSpinner'; -import { Button } from '@dolittle/design-system/atoms/Button/Button'; -import { Typography } from '@mui/material'; -import { DataTable } from '../../../dataTable'; -import { DeployButton } from '../../../deployButton'; -import { NoMicroservices } from '../../../noMicroservices'; +import React from 'react'; import { useBuildResults } from './useBuildResults'; -import { ListView } from 'Source/SelfService/Web/backup/listView'; import { ArtifactsResultsView } from './ArtifactsResults'; +import { OtherResultsView } from './OtherResults'; export type ViewProps = { applicationId: string; @@ -41,6 +35,7 @@ export const View = (props: ViewProps) => { + ); }; From d8bd5d96f16b7af055afef6a0865cbe3691ab693 Mon Sep 17 00:00:00 2001 From: woksin Date: Mon, 28 Nov 2022 10:50:09 +0100 Subject: [PATCH 06/11] Cleanup --- .../mock/proxy/runtimeManagement/index.js | 2 - .../microserviceView/management/View.tsx | 20 ++++++--- .../buildResults/ArtifactsResults.tsx | 5 +-- .../management/buildResults/OtherResults.tsx | 6 --- .../management/buildResults/View.tsx | 13 ------ .../management/buildResults/protobuf.ts | 36 +++++++++++++++ .../buildResults/useBuildResults.ts | 45 ++++++++++--------- .../management/useRuntimeManagement.ts | 33 +------------- .../microserviceView/microserviceView.tsx | 24 ++++------ 9 files changed, 82 insertions(+), 102 deletions(-) create mode 100644 Source/SelfService/Web/microservice/microserviceView/management/buildResults/protobuf.ts diff --git a/Environment/mock/proxy/runtimeManagement/index.js b/Environment/mock/proxy/runtimeManagement/index.js index e2631792f..0d68f5557 100644 --- a/Environment/mock/proxy/runtimeManagement/index.js +++ b/Environment/mock/proxy/runtimeManagement/index.js @@ -8,8 +8,6 @@ const client = require('./client'); routes.get('/*', (req, res) => { console.log('Getting RUntime Management Proxy'); - console.log(req.path); - console.log(req.params); res.status(200).end(); }) diff --git a/Source/SelfService/Web/microservice/microserviceView/management/View.tsx b/Source/SelfService/Web/microservice/microserviceView/management/View.tsx index 444a84f7c..ff221fcb4 100644 --- a/Source/SelfService/Web/microservice/microserviceView/management/View.tsx +++ b/Source/SelfService/Web/microservice/microserviceView/management/View.tsx @@ -3,8 +3,8 @@ import React, {} from 'react'; -import { Tabs } from '@dolittle/design-system/atoms/Tabs/Tabs'; -import { useBuildResults } from './buildResults/useBuildResults'; +import { Tab, Tabs } from '@dolittle/design-system/atoms/Tabs/Tabs'; +import { useBuildResultsAvailable } from './buildResults/useBuildResults'; import { View as BuildResults} from './buildResults/View'; export type ViewProps = { @@ -14,15 +14,21 @@ export type ViewProps = { }; export const View = (props: ViewProps) => { - const tabs = [ - { + const tabs: Tab[] = []; + const buildResultsAvailable = useBuildResultsAvailable(props.applicationId, props.environment, props.microserviceId); + if (buildResultsAvailable) { + tabs.push({ label: 'Build Results', render: () => - } - ]; + }); + } + return ( <> - + {tabs.length > 0 + ? + :

There are not any management endpoints on your microservice.

+ } ); }; diff --git a/Source/SelfService/Web/microservice/microserviceView/management/buildResults/ArtifactsResults.tsx b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/ArtifactsResults.tsx index b133d9ecb..8611878ac 100644 --- a/Source/SelfService/Web/microservice/microserviceView/management/buildResults/ArtifactsResults.tsx +++ b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/ArtifactsResults.tsx @@ -23,7 +23,6 @@ function toCombinedKey(id: string, alias: string, generation: number) { } function toGroupedResults(results: ArtifactResults) { - // TODO: The generation should be a part of the key here. const result = new Map(); results.forEach(_ => { const combinedKey = toCombinedKey(_.artifact.id, _.alias, _.artifact.generation); @@ -39,7 +38,6 @@ function toGroupedResults(results: ArtifactResults) { const ExpandableRow = ({children, buildMessages: buildResults}: {children: JSX.Element[], buildMessages: BuildResult[]}) => { const [isExpanded, setIsExpanded] = React.useState(false); - return ( <> @@ -59,6 +57,7 @@ const ExpandableRow = ({children, buildMessages: buildResults}: {children: JSX.E ); }; + export const ArtifactsResultsView = (props: ArtifactsResultsProps) => { if (!props.results?.length) { return <>; @@ -76,7 +75,6 @@ export const ArtifactsResultsView = (props: ArtifactsResultsProps) => { Alias Id Generation - Build Messages @@ -88,7 +86,6 @@ export const ArtifactsResultsView = (props: ArtifactsResultsProps) => { _.isFailed) === -1 ? undefined : 'red'}} align="left">{alias ?? 'No Alias'} {id} {generation} - {buildResults.length}
))}
diff --git a/Source/SelfService/Web/microservice/microserviceView/management/buildResults/OtherResults.tsx b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/OtherResults.tsx index 9da59feb4..9067bafc6 100644 --- a/Source/SelfService/Web/microservice/microserviceView/management/buildResults/OtherResults.tsx +++ b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/OtherResults.tsx @@ -13,7 +13,6 @@ export type OtherResultsProps = { results: BuildResult[] }; - export const OtherResultsView = (props: OtherResultsProps) => { if (!props.results?.length) { return <>; @@ -24,11 +23,6 @@ export const OtherResultsView = (props: OtherResultsProps) => { Other - {/* - - - - */} {results.map((result, i) => ( diff --git a/Source/SelfService/Web/microservice/microserviceView/management/buildResults/View.tsx b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/View.tsx index 67d318677..c9cabd10f 100644 --- a/Source/SelfService/Web/microservice/microserviceView/management/buildResults/View.tsx +++ b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/View.tsx @@ -13,20 +13,8 @@ export type ViewProps = { microserviceId: string; }; -const tabs = [ - { - label: 'Build Results', - render: () =>

HEllo

- } -]; - export const View = (props: ViewProps) => { const buildResults = useBuildResults(props.applicationId, props.environment, props.microserviceId); - console.log(buildResults); - - if (buildResults === undefined) { - return <>; - } return ( <> @@ -39,4 +27,3 @@ export const View = (props: ViewProps) => { ); }; - diff --git a/Source/SelfService/Web/microservice/microserviceView/management/buildResults/protobuf.ts b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/protobuf.ts new file mode 100644 index 000000000..5cba423b2 --- /dev/null +++ b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/protobuf.ts @@ -0,0 +1,36 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +import { BuildResult as PbBuildResult, ArtifactBuildResult as PbArtifactBuildResult, } from '@dolittle/contracts.web/Runtime/Client/BuildResult_pb'; +import { ClientPromiseClient } from '@dolittle/contracts.web/Runtime/Management/Client/Client_grpc_web_pb'; +import { GetBuildResultsRequest, GetBuildResultsResponse } from '@dolittle/contracts.web/Runtime/Management/Client/Client_pb'; +import { Guid } from '@dolittle/rudiments'; +import { ArtifactResult, BuildResult } from './BuildResults'; + +let buildResultsResponse: GetBuildResultsResponse; + +export async function getBuildResults(url: string): Promise { + if (buildResultsResponse !== undefined) { + return buildResultsResponse; + } + const response = await new ClientPromiseClient(url).getBuildResults(new GetBuildResultsRequest()); + buildResultsResponse = response; + return buildResultsResponse; +} + +export function toBuildResult(pb: PbBuildResult): BuildResult { + const typeString = Object.entries(PbBuildResult.Type).find(_ => _[1] === pb.getType())?.[0]!; + return { + message: pb.getMessage(), + type: typeString, + isFailed: pb.getType() !== PbBuildResult.Type.INFORMATION + }; +} + +export function toArtifactResult(pb: PbArtifactBuildResult): ArtifactResult { + return { + buildResult: toBuildResult(pb.getBuildresult()!), + alias: pb.getAlias(), + artifact: {generation: pb.getAritfact()!.getGeneration(), id: new Guid(pb.getAritfact()!.getId()!.getValue_asU8()).toString()}, + }; +} diff --git a/Source/SelfService/Web/microservice/microserviceView/management/buildResults/useBuildResults.ts b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/useBuildResults.ts index 357bc7565..4c1394018 100644 --- a/Source/SelfService/Web/microservice/microserviceView/management/buildResults/useBuildResults.ts +++ b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/useBuildResults.ts @@ -1,20 +1,16 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -import { ClientPromiseClient } from '@dolittle/contracts.web/Runtime/Management/Client/Client_grpc_web_pb'; -import { GetBuildResultsRequest } from '@dolittle/contracts.web/Runtime/Management/Client/Client_pb'; -import { BuildResult as PbBuildResult, ArtifactBuildResult as PbArtifactBuildResult, } from '@dolittle/contracts.web/Runtime/Client/BuildResult_pb'; -import { Guid } from '@dolittle/rudiments'; import { useState, useEffect } from 'react'; import { useRuntimeManagementUrl } from '../useRuntimeManagement'; -import { ArtifactResult, BuildResult, BuildResults, emptyBuildResults, } from './BuildResults'; +import { BuildResults, emptyBuildResults, } from './BuildResults'; +import { getBuildResults, toArtifactResult, toBuildResult } from './protobuf'; export const useBuildResults = (applicationId: string, environment: string, microserviceId: string): BuildResults => { const url = useRuntimeManagementUrl(applicationId, environment, microserviceId); const [buildResults, setBuildResults] = useState({} as BuildResults); useEffect(() => { - const client = new ClientPromiseClient(url); - client.getBuildResults(new GetBuildResultsRequest()) + getBuildResults(url) .then(resp => { const results = resp.getBuildresults()!; setBuildResults({ @@ -36,19 +32,24 @@ export const useBuildResults = (applicationId: string, environment: string, micr return buildResults; }; -function toBuildResult(pb: PbBuildResult): BuildResult { - const typeString = Object.entries(PbBuildResult.Type).find(_ => _[1] === pb.getType())?.[0]!; - return { - message: pb.getMessage(), - type: typeString, - isFailed: pb.getType() !== PbBuildResult.Type.INFORMATION - }; -} -function toArtifactResult(pb: PbArtifactBuildResult): ArtifactResult { - return { - buildResult: toBuildResult(pb.getBuildresult()!), - alias: pb.getAlias(), - artifact: {generation: pb.getAritfact()!.getGeneration(), id: new Guid(pb.getAritfact()!.getId()!.getValue_asU8()).toString()}, - }; -} +export const useBuildResultsAvailable = (applicationId: string, environment: string, microserviceId: string): boolean => { + const url = useRuntimeManagementUrl(applicationId, environment, microserviceId); + const [available, setAvailable] = useState(false); + useEffect(() => { + let aborted = false; + getBuildResults(url) + .then(response => { + if (aborted) return; + setAvailable(!!response.getBuildresults() && true); + }) + .catch(() => { + if (aborted) return; + setAvailable(false); + }); + + return () => { aborted = true; }; + }, [url]); + + return available; +}; diff --git a/Source/SelfService/Web/microservice/microserviceView/management/useRuntimeManagement.ts b/Source/SelfService/Web/microservice/microserviceView/management/useRuntimeManagement.ts index 42b9e8fd1..47ddf700b 100644 --- a/Source/SelfService/Web/microservice/microserviceView/management/useRuntimeManagement.ts +++ b/Source/SelfService/Web/microservice/microserviceView/management/useRuntimeManagement.ts @@ -1,7 +1,7 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -import { useMemo, useState, useEffect } from 'react'; +import { useMemo } from 'react'; export const useRuntimeManagementUrl = (applicationId: string, environment: string, microserviceId: string): string => { const url = useMemo( @@ -10,34 +10,3 @@ export const useRuntimeManagementUrl = (applicationId: string, environment: stri return url; }; - -export const useRuntimeManagementAvailable = (applicationId: string, environment: string, microserviceId: string): boolean => { - const url = useRuntimeManagementUrl(applicationId, environment, microserviceId); - const [available, setAvailable] = useState(false); - useEffect(() => { - let aborted = false; - isAvailable(url) - .then(available => { - if (aborted) return; - setAvailable(available); - }) - .catch(() => { - if (aborted) return; - setAvailable(false); - }); - - return () => { aborted = true; }; - }, [url]); - - return available; -}; - -async function isAvailable(url: string) { - try { - const response = await fetch(`${url}`); - console.log('response', response); - return response.status !== 404; - } catch (error) { - throw new Error(`Failed to fetch token ${error}`); - } -} diff --git a/Source/SelfService/Web/microservice/microserviceView/microserviceView.tsx b/Source/SelfService/Web/microservice/microserviceView/microserviceView.tsx index 75f54960e..caf5bfcea 100644 --- a/Source/SelfService/Web/microservice/microserviceView/microserviceView.tsx +++ b/Source/SelfService/Web/microservice/microserviceView/microserviceView.tsx @@ -18,7 +18,6 @@ import { ContainerHealthStatus } from '../microserviceStatus'; import { useTerminalAvailable } from './terminal/useTerminal'; import { View as Terminal } from './terminal/View'; import { View as Management } from './management/View'; -import { useRuntimeManagementAvailable } from './management/useRuntimeManagement'; type MicroserviceViewProps = { application: HttpResponseApplication; @@ -110,6 +109,14 @@ export const MicroserviceView = ({ application, microserviceId, environment, pod microserviceId={microserviceId} data={podsData} /> + }, + { + label: 'Management', + render: () => } ]; @@ -127,21 +134,6 @@ export const MicroserviceView = ({ application, microserviceId, environment, pod ); } - // const managementAvailable = useRuntimeManagementAvailable(applicationId, environment, microserviceId); - // console.log('management available', managementAvailable); - if (true) { - tabs.push( - { - label: 'Management', - render: () => - } - ); - } - return ( <> From c47d4b404c8826a5133956082968d00e7db56003 Mon Sep 17 00:00:00 2001 From: woksin Date: Mon, 28 Nov 2022 11:34:50 +0100 Subject: [PATCH 07/11] Make the Tabs selected tab cache not global --- Source/DesignSystem/atoms/Tabs/Tabs.stories.tsx | 1 + Source/DesignSystem/atoms/Tabs/Tabs.tsx | 16 +++++++++++----- .../microserviceView/management/View.tsx | 2 +- .../microserviceView/microserviceView.tsx | 2 +- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Source/DesignSystem/atoms/Tabs/Tabs.stories.tsx b/Source/DesignSystem/atoms/Tabs/Tabs.stories.tsx index 4d6f9e197..0fd7e010b 100644 --- a/Source/DesignSystem/atoms/Tabs/Tabs.stories.tsx +++ b/Source/DesignSystem/atoms/Tabs/Tabs.stories.tsx @@ -11,6 +11,7 @@ const { metadata, createStory } = componentStories(Tabs); export default metadata; export const Normal = createStory({ + id: 'Tabs', tabs: [ { label: 'First tab', diff --git a/Source/DesignSystem/atoms/Tabs/Tabs.tsx b/Source/DesignSystem/atoms/Tabs/Tabs.tsx index e5f55023b..faea24d75 100644 --- a/Source/DesignSystem/atoms/Tabs/Tabs.tsx +++ b/Source/DesignSystem/atoms/Tabs/Tabs.tsx @@ -40,20 +40,26 @@ export type Tab = { export type TabsProps = { tabs: Tab[]; + id?: string, sx?: any; }; export const Tabs = (props: TabsProps) => { + const getCacheKey = () => `selectedTab#${props.id}`; const [currentTab, setCurrentTab] = useState(0); - useEffect(() => { - const storedSelectedOption = parseInt(sessionStorage.getItem('selectedTab') || '0'); - setCurrentTab(storedSelectedOption); - }, []); + if (!!props.id) { + useEffect(() => { + const storedSelectedOption = parseInt(sessionStorage.getItem(getCacheKey()) || '0'); + setCurrentTab(storedSelectedOption); + }, []); + } const handleChange = (event: React.ChangeEvent<{}>, newValue: number) => { setCurrentTab(newValue); - sessionStorage.setItem('selectedTab', newValue.toString()); + if (!!props.id) { + sessionStorage.setItem(getCacheKey(), newValue.toString()); + } }; return ( diff --git a/Source/SelfService/Web/microservice/microserviceView/management/View.tsx b/Source/SelfService/Web/microservice/microserviceView/management/View.tsx index ff221fcb4..93027bc11 100644 --- a/Source/SelfService/Web/microservice/microserviceView/management/View.tsx +++ b/Source/SelfService/Web/microservice/microserviceView/management/View.tsx @@ -26,7 +26,7 @@ export const View = (props: ViewProps) => { return ( <> {tabs.length > 0 - ? + ? :

There are not any management endpoints on your microservice.

} diff --git a/Source/SelfService/Web/microservice/microserviceView/microserviceView.tsx b/Source/SelfService/Web/microservice/microserviceView/microserviceView.tsx index caf5bfcea..5bfb44e0a 100644 --- a/Source/SelfService/Web/microservice/microserviceView/microserviceView.tsx +++ b/Source/SelfService/Web/microservice/microserviceView/microserviceView.tsx @@ -141,7 +141,7 @@ export const MicroserviceView = ({ application, microserviceId, environment, pod
- + ); }; From e13e91ded861197bec71c11665c60f0de1a97b30 Mon Sep 17 00:00:00 2001 From: woksin Date: Wed, 30 Nov 2022 14:02:13 +0100 Subject: [PATCH 08/11] Cleanup and fix cache mechanism --- .../microserviceView/management/Protobuf.ts | 21 ++++++++++++++++ .../microserviceView/management/Types.ts | 7 ++++++ .../management/buildResults/BuildResults.ts | 25 +++++++++++++++---- .../management/buildResults/protobuf.ts | 15 +++++------ .../buildResults/useBuildResults.ts | 21 ++++++---------- 5 files changed, 63 insertions(+), 26 deletions(-) create mode 100644 Source/SelfService/Web/microservice/microserviceView/management/Protobuf.ts create mode 100644 Source/SelfService/Web/microservice/microserviceView/management/Types.ts diff --git a/Source/SelfService/Web/microservice/microserviceView/management/Protobuf.ts b/Source/SelfService/Web/microservice/microserviceView/management/Protobuf.ts new file mode 100644 index 000000000..910213ce4 --- /dev/null +++ b/Source/SelfService/Web/microservice/microserviceView/management/Protobuf.ts @@ -0,0 +1,21 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +import { Uuid } from '@dolittle/contracts.web/Protobuf/Uuid_pb'; +import { Artifact as PbArtifact } from '@dolittle/contracts.web/Artifacts/Artifact_pb'; +import { Guid } from '@dolittle/rudiments'; +import { Artifact } from './Types'; + +export function toGuid(uuid: Uuid) { + return new Guid(uuid.getValue_asU8()); +} + +export function toUuid(guid: Guid | string) { + const uuid = new Uuid(); + uuid.setValue(new Uint8Array(Guid.as(guid).bytes)); + return uuid; +} + +export function toArtifact(artifact: PbArtifact): Artifact { + return {generation: artifact.getGeneration(), id: toGuid(artifact.getId()!).toString()}; +} diff --git a/Source/SelfService/Web/microservice/microserviceView/management/Types.ts b/Source/SelfService/Web/microservice/microserviceView/management/Types.ts new file mode 100644 index 000000000..06b369e6e --- /dev/null +++ b/Source/SelfService/Web/microservice/microserviceView/management/Types.ts @@ -0,0 +1,7 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +export type Artifact = { + id: string, + generation: number +}; diff --git a/Source/SelfService/Web/microservice/microserviceView/management/buildResults/BuildResults.ts b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/BuildResults.ts index d56dd1db1..ceab8e23f 100644 --- a/Source/SelfService/Web/microservice/microserviceView/management/buildResults/BuildResults.ts +++ b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/BuildResults.ts @@ -1,6 +1,9 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +import { Artifact } from '../Types'; +import { getBuildResults as pbGetBuildResults, toArtifactResult, toBuildResult } from './Protobuf'; + export type BuildResults = { other: OtherResults; eventTypes: ArtifactResults; @@ -17,11 +20,6 @@ export type BuildResult = { isFailed: boolean }; -export type Artifact = { - id: string, - generation: number -}; - export type OtherResults = BuildResult[]; export type ArtifactResult = { @@ -41,3 +39,20 @@ export const emptyBuildResults: BuildResults = { filters: [], projections: [] }; + +export async function getBuildResults(url: string): Promise { + const response = await pbGetBuildResults(url); + const results = response.getBuildresults(); + if (results === undefined) { + throw new Error('Build results is empty'); + } + return { + other: results.getOtherList().map(toBuildResult), + aggregateRoots: results.getAggregaterootsList().map(toArtifactResult), + embeddings: results.getEmbeddingsList().map(toArtifactResult), + eventHandlers: results.getEventhandlersList().map(toArtifactResult), + eventTypes: results.getEventtypesList().map(toArtifactResult), + filters: results.getFiltersList().map(toArtifactResult), + projections: results.getProjectionsList().map(toArtifactResult), + }; +} diff --git a/Source/SelfService/Web/microservice/microserviceView/management/buildResults/protobuf.ts b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/protobuf.ts index 5cba423b2..51060f703 100644 --- a/Source/SelfService/Web/microservice/microserviceView/management/buildResults/protobuf.ts +++ b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/protobuf.ts @@ -4,18 +4,19 @@ import { BuildResult as PbBuildResult, ArtifactBuildResult as PbArtifactBuildResult, } from '@dolittle/contracts.web/Runtime/Client/BuildResult_pb'; import { ClientPromiseClient } from '@dolittle/contracts.web/Runtime/Management/Client/Client_grpc_web_pb'; import { GetBuildResultsRequest, GetBuildResultsResponse } from '@dolittle/contracts.web/Runtime/Management/Client/Client_pb'; -import { Guid } from '@dolittle/rudiments'; +import { toArtifact } from '../Protobuf'; import { ArtifactResult, BuildResult } from './BuildResults'; -let buildResultsResponse: GetBuildResultsResponse; +const buildResultsResponseCache: Map = new Map(); export async function getBuildResults(url: string): Promise { - if (buildResultsResponse !== undefined) { - return buildResultsResponse; + if (buildResultsResponseCache.has(url)) { + return buildResultsResponseCache.get(url)!; } + const response = await new ClientPromiseClient(url).getBuildResults(new GetBuildResultsRequest()); - buildResultsResponse = response; - return buildResultsResponse; + buildResultsResponseCache.set(url, response); + return response; } export function toBuildResult(pb: PbBuildResult): BuildResult { @@ -31,6 +32,6 @@ export function toArtifactResult(pb: PbArtifactBuildResult): ArtifactResult { return { buildResult: toBuildResult(pb.getBuildresult()!), alias: pb.getAlias(), - artifact: {generation: pb.getAritfact()!.getGeneration(), id: new Guid(pb.getAritfact()!.getId()!.getValue_asU8()).toString()}, + artifact: toArtifact(pb.getAritfact()!) }; } diff --git a/Source/SelfService/Web/microservice/microserviceView/management/buildResults/useBuildResults.ts b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/useBuildResults.ts index 4c1394018..b3738f42d 100644 --- a/Source/SelfService/Web/microservice/microserviceView/management/buildResults/useBuildResults.ts +++ b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/useBuildResults.ts @@ -3,8 +3,8 @@ import { useState, useEffect } from 'react'; import { useRuntimeManagementUrl } from '../useRuntimeManagement'; -import { BuildResults, emptyBuildResults, } from './BuildResults'; -import { getBuildResults, toArtifactResult, toBuildResult } from './protobuf'; +import { BuildResults, emptyBuildResults, getBuildResults } from './BuildResults'; +import { getBuildResults as pbGetBuildResults } from './Protobuf'; export const useBuildResults = (applicationId: string, environment: string, microserviceId: string): BuildResults => { const url = useRuntimeManagementUrl(applicationId, environment, microserviceId); @@ -12,16 +12,7 @@ export const useBuildResults = (applicationId: string, environment: string, micr useEffect(() => { getBuildResults(url) .then(resp => { - const results = resp.getBuildresults()!; - setBuildResults({ - other: results.getOtherList().map(toBuildResult), - aggregateRoots: results.getAggregaterootsList().map(toArtifactResult), - embeddings: results.getEmbeddingsList().map(toArtifactResult), - eventHandlers: results.getEventhandlersList().map(toArtifactResult), - eventTypes: results.getEventtypesList().map(toArtifactResult), - filters: results.getFiltersList().map(toArtifactResult), - projections: results.getProjectionsList().map(toArtifactResult), - }); + setBuildResults(resp); }) .catch(err => { console.error(err); @@ -38,12 +29,14 @@ export const useBuildResultsAvailable = (applicationId: string, environment: str const [available, setAvailable] = useState(false); useEffect(() => { let aborted = false; - getBuildResults(url) + pbGetBuildResults(url) .then(response => { if (aborted) return; + console.log(response); setAvailable(!!response.getBuildresults() && true); }) - .catch(() => { + .catch((err) => { + console.log('err', err); if (aborted) return; setAvailable(false); }); From ff69b244a36dad157928afcb8b11c927b5365657 Mon Sep 17 00:00:00 2001 From: woksin Date: Wed, 30 Nov 2022 14:04:48 +0100 Subject: [PATCH 09/11] No tabs --- .../microservice/microserviceView/management/View.tsx | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/Source/SelfService/Web/microservice/microserviceView/management/View.tsx b/Source/SelfService/Web/microservice/microserviceView/management/View.tsx index 93027bc11..614812208 100644 --- a/Source/SelfService/Web/microservice/microserviceView/management/View.tsx +++ b/Source/SelfService/Web/microservice/microserviceView/management/View.tsx @@ -16,17 +16,10 @@ export type ViewProps = { export const View = (props: ViewProps) => { const tabs: Tab[] = []; const buildResultsAvailable = useBuildResultsAvailable(props.applicationId, props.environment, props.microserviceId); - if (buildResultsAvailable) { - tabs.push({ - label: 'Build Results', - render: () => - }); - } - return ( <> - {tabs.length > 0 - ? + {buildResultsAvailable + ? :

There are not any management endpoints on your microservice.

} From 67e5d75533e0f80cbe704638ba03dcefc7313834 Mon Sep 17 00:00:00 2001 From: woksin Date: Wed, 30 Nov 2022 14:15:57 +0100 Subject: [PATCH 10/11] Cleanup --- .../microservice/microserviceView/management/View.tsx | 6 ++---- .../management/buildResults/useBuildResults.ts | 4 +--- .../management/useRuntimeManagement.ts | 5 +++++ .../microserviceView/microserviceView.tsx | 11 ++++++++--- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/Source/SelfService/Web/microservice/microserviceView/management/View.tsx b/Source/SelfService/Web/microservice/microserviceView/management/View.tsx index 614812208..de02ed2d4 100644 --- a/Source/SelfService/Web/microservice/microserviceView/management/View.tsx +++ b/Source/SelfService/Web/microservice/microserviceView/management/View.tsx @@ -3,9 +3,8 @@ import React, {} from 'react'; -import { Tab, Tabs } from '@dolittle/design-system/atoms/Tabs/Tabs'; -import { useBuildResultsAvailable } from './buildResults/useBuildResults'; import { View as BuildResults} from './buildResults/View'; +import { useRuntimeManagementAvailable } from './useRuntimeManagement'; export type ViewProps = { applicationId: string; @@ -14,8 +13,7 @@ export type ViewProps = { }; export const View = (props: ViewProps) => { - const tabs: Tab[] = []; - const buildResultsAvailable = useBuildResultsAvailable(props.applicationId, props.environment, props.microserviceId); + const buildResultsAvailable = useRuntimeManagementAvailable(props.applicationId, props.environment, props.microserviceId); return ( <> {buildResultsAvailable diff --git a/Source/SelfService/Web/microservice/microserviceView/management/buildResults/useBuildResults.ts b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/useBuildResults.ts index b3738f42d..badfe92da 100644 --- a/Source/SelfService/Web/microservice/microserviceView/management/buildResults/useBuildResults.ts +++ b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/useBuildResults.ts @@ -32,11 +32,9 @@ export const useBuildResultsAvailable = (applicationId: string, environment: str pbGetBuildResults(url) .then(response => { if (aborted) return; - console.log(response); setAvailable(!!response.getBuildresults() && true); }) - .catch((err) => { - console.log('err', err); + .catch(() => { if (aborted) return; setAvailable(false); }); diff --git a/Source/SelfService/Web/microservice/microserviceView/management/useRuntimeManagement.ts b/Source/SelfService/Web/microservice/microserviceView/management/useRuntimeManagement.ts index 47ddf700b..8bec91042 100644 --- a/Source/SelfService/Web/microservice/microserviceView/management/useRuntimeManagement.ts +++ b/Source/SelfService/Web/microservice/microserviceView/management/useRuntimeManagement.ts @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. import { useMemo } from 'react'; +import { useBuildResultsAvailable } from './buildResults/useBuildResults'; export const useRuntimeManagementUrl = (applicationId: string, environment: string, microserviceId: string): string => { const url = useMemo( @@ -10,3 +11,7 @@ export const useRuntimeManagementUrl = (applicationId: string, environment: stri return url; }; + +export const useRuntimeManagementAvailable = (applicationId: string, environment: string, microserviceId: string): boolean => { + return useBuildResultsAvailable(applicationId, environment, microserviceId); +}; diff --git a/Source/SelfService/Web/microservice/microserviceView/microserviceView.tsx b/Source/SelfService/Web/microservice/microserviceView/microserviceView.tsx index 5bfb44e0a..611c3b87a 100644 --- a/Source/SelfService/Web/microservice/microserviceView/microserviceView.tsx +++ b/Source/SelfService/Web/microservice/microserviceView/microserviceView.tsx @@ -18,6 +18,7 @@ import { ContainerHealthStatus } from '../microserviceStatus'; import { useTerminalAvailable } from './terminal/useTerminal'; import { View as Terminal } from './terminal/View'; import { View as Management } from './management/View'; +import { useRuntimeManagementAvailable } from './management/useRuntimeManagement'; type MicroserviceViewProps = { application: HttpResponseApplication; @@ -110,15 +111,19 @@ export const MicroserviceView = ({ application, microserviceId, environment, pod data={podsData} /> }, - { + ]; + + const managementAvailable = useRuntimeManagementAvailable(applicationId, environment, microserviceId); + if (managementAvailable) { + tabs.push({ label: 'Management', render: () => - } - ]; + }); + } const terminalAvailable = useTerminalAvailable(applicationId, environment, microserviceId); if (terminalAvailable) { From 7f13ffa0466894690e437a0349b76503e4037a44 Mon Sep 17 00:00:00 2001 From: woksin Date: Wed, 30 Nov 2022 14:19:58 +0100 Subject: [PATCH 11/11] Rename file --- .../management/buildResults/{protobuf.ts => Protobuf.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Source/SelfService/Web/microservice/microserviceView/management/buildResults/{protobuf.ts => Protobuf.ts} (100%) diff --git a/Source/SelfService/Web/microservice/microserviceView/management/buildResults/protobuf.ts b/Source/SelfService/Web/microservice/microserviceView/management/buildResults/Protobuf.ts similarity index 100% rename from Source/SelfService/Web/microservice/microserviceView/management/buildResults/protobuf.ts rename to Source/SelfService/Web/microservice/microserviceView/management/buildResults/Protobuf.ts