Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
IMAGE?=localstack/localstack-docker-desktop
TAG?=0.5.4
TAG?=0.5.5

BUILDER=buildx-multi-arch

Expand Down
128 changes: 87 additions & 41 deletions ui/src/services/hooks/api.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,53 @@
import useSWR from 'swr';
import { STORAGE_KEY_ENVVARS, STORAGE_KEY_LOCALSTACK, STORAGE_KEY_MOUNT } from '../../constants';
import { ConfigData, DockerContainer, mountPointData, RunConfig } from '../../types';
import {
STORAGE_KEY_ENVVARS,
STORAGE_KEY_LOCALSTACK,
STORAGE_KEY_MOUNT,
} from '../../constants';
import {
ConfigData,
DockerContainer,
mountPointData,
RunConfig,
} from '../../types';
import { isALocalStackContainer, isJson } from '../util';
import { useDDClient } from './utils';

interface useRunConfigsReturn {
configData: ConfigData,
isLoading: boolean,
configData: ConfigData;
isLoading: boolean;
setRunningConfig: (data: string) => unknown;
createConfig: (data: RunConfig) => unknown;
updateConfig: (data: RunConfig) => unknown;
deleteConfig: (data: string) => unknown;
}

interface HTTPMessage {
data: {
Message: string,
},
}
// This is what backend calls send in MacOS
type BaseMessage = {
Message: string;
};

// This is what backend calls send on Linux
type LinuxMessage = {
data: BaseMessage;
};

type HTTPMessage = LinuxMessage | BaseMessage;

const isBaseMessage = (msg: HTTPMessage): msg is BaseMessage => (msg as BaseMessage).Message !== undefined;

const resolveOSMessage = (message: HTTPMessage | undefined): BaseMessage | undefined => {
if (!message) return undefined;
if (isBaseMessage(message)) return message;
return message.data;
};

const adaptVersionData = (message: HTTPMessage, error: Error) => {
const newData = (!message || !message.data?.Message || error) ?
{ configs: [], runningConfig: null }
:
JSON.parse(message.data?.Message);
const data = resolveOSMessage(message);
const newData =
!data || !data?.Message || error
? { configs: [], runningConfig: null }
: JSON.parse(data?.Message);
if (Array.isArray(newData)) {
return { configs: newData, runningConfig: newData.at(0).id ?? null };
}
Expand All @@ -35,21 +59,27 @@ export const useRunConfigs = (): useRunConfigsReturn => {
const { client: ddClient } = useDDClient();
const { data, mutate, isValidating, error } = useSWR(
cacheKey,
() => (ddClient.extension.vm.service.get('/configs') as Promise<HTTPMessage>),
() => ddClient.extension.vm.service.get('/configs') as Promise<HTTPMessage>,
);

const updateConfig = async (newData: RunConfig) => {
await ddClient.extension.vm.service.put('/configs', { Data: JSON.stringify(newData) });
await ddClient.extension.vm.service.put('/configs', {
Data: JSON.stringify(newData),
});
mutate();
};

const setRunningConfig = async (configId: string) => {
await ddClient.extension.vm.service.put('/configs/running', { Data: JSON.stringify(configId) });
await ddClient.extension.vm.service.put('/configs/running', {
Data: JSON.stringify(configId),
});
mutate();
};

const createConfig = async (newData: RunConfig) => {
await ddClient.extension.vm.service.post('/configs', { Data: JSON.stringify(newData) });
await ddClient.extension.vm.service.post('/configs', {
Data: JSON.stringify(newData),
});
mutate();
};

Expand All @@ -58,7 +88,6 @@ export const useRunConfigs = (): useRunConfigsReturn => {
mutate();
};


return {
configData: adaptVersionData(data, error),
isLoading: isValidating || (!error && !data),
Expand All @@ -70,12 +99,12 @@ export const useRunConfigs = (): useRunConfigsReturn => {
};

interface useMountPointReturn {
user: string | null,
os: string | null,
showForm: boolean,
showSetupWarning: boolean,
hasSkippedConfiguration: boolean,
isLoading: boolean,
user: string | null;
os: string | null;
showForm: boolean;
showSetupWarning: boolean;
hasSkippedConfiguration: boolean;
isLoading: boolean;
setMountPointData: (data: mountPointData) => void;
}

Expand All @@ -85,30 +114,41 @@ export const useMountPoint = (): useMountPointReturn => {

const { data, mutate, isValidating, error } = useSWR(
cacheKey,
async () => (ddClient.extension.vm.service.get('/mount') as Promise<HTTPMessage>),
async () =>
ddClient.extension.vm.service.get('/mount') as Promise<HTTPMessage>,
);

const setMountPointData = async (data: mountPointData) => {
await ddClient.extension.vm.service.post('/mount', { Data: JSON.stringify(data) });
await ddClient.extension.vm.service.post('/mount', {
Data: JSON.stringify(data),
});
mutate();
};

const fileContent = (!error && data) ? data.data.Message : null;
const mountPointData = isJson(fileContent) ? JSON.parse(fileContent) as mountPointData : null;
const adaptedData = resolveOSMessage(data);

const fileContent = !error && adaptedData ? adaptedData.Message : null;
const mountPointData = isJson(fileContent)
? (JSON.parse(fileContent) as mountPointData)
: null;

return {
user: mountPointData?.user,
os: mountPointData?.os,
showForm: mountPointData?.showForm == null ? true : mountPointData?.showForm,
showSetupWarning: mountPointData?.showSetupWarning == null ? true : mountPointData?.showSetupWarning,
showForm:
mountPointData?.showForm == null ? true : mountPointData?.showForm,
showSetupWarning:
mountPointData?.showSetupWarning == null
? true
: mountPointData?.showSetupWarning,
hasSkippedConfiguration: mountPointData?.hasSkippedConfiguration || false,
isLoading: isValidating || (!error && !data),
isLoading: isValidating || (!error && !adaptedData),
setMountPointData,
};
};

interface useLocalStackReturn {
data: DockerContainer | null,
data: DockerContainer | null;
mutate: () => void;
}

Expand All @@ -118,15 +158,21 @@ export const useLocalStack = (): useLocalStackReturn => {

const { data, mutate } = useSWR(
cacheKey,
async () => (await ddClient.docker.listContainers() as [DockerContainer])
.find(container =>
isALocalStackContainer(container) && container.Command !== 'bin/localstack update docker-images',
), {
refreshInterval: 2000, compare:
/*
* compares whether the old (b) status aligns with that of new (a) status
*/
(a, b) => a?.Id === b?.Id && a?.Status.includes('unhealthy') === b?.Status.includes('unhealthy'),
async () =>
((await ddClient.docker.listContainers()) as [DockerContainer]).find(
(container) =>
isALocalStackContainer(container) &&
container.Command !== 'bin/localstack update docker-images',
),
{
refreshInterval: 2000,
compare:
/*
* compares whether the old (b) status aligns with that of new (a) status
*/
(a, b) =>
a?.Id === b?.Id &&
a?.Status.includes('unhealthy') === b?.Status.includes('unhealthy'),
},
);

Expand Down