Skip to content

Commit

Permalink
Formating of helm ls and resizing of the command bar
Browse files Browse the repository at this point in the history
  • Loading branch information
garronej committed Oct 7, 2023
1 parent f1bc76f commit 3d188a1
Show file tree
Hide file tree
Showing 6 changed files with 224 additions and 31 deletions.
11 changes: 4 additions & 7 deletions web/src/core/usecases/serviceManager/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import { createSelector } from "@reduxjs/toolkit";

import { name, type RunningService } from "./state";

const readyState = (rootState: RootState) => {
const state = rootState[name];
const state = (rootState: RootState) => rootState[name];

const readyState = createSelector(state, state => {
if (state.stateDescription !== "ready") {
return undefined;
}

return state;
};
});

const runningServices = createSelector(
readyState,
Expand Down Expand Up @@ -52,10 +52,7 @@ const isThereOwnedSharedServices = createSelector(
undefined
);

const commandLogsEntries = createSelector(
readyState,
state => state?.commandLogsEntries ?? []
);
const commandLogsEntries = createSelector(state, state => state.commandLogsEntries);

export const selectors = {
runningServices,
Expand Down
62 changes: 47 additions & 15 deletions web/src/core/usecases/serviceManager/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { assert } from "tsafe/assert";
import { createSlice } from "@reduxjs/toolkit";
import type { PayloadAction } from "@reduxjs/toolkit";
import { id } from "tsafe/id";

import { nestObject } from "core/tools/nestObject";
import * as yaml from "yaml";

Expand All @@ -11,6 +10,11 @@ export type State = State.NotInitialized | State.Ready;
export namespace State {
export type Common = {
isUpdating: boolean;
commandLogsEntries: {
cmdId: number;
cmd: string;
resp: string | undefined;
}[];
};

export type NotInitialized = Common & {
Expand All @@ -23,11 +27,6 @@ export namespace State {
envByServiceId: Record<string, Record<string, string>>;
postInstallInstructionsByServiceId: Record<string, string>;
kubernetesNamespace: string;
commandLogsEntries: {
cmdId: number;
cmd: string;
resp: string | undefined;
}[];
};
}

Expand Down Expand Up @@ -68,7 +67,8 @@ export const { reducer, actions } = createSlice({
"initialState": id<State>(
id<State.NotInitialized>({
"stateDescription": "not initialized",
"isUpdating": false
"isUpdating": false,
"commandLogsEntries": []
})
),
"reducers": {
Expand Down Expand Up @@ -100,14 +100,7 @@ export const { reducer, actions } = createSlice({
envByServiceId,
postInstallInstructionsByServiceId,
kubernetesNamespace,
"commandLogsEntries": (() => {
switch (state.stateDescription) {
case "ready":
return state.commandLogsEntries;
case "not initialized":
return [];
}
})()
"commandLogsEntries": state.commandLogsEntries
});
},
"serviceStarted": (
Expand Down Expand Up @@ -186,6 +179,45 @@ export const { reducer, actions } = createSlice({
"\n"
)
});
},
"commandLogsEntryAdded": (
state,
{
payload
}: {
payload: {
commandLogsEntry: {
cmdId: number;
cmd: string;
resp: string | undefined;
};
};
}
) => {
const { commandLogsEntry } = payload;

state.commandLogsEntries.push(commandLogsEntry);
},
"commandLogsRespUpdated": (
state,
{
payload
}: {
payload: {
cmdId: number;
resp: string;
};
}
) => {
const { cmdId, resp } = payload;

const commandLogsEntry = state.commandLogsEntries.find(
commandLogsEntry => commandLogsEntry.cmdId === cmdId
);

assert(commandLogsEntry !== undefined);

commandLogsEntry.resp = resp;
}
}
});
90 changes: 90 additions & 0 deletions web/src/core/usecases/serviceManager/thunks/formatHelmCommands.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
export function formatHelmLsResp(params: {
lines: {
namespace: string;
name: string;
revision: string;
updatedTime: number;
status: string;
chart: string;
appVersion: string;
}[];
}): string {
const { lines } = params;

const formatTime = (unixTimestampMs: number) => {
const date = new Date(unixTimestampMs);
return date.toISOString() + " " + date.getTimezoneOffset() / 60 + " UTC";
};

const header = {
...(() => {
const key = "NAME";

const nameMaxLength = Math.max(...lines.map(({ name }) => name.length));

return {
[key]: `${key}${" ".repeat(Math.max(nameMaxLength - key.length, 7))} `
};
})(),
...(() => {
const key = "NAMESPACE";

const maxNamespaceLength = Math.max(
...lines.map(({ namespace }) => namespace.length)
);

return {
[key]: `${key}${" ".repeat(
Math.max(maxNamespaceLength - key.length, 7)
)} `
};
})(),
...(() => {
const key = "REVISION";

return {
[key]: `${key}${" ".repeat(7)} `
};
})(),
...(() => {
const key = "UPDATED";

return { [key]: `${key}${" ".repeat(formatTime(Date.now()).length)} ` };
})(),
...(() => {
const key = "STATUS";

return { [key]: `${key}${" ".repeat(7)} ` };
})(),
...(() => {
const key = "CHART";

const chartMaxLength = Math.max(...lines.map(({ chart }) => chart.length));

return {
[key]: `${key}${" ".repeat(Math.max(chartMaxLength - key.length, 7))} `
};
})(),
...(() => {
const key = "APP VERSION";

return { [key]: `${key}${" ".repeat(7)} ` };
})()
};

return [
Object.values(header).join(""),
...lines.map(
({ name, namespace, revision, updatedTime, chart, status, appVersion }) =>
[
name.padEnd(header.NAME.length),
namespace.padEnd(header.NAMESPACE.length),
revision.padEnd(header.REVISION.length),
formatTime(updatedTime).padEnd(header.UPDATED.length),
status.padEnd(header.STATUS.length),
chart.padEnd(header.CHART.length),
appVersion.padEnd(header["APP VERSION"].length)
].join("")
)
].join("\n");
}
1 change: 1 addition & 0 deletions web/src/core/usecases/serviceManager/thunks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./thunks";
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { id } from "tsafe/id";
import * as deploymentRegion from "../deploymentRegion";
import * as projectConfigs from "../projectConfigs";
import * as deploymentRegion from "core/usecases/deploymentRegion";
import * as projectConfigs from "core/usecases/projectConfigs";
import type { Thunks } from "core/core";
import { exclude } from "tsafe/exclude";
import { createUsecaseContextApi } from "redux-clean-architecture";
import { assert } from "tsafe/assert";
import { Evt } from "evt";
import { name, actions } from "./state";
import type { RunningService } from "./state";
import { name, actions } from "../state";
import type { RunningService } from "../state";
import type { OnyxiaApi } from "core/ports/OnyxiaApi";
import { formatHelmLsResp } from "./formatHelmCommands";

export const thunks = {
"setActive":
Expand Down Expand Up @@ -36,7 +38,7 @@ export const thunks = {
"update":
() =>
async (...args) => {
const [dispatch, getState, { onyxiaApi }] = args;
const [dispatch, getState] = args;

{
const state = getState()[name];
Expand All @@ -48,6 +50,8 @@ export const thunks = {

dispatch(actions.updateStarted());

const onyxiaApi = dispatch(privateThunks.getLoggedOnyxiaApi());

const runningServicesRaw = await onyxiaApi.getRunningServices();

//NOTE: We do not have the catalog id so we search in every catalog.
Expand Down Expand Up @@ -271,11 +275,73 @@ const privateThunks = {
s3TokensTTLms,
vaultTokenTTLms
})));
},
"getLoggedOnyxiaApi":
() =>
(...args): OnyxiaApi => {
const [dispatch, getState, extraArg] = args;

const sliceContext = getContext(extraArg);

{
const { loggedOnyxiaApi } = sliceContext;
if (loggedOnyxiaApi !== undefined) {
return loggedOnyxiaApi;
}
}

const { onyxiaApi } = extraArg;

sliceContext.loggedOnyxiaApi = {
...onyxiaApi,
"getRunningServices": async () => {
const { namespace: kubernetesNamespace } =
projectConfigs.selectors.selectedProject(getState());

const cmdId = Date.now();

const commandLogsEntry = {
cmdId,
"cmd": `helm list --namespace ${kubernetesNamespace}`,
"resp": undefined
};

dispatch(
actions.commandLogsEntryAdded({
commandLogsEntry
})
);

const runningServices = await onyxiaApi.getRunningServices();

dispatch(
actions.commandLogsRespUpdated({
cmdId,
"resp": formatHelmLsResp({
"lines": runningServices.map(runningService => ({
"name": runningService.packageName,
"namespace": kubernetesNamespace,
"revision": "TODO",
"updatedTime": runningService.startedAt,
"status": "TODO",
"chart": "TODO",
"appVersion": "TODO"
}))
})
})
);

return runningServices;
}
};

return dispatch(privateThunks.getLoggedOnyxiaApi());
}
} satisfies Thunks;

const { getContext } = createUsecaseContextApi(() => ({
"prDefaultTokenTTL": id<
Promise<{ s3TokensTTLms: number; vaultTokenTTLms: number }> | undefined
>(undefined)
>(undefined),
"loggedOnyxiaApi": id<OnyxiaApi | undefined>(undefined)
}));
13 changes: 10 additions & 3 deletions web/src/ui/pages/myServices/MyServices.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,10 @@ export default function MyServices(props: Props) {
</div>
{isCommandBarEnabled && (
<CommandBar
className={classes.commandBar}
classes={{
"root": classes.commandBar,
"rootWhenExpended": classes.commandBarWhenExpended
}}
entries={commandLogsEntries}
maxHeight={commandBarMaxHeight}
/>
Expand Down Expand Up @@ -421,10 +424,14 @@ const useStyles = tss
"commandBar": {
"position": "absolute",
"right": 0,
"width": "42%",
"top": commandBarTop,
"zIndex": 1,
"opacity": commandBarTop === 0 ? 0 : 1,
"transition": "opacity 750ms linear"
"transition": "opacity 750ms linear",
"width": "min(100%, 1100px)"
},
"commandBarWhenExpended": {
"width": "min(100%, 1350px)",
"transition": "width 70ms linear"
}
}));

0 comments on commit 3d188a1

Please sign in to comment.