Skip to content

Commit f988bba

Browse files
authored
fix: Download correct image (#35)
* Now download correct image if not present * simplified if statement * Applied review suggestions
1 parent b6281ec commit f988bba

File tree

7 files changed

+44
-25
lines changed

7 files changed

+44
-25
lines changed

ui/src/components/Feedback/DownloadProgress/DownloadProgress.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import React, { ReactElement, useEffect, useState } from 'react';
22
import { useDDClient } from '../../../services';
33
import { CircularProgressWithLabel } from './CircularProgressWithLabel';
44

5-
const SKIPPING_KEYS = ['Digest', 'Status', 'latest'];
5+
const SKIPPING_KEY = 'latest';
6+
const END_KEYS = ['Digest', 'Status'];
67

78
const statusValues = new Map([
89
['Waiting', 0],
@@ -38,16 +39,17 @@ export const DownloadProgress = ({ callback, imageName }: DownloadProgressProps)
3839

3940
const [key, status] = data.stdout.split(':').map(item => item.trim());
4041

41-
if (SKIPPING_KEYS.includes(key) || status === 'latest') { // don't process lines that are not in the format hash: status
42+
if ([key, status].includes(SKIPPING_KEY)) { // prevent inserting in the map non related info
4243
return;
4344
}
4445

45-
if (status.startsWith('Image is up to date')) { // otherwise if Image is up to date nothing is downloaded and the progress remains to 0
46+
if (status.startsWith('Image is up to date') || END_KEYS.includes(key)) {
4647
setIsDone(true);
4748
return;
4849
}
49-
50-
setStatusMap(new Map(statusMap.set(key, status)));
50+
if (!status.startsWith('Retrying in')) {
51+
setStatusMap(new Map(statusMap.set(key, status)));
52+
}
5153
},
5254
onError(error: unknown): void {
5355
ddClient.desktopUI.toast.error('An error occurred');

ui/src/components/Header/Controller.tsx

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
11
import React, { ReactElement, useEffect, useState } from 'react';
22
import { Chip, ButtonGroup, Select, MenuItem, FormControl, Box, Badge, Tooltip } from '@mui/material';
33
import { PlayArrow, Stop } from '@mui/icons-material';
4-
import { isALocalStackContainer, useDDClient, useLocalStack, useMountPoint, useRunConfig } from '../../services';
4+
import {
5+
isALocalStackContainer,
6+
removeTagFromImage,
7+
useDDClient,
8+
useLocalStack,
9+
useMountPoint,
10+
useRunConfigs,
11+
} from '../../services';
512
import {
613
DEFAULT_CONFIGURATION_ID,
714
CORS_ALLOW_DEFAULT,
8-
LATEST_IMAGE,
915
START_ARGS,
1016
FLAGS,
17+
IMAGE,
18+
PRO_IMAGE,
1119
} from '../../constants';
1220
import { LongMenu } from './Menu';
1321
import { DockerContainer, DockerImage } from '../../types';
@@ -17,11 +25,11 @@ import { ProgressButton } from '../Feedback';
1725
const EXCLUDED_ERROR_TOAST = ['INFO', 'WARN', 'DEBUG'];
1826

1927
export const Controller = (): ReactElement => {
20-
const { runConfig, isLoading, createConfig } = useRunConfig();
28+
const { runConfigs, isLoading, createConfig } = useRunConfigs();
2129
const { data, mutate } = useLocalStack();
2230
const { user, os, hasSkippedConfiguration } = useMountPoint();
2331
const [runningConfig, setRunningConfig] = useState<string>('Default');
24-
const [downloadProps, setDownloadProps] = useState({ open: false, image: LATEST_IMAGE });
32+
const [downloadProps, setDownloadProps] = useState({ open: false, image: IMAGE });
2533
const [isStarting, setIsStarting] = useState<boolean>(false);
2634
const [isStopping, setIsStopping] = useState<boolean>(false);
2735
const ddClient = useDDClient();
@@ -30,7 +38,7 @@ export const Controller = (): ReactElement => {
3038
const tooltipLabel = isUnhealthy ? 'Unhealthy' : 'Healthy';
3139

3240
useEffect(() => {
33-
if (!isLoading && (!runConfig || !runConfig.find(item => item.name === 'Default'))) {
41+
if (!isLoading && (!runConfigs || !runConfigs.find(item => item.name === 'Default'))) {
3442
createConfig({
3543
name: 'Default', id: DEFAULT_CONFIGURATION_ID, vars: [],
3644
},
@@ -61,7 +69,7 @@ export const Controller = (): ReactElement => {
6169

6270
const corsArg = ['-e', `EXTRA_CORS_ALLOWED_ORIGINS=${CORS_ALLOW_DEFAULT}`];
6371

64-
const addedArgs = runConfig.find(config => config.name === runningConfig)
72+
const addedArgs = runConfigs.find(config => config.name === runningConfig)
6573
.vars.map(item => {
6674
if (item.variable === 'EXTRA_CORS_ALLOWED_ORIGINS') { // prevent overriding variable
6775
corsArg.slice(0, 0);
@@ -79,10 +87,15 @@ export const Controller = (): ReactElement => {
7987

8088
const start = async () => {
8189
const images = await ddClient.docker.listImages() as [DockerImage];
82-
const haveLocally = images.some(image => image.RepoTags?.at(0) === LATEST_IMAGE);
90+
91+
const isPro = runConfigs.find(config => config.name === runningConfig)
92+
.vars.some(item => item.variable === 'LOCALSTACK_API_KEY');
93+
94+
const imageToUse = isPro ? PRO_IMAGE : IMAGE;
95+
const haveLocally = images.some(image => removeTagFromImage(image) === imageToUse);
8396

8497
if (!haveLocally) {
85-
setDownloadProps({ open: true, image: LATEST_IMAGE });
98+
setDownloadProps({ open: true, image: imageToUse });
8699
return;
87100
}
88101
const args = await normalizeArguments();
@@ -164,7 +177,7 @@ export const Controller = (): ReactElement => {
164177
onChange={({ target }) => setRunningConfig(target.value)}
165178
>
166179
{
167-
runConfig?.map(config => (
180+
runConfigs?.map(config => (
168181
<MenuItem key={config.id} value={config.name}>{config.name}</MenuItem>
169182
))
170183
}

ui/src/components/Views/Configs/ConfigPage.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import React, { ReactElement, useState } from 'react';
44
import { createStyles, makeStyles } from '@mui/styles';
55
import { DataGrid, GridColDef, GridRenderCellParams } from '@mui/x-data-grid';
66
import { v4 as uuid } from 'uuid';
7-
import { useMountPoint, useRunConfig } from '../../../services';
7+
import { useMountPoint, useRunConfigs } from '../../../services';
88
import { DEFAULT_CONFIGURATION_ID } from '../../../constants';
99
import { RunConfig, Optional } from '../../../types';
1010
import { ConfirmableButton } from '../../Feedback';
@@ -18,7 +18,7 @@ const useStyles = makeStyles((theme: Theme) => createStyles({
1818

1919
export const ConfigPage = (): ReactElement => {
2020

21-
const { runConfig, deleteConfig } = useRunConfig();
21+
const { runConfigs, deleteConfig } = useRunConfigs();
2222
const mountPoint = useMountPoint();
2323
const [openModal, setOpenModal] = useState<boolean>(false);
2424
const [targetConfig, setTargetConfig] = useState<RunConfig | null>(null);
@@ -89,7 +89,7 @@ export const ConfigPage = (): ReactElement => {
8989
<Box sx={{ marginTop: 3 }}>
9090
<DataGrid
9191
autoHeight
92-
rows={runConfig.filter(config => config.id !== DEFAULT_CONFIGURATION_ID)}
92+
rows={runConfigs.filter(config => config.id !== DEFAULT_CONFIGURATION_ID)}
9393
columns={columns}
9494
getRowId={(row) => (row).id as string || uuid()}
9595
disableSelectionOnClick

ui/src/components/Views/Configs/UpsertConfig.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { Add, Remove, Settings } from '@mui/icons-material';
1515
import React, { ReactElement, useState } from 'react';
1616
import { v4 as uuid } from 'uuid';
1717
import { createStyles, makeStyles } from '@mui/styles';
18-
import { useRunConfig } from '../../../services/hooks';
18+
import { useRunConfigs } from '../../../services/hooks';
1919
import { RunConfig } from '../../../types';
2020

2121
const DEFAULT_COLUMN_WIDTH = 2000;
@@ -38,7 +38,7 @@ const useStyles = makeStyles((theme: Theme) => createStyles({
3838

3939
export const UpsertConfig = ({ config, open, onClose }: Props): ReactElement => {
4040

41-
const { updateConfig } = useRunConfig();
41+
const { updateConfig } = useRunConfigs();
4242
const [newVar, setNewVar] = useState<string>('');
4343
const [newValue, setNewValue] = useState<string>('');
4444
const [configName, setConfigName] = useState<string>(config?.name || '');

ui/src/constants/common.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export const DEFAULT_CONFIGURATION_ID='00000000-0000-0000-0000-000000000000';
22
export const CORS_ALLOW_DEFAULT='http://localhost:3000';
3-
export const LATEST_IMAGE = 'localstack/localstack:latest';
3+
export const IMAGE = 'localstack/localstack';
4+
export const PRO_IMAGE = 'localstack/localstack-pro';

ui/src/services/hooks/api.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import { DockerContainer, mountPointData, RunConfig } from '../../types';
44
import { isALocalStackContainer, isJson } from '../util';
55
import { useDDClient } from './utils';
66

7-
interface useRunConfigReturn {
8-
runConfig: RunConfig[],
7+
interface useRunConfigsReturn {
8+
runConfigs: RunConfig[],
99
isLoading: boolean,
1010
createConfig: (data: RunConfig) => unknown;
1111
updateConfig: (data: RunConfig) => unknown;
@@ -16,7 +16,7 @@ interface HTTPMessageBody {
1616
Message: string,
1717
}
1818

19-
export const useRunConfig = (): useRunConfigReturn => {
19+
export const useRunConfigs = (): useRunConfigsReturn => {
2020
const cacheKey = STORAGE_KEY_ENVVARS;
2121
const ddClient = useDDClient();
2222
const { data, mutate, isValidating, error } = useSWR(
@@ -40,7 +40,7 @@ export const useRunConfig = (): useRunConfigReturn => {
4040
};
4141

4242
return {
43-
runConfig: (!data || !data?.Message || error) ? [] : JSON.parse(data?.Message),
43+
runConfigs: (!data || !data?.Message || error) ? [] : JSON.parse(data?.Message),
4444
isLoading: isValidating || (!error && !data),
4545
createConfig,
4646
updateConfig,

ui/src/services/util/containers.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { DockerContainer } from '../../types';
1+
import { DockerContainer, DockerImage } from '../../types';
22

33
/**
44
* Removes repo from image identifier
@@ -10,6 +10,9 @@ export function removeRepoFromImage(repoTag: string) {
1010
return repoTag.split('/').at(-1);
1111
}
1212

13+
export function removeTagFromImage(image: DockerImage){
14+
return image.RepoTags[0].split(':').slice(0, -1).join(':');
15+
}
1316

1417
export const isALocalStackContainer = (container: DockerContainer) =>
1518
(container.Image === 'localstack/localstack' || container.Image === 'localstack/localstack-pro');

0 commit comments

Comments
 (0)