Skip to content

Commit aa94a39

Browse files
authored
improve user interface of the docker extension (#15)
* Added built for both amd64 and arm64 in workflow * Updated Readme and Dockerfile * added confirmation button to delete configuration * changed spacing in table * Start button shows only if no instance is running * restored otherwise update called but not shown * Safer status control * updated Images and order of controls * updated dockerfile * Updates in changelog, github actions and version * Updated README.md with changelog * Spacing * Fixed missing / * Fixed validation problems
1 parent cd12c05 commit aa94a39

File tree

12 files changed

+213
-76
lines changed

12 files changed

+213
-76
lines changed

.github/images/1-systemStatus.png

104 KB
Loading

.github/images/2-configuration.png

77.3 KB
Loading

.github/images/3-logs.png

202 KB
Loading
-1000 KB
Binary file not shown.

.github/workflows/build-push-docker.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ on:
55
branches: [ main ]
66
tags:
77
- "*"
8-
pull_request:
9-
branches: [ main ]
108

119
concurrency:
1210
group: docker-${{ github.ref }}
@@ -49,6 +47,7 @@ jobs:
4947
with:
5048
context: .
5149
file: "./Dockerfile"
50+
platforms: linux/amd64,linux/arm64
5251
push: ${{ github.event_name != 'pull_request' }}
5352
tags: ${{ steps.meta.outputs.tags }}
5453
labels: ${{ steps.meta.outputs.labels }}

Dockerfile

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,36 +3,67 @@ ENV CGO_ENABLED=0
33
WORKDIR /backend
44
COPY vm/go.* .
55
RUN --mount=type=cache,target=/go/pkg/mod \
6-
--mount=type=cache,target=/root/.cache/go-build \
7-
go mod download
6+
--mount=type=cache,target=/root/.cache/go-build \
7+
go mod download
88
COPY vm/. .
99
RUN --mount=type=cache,target=/go/pkg/mod \
10-
--mount=type=cache,target=/root/.cache/go-build \
11-
go build -trimpath -ldflags="-s -w" -o bin/service
10+
--mount=type=cache,target=/root/.cache/go-build \
11+
go build -trimpath -ldflags="-s -w" -o bin/service
1212

1313
FROM --platform=$BUILDPLATFORM node:17.7-alpine3.14 AS client-builder
1414
WORKDIR /ui
1515
# cache packages in layer
1616
COPY ui/package.json /ui/package.json
1717
COPY ui/package-lock.json /ui/package-lock.json
1818
RUN --mount=type=cache,target=/usr/src/app/.npm \
19-
npm set cache /usr/src/app/.npm && \
20-
npm ci
19+
npm set cache /usr/src/app/.npm && \
20+
npm ci
2121
# install
2222
COPY ui /ui
2323
RUN npm run build
2424

2525
FROM alpine
2626
LABEL org.opencontainers.image.title="LocalStack" \
27-
org.opencontainers.image.description="Extension of Localstack for Docker desktop" \
28-
org.opencontainers.image.vendor="LocalStack GmbH" \
29-
com.docker.desktop.extension.api.version=">= 0.2.3" \
30-
com.docker.desktop.extension.icon="https://avatars.githubusercontent.com/u/28732122?v=4" \
31-
com.docker.extension.screenshots="" \
32-
com.docker.extension.detailed-description="" \
33-
com.docker.extension.publisher-url="" \
34-
com.docker.extension.additional-urls="" \
35-
com.docker.extension.changelog=""
27+
org.opencontainers.image.description="Extension of Localstack for Docker desktop" \
28+
org.opencontainers.image.vendor="LocalStack GmbH" \
29+
com.docker.desktop.extension.api.version=">= 0.2.3" \
30+
com.docker.desktop.extension.icon="https://avatars.githubusercontent.com/u/28732122?v=4" \
31+
com.docker.extension.screenshots="[ \
32+
{\"alt\": \"System status\", \"url\": \"https://raw.githubusercontent.com/localstack/localstack-docker-extension/main/.github/images/1-systemStatus.png\"}, \
33+
{\"alt\": \"Edit configurations\", \"url\": \"https://raw.githubusercontent.com/localstack/localstack-docker-extension/main/.github/images/2-configuration.png\"}, \
34+
{\"alt\": \"Watch logs of the LocalStack running container \", \"url\": \"https://raw.githubusercontent.com/localstack/localstack-docker-extension/main/.github/images/3-logs.png\"} \
35+
]" \
36+
com.docker.extension.detailed-description="The LocalStack Extension for Docker Desktop enables developers working with LocalStack to run their AWS applications or Lambdas entirely \
37+
on their local machine without connecting to a remote cloud provider! LocalStack empowers developers to use over 75+ AWS services locally while helping them simplify their testing \
38+
and development workflow. LocalStack supports a comprehensive list of APIs, which you can view on our <a href=\"https://docs.localstack.cloud/user-guide/aws/feature-coverage/\"> \
39+
Feature coverage page</a>. <br><br> \
40+
Make sure to have also installed awscli-local. You can install it via pip: <b>pip install awscli-local</b> \
41+
<h2>This extension supports the following main features:</h2>\
42+
<ul>\
43+
<li> Control LocalStack: Start, stop, and restart LocalStack from the Docker Desktop. You can also see the current status of your LocalStack instance and navigate to LocalStack Web Application. </li>\
44+
<li> LocalStack insights: You can see the log information of the LocalStack instance and all the available services and their status on the service page. </li>\
45+
<li> LocalStack configurations: You can manage and use your profiles via configurations and create new configurations for your LocalStack instance. </li>\
46+
</ul>" \
47+
com.docker.extension.publisher-url="https://localstack.cloud/" \
48+
com.docker.extension.additional-urls="[ \
49+
{\"title\":\"GitHub Repository\", \"url\":\"https://github.com/localstack/localstack-docker-extension\"}, \
50+
{\"title\":\"Feedback and Issues\", \"url\":\"https://github.com/localstack/localstack-docker-extension/issues\"}\
51+
]" \
52+
com.docker.extension.changelog="We have introduced a new feature:<br/> \
53+
<ul> \
54+
<li> You can now update your LocalStack images from the UI </li> \
55+
</ul> \
56+
We have made some changes in the UI: \
57+
<ul> \
58+
<li> Updates in the control section </li> \
59+
<li> Moved to a table to display saved configurations </li> \
60+
<li> Improved UI for inserting a new configuration </li> \
61+
</ul> \
62+
Bug fixes:<br/> \
63+
<ul> \
64+
<li> Made configuration persistent </li> \
65+
<li> Logs are correctly displayed </li> \
66+
</ul>"
3667

3768
COPY --from=builder /backend/bin/service /
3869
COPY docker-compose.yaml .

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
IMAGE?=localstack/localstack-docker-desktop
2-
TAG?=0.1.0
2+
TAG?=0.2.0
33

44
BUILDER=buildx-multi-arch
55

README.md

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ The LocalStack Extension for Docker Desktop enables developers working with Loca
44

55
LocalStack empowers developers to use over 75+ AWS services locally while helping them simplify their testing and development workflow. LocalStack supports a comprehensive list of APIs, which you can view on our [Feature coverage](https://docs.localstack.cloud/aws/feature-coverage/) page.
66

7-
![Snap of LocalStack running on Docker Desktop as a Docker Extension](.github/images/localstack-docker-extension.png)
7+
![Snap of LocalStack running on Docker Desktop as a Docker Extension](.github/images/1-systemStatus.png)
88

99
## Installation
1010

@@ -22,8 +22,6 @@ make install-extension
2222

2323
It will build the Docker image and install the extension on your Docker Desktop application.
2424

25-
**Note**: We recommend you to add add `/tmp` to your shared files on Docker Desktop under **Settings** > **Resources** > **File sharing**. It is a temporary solution since it's where the LocalStack volume directory mounts.
26-
2725
## Features
2826

2927
Currently, the LocalStack Extension for Docker Desktop supports the following features:
@@ -55,6 +53,18 @@ To contribute, check out our [issue tracker](https://github.com/localstack/local
5553
$ docker extension dev ui-source localstack/localstack-docker-desktop http://localhost:3000
5654
```
5755

56+
## Changelog
57+
- v0.2.0:
58+
- You can now update your LocalStack images from the UI
59+
- We have made some changes in the UI:
60+
- Updates in the control section
61+
- Moved to a table to display saved configurations
62+
- Improved UI for inserting a new configuration
63+
- Bug fixes:
64+
- Made configuration persistent
65+
- Logs are correctly displayed
66+
67+
5868
## License
5969

6070
This software is released under the Apache License, Version 2.0 (see [`LICENSE`](LICENSE)).
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import React, { useState, ReactElement, ReactNode, FunctionComponent, MouseEvent } from 'react';
2+
3+
import {
4+
Button,
5+
IconButton,
6+
ButtonProps,
7+
MenuItem,
8+
Dialog,
9+
DialogTitle,
10+
DialogContent,
11+
DialogContentText,
12+
DialogActions,
13+
} from '@mui/material';
14+
15+
const COMPONENTS_MAP = {
16+
Button,
17+
IconButton,
18+
MenuItem,
19+
fallback: Button,
20+
};
21+
22+
export type BaseProps = {
23+
title: string;
24+
text?: string | JSX.Element;
25+
okText?: string;
26+
cancelText?: string;
27+
children?: ReactNode;
28+
}
29+
30+
type ComponentButton = (ButtonProps & { component: 'Button' }) & BaseProps
31+
type ComponentIconButton = (ButtonProps & { component: 'IconButton' }) & BaseProps
32+
type ComponentMenuItem = (ButtonProps & { component: 'MenuItem' }) & BaseProps
33+
34+
export type ConfirmableButtonProps =
35+
ComponentButton | ComponentIconButton | ComponentMenuItem;
36+
37+
export const ConfirmableButton = ({
38+
title,
39+
text,
40+
component = 'Button',
41+
okText,
42+
cancelText,
43+
children,
44+
...rest
45+
}: ConfirmableButtonProps): ReactElement => {
46+
const [showConfirmDialog, setShowConfirmDialog] = useState(false);
47+
48+
// eslint-disable-next-line
49+
const Component: FunctionComponent<any> = COMPONENTS_MAP[component] || COMPONENTS_MAP.fallback;
50+
51+
return (
52+
<>
53+
<Dialog
54+
open={showConfirmDialog}
55+
onClose={() => setShowConfirmDialog(false)}
56+
>
57+
<DialogTitle>{title}</DialogTitle>
58+
{text && (
59+
<DialogContent>
60+
{typeof text === 'string' ? (
61+
<DialogContentText>{text}</DialogContentText>
62+
) : (
63+
text
64+
)}
65+
</DialogContent>
66+
)}
67+
<DialogActions>
68+
<Button
69+
color="secondary"
70+
onClick={() => setShowConfirmDialog(false)}
71+
>
72+
{cancelText || 'Cancel'}
73+
</Button>
74+
<Button
75+
autoFocus
76+
color="primary"
77+
variant="contained"
78+
onClick={(event: MouseEvent<HTMLButtonElement>) => {
79+
if (rest.onClick) rest.onClick(event as any); // eslint-disable-line
80+
setShowConfirmDialog(false);
81+
}}
82+
>
83+
{okText || 'Continue'}
84+
</Button>
85+
</DialogActions>
86+
</Dialog>
87+
<Component {...rest} onClick={() => setShowConfirmDialog(true)}>
88+
{children}
89+
</Component>
90+
</>
91+
);
92+
};

ui/src/components/Configs/StartConfigs.tsx

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Add as AddIcon, Edit } from '@mui/icons-material';
1+
import { Add as AddIcon, Delete, Edit } from '@mui/icons-material';
22
import { Box, Button, IconButton, Theme } from '@mui/material';
33
import React, { ReactElement, useState } from 'react';
44
import { createStyles, makeStyles } from '@mui/styles';
@@ -8,6 +8,7 @@ import { useRunConfig } from '../../services/hooks';
88
import { UpsertConfig } from './UpsertConfig';
99
import { Optional, RunConfig } from '../../types';
1010
import { DEFAULT_CONFIGURATION_ID } from '../../constants';
11+
import { ConfirmableButton } from './ConfirmableButton';
1112

1213
const useStyles = makeStyles((theme: Theme) => createStyles({
1314
addButton: {
@@ -17,6 +18,7 @@ const useStyles = makeStyles((theme: Theme) => createStyles({
1718

1819
export const StartConfigs = (): ReactElement => {
1920

21+
const { deleteConfig } = useRunConfig();
2022
const { runConfig } = useRunConfig();
2123
const [openModal, setOpenModal] = useState<boolean>(false);
2224
const [targetConfig, setTargetConfig] = useState<RunConfig | null>(null);
@@ -30,30 +32,42 @@ export const StartConfigs = (): ReactElement => {
3032

3133
const columns: GridColDef<RunConfig>[] = [
3234
{
33-
field: 'Edit',
34-
headerName: 'Edit',
35-
width: 50,
35+
field: 'Actions',
36+
headerName: 'Actions',
37+
flex: 1,
38+
minWidth: 100,
3639
renderCell: (params: GridRenderCellParams) =>
3740
// eslint-disable-next-line react/jsx-no-useless-fragment
3841
<>
39-
{params.row.id !== DEFAULT_CONFIGURATION_ID &&
40-
<IconButton onClick={() => openModalSetup(params.row)} >
41-
<Edit />
42-
</IconButton>
43-
}
42+
<IconButton disabled={params.row.id === DEFAULT_CONFIGURATION_ID} onClick={() => openModalSetup(params.row)} >
43+
<Edit fontSize='small' />
44+
</IconButton>
45+
<ConfirmableButton
46+
component="IconButton"
47+
disabled={params.row.id === DEFAULT_CONFIGURATION_ID}
48+
title={`Remove ${params.row.name} configuration?`}
49+
onClick={() => deleteConfig(params.row.id)}
50+
text="Selected configuration will be permanently deleted"
51+
>
52+
<Delete fontSize='small' />
53+
</ConfirmableButton>
4454
</>,
4555
},
46-
{ field: 'name', headerName: 'Name', width: 300 },
56+
{
57+
field: 'name',
58+
headerName: 'Name',
59+
flex: 2,
60+
},
4761
{
4862
field: 'id',
4963
headerName: 'ID',
50-
width: 300,
64+
flex: 2,
5165
},
5266
{
5367
field: 'Configurations',
5468
headerName: 'Configurations',
5569
sortable: false,
56-
width: 900,
70+
flex: 5,
5771
renderCell: (params: GridRenderCellParams) =>
5872
(params.row as RunConfig).vars.map(setting => `${setting.variable}=${setting.value}`).join(', '),
5973
},

0 commit comments

Comments
 (0)