Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
7d95dc2
Rename file referring to other platforms
t-kikuc May 3, 2024
590e649
Add ECS to live-state protobuf
t-kikuc May 3, 2024
b1a4e6e
Impl ECS APIs
t-kikuc May 4, 2024
31cdabe
Impl ECS's state.go
t-kikuc May 4, 2024
cda4764
Fix the healthDescription because a task has two statuses
t-kikuc May 4, 2024
8f65a95
Add GetClusterTasks func
t-kikuc May 5, 2024
44931c8
draft: add ecs store.go
t-kikuc May 7, 2024
40c4333
Add ECSApplicationLiveState to ApplicationLiveStateSnapshot and gen code
t-kikuc Jun 10, 2024
85c2618
Fix typo: ECSRun -> ECS
t-kikuc Jun 10, 2024
23fde0d
draft: reporter, model
t-kikuc Jun 10, 2024
11ec154
remove applicationLister from ECS
t-kikuc Jun 12, 2024
22c3152
Define blank funcs in Getter
t-kikuc Jun 12, 2024
8d6cecd
impl NewStore, GetManifests, GetState, WaitForReady
t-kikuc Jun 12, 2024
cbac8ed
Add GetTaskDefinition()
t-kikuc Jun 13, 2024
842915c
fix comment
t-kikuc Jun 13, 2024
9304b16
Revert "Add GetTaskDefinition()"
t-kikuc Jun 13, 2024
2feb9ec
Revert "Revert "Add GetTaskDefinition()""
t-kikuc Jun 13, 2024
6dbaa71
impl store.go
t-kikuc Jun 13, 2024
a30e1fb
Impl ecs.go > Run()
t-kikuc Jun 13, 2024
934950c
impl ecs/report.go]
t-kikuc Jun 13, 2024
04f364b
add switch case of ECS
t-kikuc Jun 13, 2024
66fd1dd
fix livestatestore v1 for ecs
t-kikuc Jun 13, 2024
eb92e76
Add ecs/state_test.go
t-kikuc Jun 14, 2024
a43ee22
fix comments
t-kikuc Jun 14, 2024
c299405
remove comment
t-kikuc Jun 14, 2024
0622690
Remove TODO comment
t-kikuc Jun 14, 2024
1007be3
Remove standalone tasks states
t-kikuc Jun 14, 2024
53c5971
fix fetching ecs resources
t-kikuc Jun 17, 2024
c3e9e5f
Fix appId key in store: use appId tag
t-kikuc Jun 18, 2024
e6b1ee6
Remove validation of ApiVersion of ECS
t-kikuc Jun 18, 2024
516d5bd
Merge branch 'master' of https://github.com/pipe-cd/pipecd into ecs-l…
t-kikuc Jun 18, 2024
bc8eb77
Fix updatedAt of ECS Service to pass validation
t-kikuc Jun 18, 2024
18c048c
Use VersionV1Beta1 for ECS states
t-kikuc Jun 18, 2024
facbff2
Revert "Remove validation of ApiVersion of ECS"
t-kikuc Jun 18, 2024
730460d
Fix comments
t-kikuc Jun 18, 2024
7c0ab99
fix pipedv1
t-kikuc Jun 19, 2024
ac5ade7
fix test: add apiversion, updatedat
t-kikuc Jun 19, 2024
0cab4c7
remove comment-outed namespace
t-kikuc Jun 19, 2024
01a5abf
Merge branch 'master' into ecs-live-state-store
t-kikuc Jun 26, 2024
a8bcb30
Merge branch 'ecs-live-state-store' into ecs-live-state-ui
t-kikuc Jun 26, 2024
5a53f4b
Export ECSResourceState
t-kikuc Jun 26, 2024
94e77e4
add ECSResourceHealthStatusIcon index.tsx
t-kikuc Jun 26, 2024
87e6436
Add ECSResource index.tsx
t-kikuc Jun 26, 2024
ec76467
Add ECSResourceDetail index.tsx
t-kikuc Jun 26, 2024
e2e7398
Add ECSStateView index.tsx
t-kikuc Jun 26, 2024
30c2593
Add ECS as supported kind for livestate UI
t-kikuc Jun 26, 2024
b869b70
Use ID for ResourceState of taskset and task
t-kikuc Jun 27, 2024
3adaa79
Merge branch 'ecs-live-state-store' of https://github.com/pipe-cd/pip…
t-kikuc Jun 27, 2024
7c87085
Merge branch 'ecs-live-state-store' into ecs-live-state-ui
t-kikuc Jun 27, 2024
29113ae
Fix nits: arrange import section
t-kikuc Jul 2, 2024
6384285
Merge branch 'ecs-live-state-store' into ecs-live-state-ui
t-kikuc Jul 3, 2024
8a4c5c9
Fix graph
t-kikuc Jul 3, 2024
ba4decb
fix lint/web by `make lint/web FIX=true`
t-kikuc Jul 3, 2024
2d92252
Merge branch 'master' into ecs-live-state-store
t-kikuc Jul 4, 2024
73051fd
Merge branch 'master' into ecs-live-state-ui
t-kikuc Jul 8, 2024
93edc0d
Remove ApiVersion & Namespace from ECSResourceState
t-kikuc Jul 16, 2024
865df89
Merge branch 'ecs-live-state-store' of https://github.com/pipe-cd/pip…
t-kikuc Jul 16, 2024
154bff2
Merge branch 'ecs-live-state-store' into ecs-live-state-ui
t-kikuc Jul 16, 2024
9b740ac
Merge branch 'ecs-live-state-ui' of https://github.com/pipe-cd/pipecd…
t-kikuc Jul 16, 2024
f9cc52c
Remove ApiVersion from ECSStateView
t-kikuc Jul 16, 2024
3531eaa
Merge branch 'master' into ecs-live-state-ui
t-kikuc Jul 22, 2024
e7f2b34
fix indent
t-kikuc Jul 22, 2024
e670983
Merge branch 'master' into ecs-live-state-ui
t-kikuc Jul 23, 2024
7926720
[debug] add debug logs
t-kikuc Jul 23, 2024
2495c62
add dummyApplicationLiveState of ecs
t-kikuc Jul 24, 2024
9a80484
Revert "[debug] add debug logs"
t-kikuc Jul 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions web/src/__fixtures__/dummy-application-live-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export const dummyApplicationLiveState: ApplicationLiveState = {
cloudrun: { resourcesList: [] },
lambda: {},
terraform: {},
ecs: { resourcesList: [] },
kubernetes: { resourcesList },
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { IconButton, makeStyles, Paper, Typography } from "@material-ui/core";
import CloseIcon from "@material-ui/icons/Close";
import { FC } from "react";

const DETAIL_WIDTH = 400;

const useStyles = makeStyles((theme) => ({
root: {
width: DETAIL_WIDTH,
padding: "16px 24px",
height: "100%",
overflow: "auto",
position: "relative",
zIndex: 2,
},
closeButton: {
position: "absolute",
right: theme.spacing(1),
top: theme.spacing(1),
color: theme.palette.grey[500],
},
name: {
paddingRight: theme.spacing(4),
wordBreak: "break-all",
paddingBottom: theme.spacing(2),
},
section: {
paddingTop: theme.spacing(1),
display: "flex",
alignItems: "center",
},
sectionTitle: {
color: theme.palette.text.secondary,
minWidth: 120,
},
sectionBody: {
flex: 1,
wordBreak: "break-all",
},
multilineSection: {
paddingTop: theme.spacing(1),
},
}));

export interface ECSResourceDetailProps {
resource: {
name: string;
kind: string;
healthDescription: string;
};
onClose: () => void;
}

export const ECSResourceDetail: FC<ECSResourceDetailProps> = ({
resource,
onClose,
}) => {
const classes = useStyles();
return (
<Paper className={classes.root} square>
<IconButton className={classes.closeButton} onClick={onClose}>
<CloseIcon />
</IconButton>
<Typography variant="h6" className={classes.name}>
{resource.name}
</Typography>

<div className={classes.section}>
<Typography variant="subtitle1" className={classes.sectionTitle}>
Kind
</Typography>
<Typography variant="body1" className={classes.sectionBody}>
{resource.kind}
</Typography>
</div>

<div className={classes.multilineSection}>
<Typography variant="subtitle1" className={classes.sectionTitle}>
Health Description
</Typography>
<Typography variant="body1">
{resource.healthDescription || "Empty"}
</Typography>
</div>
</Paper>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { makeStyles } from "@material-ui/core";
import UnknownIcon from "@material-ui/icons/ErrorOutline";
import FavoriteIcon from "@material-ui/icons/Favorite";
import OtherIcon from "@material-ui/icons/HelpOutline";
import { FC, memo } from "react";
import { HealthStatus } from "~/modules/applications-live-state";

const useStyles = makeStyles((theme) => ({
healthy: {
color: theme.palette.success.main,
},
unknown: {
color: theme.palette.warning.main,
},
other: {
color: theme.palette.info.main,
},
}));

export interface ECSResourceHealthStatusIconProps {
health: HealthStatus;
}

export const ECSResourceHealthStatusIcon: FC<ECSResourceHealthStatusIconProps> = memo(
function HealthStatusIcon({ health }) {
const classes = useStyles();
switch (health) {
case HealthStatus.UNKNOWN:
return <UnknownIcon fontSize="small" className={classes.unknown} />;
case HealthStatus.HEALTHY:
return <FavoriteIcon fontSize="small" className={classes.healthy} />;
case HealthStatus.OTHER:
return <OtherIcon fontSize="small" className={classes.other} />;
}
}
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { makeStyles, Paper, Typography } from "@material-ui/core";
import { FC, memo } from "react";
import { ECSResourceState } from "~/modules/applications-live-state";
import { ECSResourceHealthStatusIcon } from "./health-status-icon";

const useStyles = makeStyles((theme) => ({
root: {
display: "inline-flex",
flexDirection: "column",
padding: theme.spacing(2),
width: 300,
cursor: "pointer",
},
nameLine: {
display: "flex",
},
name: {
marginLeft: theme.spacing(0.5),
},
}));

export interface ECSResourceProps {
resource: ECSResourceState.AsObject;
onClick: (resource: ECSResourceState.AsObject) => void;
}

export const ECSResource: FC<ECSResourceProps> = memo(function ECSResource({
resource,
onClick,
}) {
const classes = useStyles();
return (
<Paper square className={classes.root} onClick={() => onClick(resource)}>
<Typography variant="caption">{resource.kind}</Typography>
<div className={classes.nameLine}>
<ECSResourceHealthStatusIcon health={resource.healthStatus} />
<Typography variant="subtitle2" className={classes.name}>
{resource.name}
</Typography>
</div>
</Paper>
);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import { Box, makeStyles } from "@material-ui/core";
import clsx from "clsx";
import dagre from "dagre";
import { FC, useState } from "react";
import { ECSResourceState } from "~/modules/applications-live-state";
import { theme } from "~/theme";
import { ECSResource } from "./ecs-resource";
import { ECSResourceDetail } from "./ecs-resource-detail";

const useStyles = makeStyles((theme) => ({
root: {
display: "flex",
flex: 1,
justifyContent: "center",
overflow: "hidden",
},
stateViewWrapper: {
flex: 1,
display: "flex",
justifyContent: "center",
overflow: "hidden",
},
stateView: {
position: "relative",
overflow: "auto",
},
closeDetailButton: {
position: "absolute",
right: theme.spacing(1),
top: theme.spacing(1),
color: theme.palette.grey[500],
},
}));

export interface ECSStateViewProps {
resources: ECSResourceState.AsObject[];
}

const NODE_HEIGHT = 72;
const NODE_WIDTH = 300;
const STROKE_WIDTH = 2;
const SVG_RENDER_PADDING = STROKE_WIDTH * 2;

function useGraph(
resources: ECSResourceState.AsObject[]
): dagre.graphlib.Graph<{
resource: ECSResourceState.AsObject;
}> {
const graph = new dagre.graphlib.Graph<{
resource: ECSResourceState.AsObject;
}>();
graph.setGraph({ rankdir: "LR", align: "UL" });
graph.setDefaultEdgeLabel(() => ({}));

resources.forEach((resource) => {
graph.setNode(resource.id, {
resource,
height: NODE_HEIGHT,
width: NODE_WIDTH,
});
// 'Service' does not need parent nodes.
if (resource.kind != "Service" && resource.parentIdsList.length > 0) {
resource.parentIdsList.forEach((parentId) => {
graph.setEdge(parentId, resource.id);
});
}
});

// Update after change graph
dagre.layout(graph);

return graph;
}

export const ECSStateView: FC<ECSStateViewProps> = ({ resources }) => {
const classes = useStyles();
const [
selectedResource,
setSelectedResource,
] = useState<ECSResourceState.AsObject | null>(null);

const graph = useGraph(resources);
const nodes = graph
.nodes()
.map((v) => graph.node(v))
.filter(Boolean);

const graphInstance = graph.graph();

return (
<div className={clsx(classes.root)}>
<div className={classes.stateViewWrapper}>
<div className={classes.stateView}>
{nodes.map((node) => (
<Box
key={`${node.resource.kind}-${node.resource.name}`}
position="absolute"
top={node.y}
left={node.x}
zIndex={1}
data-testid="ecs-resource"
>
<ECSResource
resource={node.resource}
onClick={setSelectedResource}
/>
</Box>
))}
{
// render edges
graph.edges().map((v, i) => {
const edge = graph.edge(v);
let baseX = Infinity;
let baseY = Infinity;
let svgWidth = 0;
let svgHeight = 0;
edge.points.forEach((p) => {
baseX = Math.min(baseX, p.x);
baseY = Math.min(baseY, p.y);
svgWidth = Math.max(svgWidth, p.x);
svgHeight = Math.max(svgHeight, p.y);
});
baseX = Math.round(baseX);
baseY = Math.round(baseY);
// NOTE: Add padding to SVG sizes for showing edges completely.
// If you use the same size as the polyline points, it may hide the some strokes.
svgWidth = Math.ceil(svgWidth - baseX) + SVG_RENDER_PADDING;
svgHeight = Math.ceil(svgHeight - baseY) + SVG_RENDER_PADDING;
return (
<svg
key={`edge-${i}`}
style={{
position: "absolute",
top: baseY + NODE_HEIGHT / 2,
left: baseX + NODE_WIDTH / 2,
}}
width={svgWidth}
height={svgHeight}
>
<polyline
points={edge.points.reduce((prev, current) => {
return (
prev +
`${Math.round(current.x - baseX) + STROKE_WIDTH},${
Math.round(current.y - baseY) + STROKE_WIDTH
} `
);
}, "")}
strokeWidth={STROKE_WIDTH}
stroke={theme.palette.divider}
fill="transparent"
/>
</svg>
);
})
}
{graphInstance && (
<div
style={{
width: (graphInstance.width ?? 0) + NODE_WIDTH,
height: (graphInstance.height ?? 0) + NODE_HEIGHT,
}}
/>
)}
</div>
</div>

{selectedResource && (
<ECSResourceDetail
resource={selectedResource}
onClose={() => setSelectedResource(null)}
/>
)}
</div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ import {
} from "~/modules/applications-live-state";
import { KubernetesStateView } from "./kubernetes-state-view";
import { CloudRunStateView } from "./cloudrun-state-view";
import { ECSStateView } from "./ecs-state-view";

const isDisplayLiveState = (app: Application.AsObject | undefined): boolean => {
return (
app?.kind === ApplicationKind.KUBERNETES ||
app?.kind === ApplicationKind.CLOUDRUN
app?.kind === ApplicationKind.CLOUDRUN ||
app?.kind === ApplicationKind.ECS
);
};

Expand Down Expand Up @@ -77,12 +79,12 @@ export const ApplicationStateView: FC<ApplicationStateViewProps> = memo(

useInterval(
() => {
// Only fetch kubernetes or cloud run application.
// Fetch only supported kind applications.
if (app && isDisplayLiveState(app)) {
dispatch(fetchApplicationStateById(app.id));
}
},
// Only fetch kubernetes or cloud run application.
// Fetch only supported kind applications.
isDisplayLiveState(app) && hasError === false ? FETCH_INTERVAL : null
);

Expand Down Expand Up @@ -149,6 +151,10 @@ export const ApplicationStateView: FC<ApplicationStateViewProps> = memo(
const resources = liveState.cloudrun?.resourcesList || [];
return <CloudRunStateView resources={resources} />;
}
case ApplicationKind.ECS: {
const resources = liveState.ecs?.resourcesList || [];
return <ECSStateView resources={resources} />;
}
default:
}

Expand Down
Loading