diff --git a/Makefile b/Makefile
index 3120f24..3bc6190 100644
--- a/Makefile
+++ b/Makefile
@@ -16,6 +16,9 @@ install-extension: build-extension ## Install the extension
update-extension: build-extension ## Update the extension
docker extension update $(IMAGE):$(TAG)
+install-dev:
+ cd ui/ && npm install
+
debug: ## Start the extension in debug mode
docker extension dev debug $(IMAGE)
diff --git a/ui/src/components/Header/Controller.tsx b/ui/src/components/Header/Controller.tsx
index 09afea4..f338cab 100644
--- a/ui/src/components/Header/Controller.tsx
+++ b/ui/src/components/Header/Controller.tsx
@@ -14,6 +14,8 @@ import {
PRO_IMAGE,
COMMUNITY_IMAGE,
FLAGS_AS_STRING,
+ WIN_OS,
+ MAC_OS,
} from '../../constants';
import { LongMenu } from './Menu';
import { DockerContainer, DockerImage } from '../../types';
@@ -52,10 +54,10 @@ export const Controller = (): ReactElement => {
if (!hasSkippedConfiguration) {
switch (ddClient.host.platform) {
- case 'win32':
+ case WIN_OS:
location = `\\\\wsl$\\${os}\\home\\${user}\\.cache\\localstack\\volume`;
break;
- case 'darwin':
+ case MAC_OS:
location = `/Users/${user}/Library/Caches/localstack/volume`;
break;
default:
diff --git a/ui/src/components/Views/Configs/SettingsForm.tsx b/ui/src/components/Views/Configs/SettingsForm.tsx
index 47f756b..6c82d25 100644
--- a/ui/src/components/Views/Configs/SettingsForm.tsx
+++ b/ui/src/components/Views/Configs/SettingsForm.tsx
@@ -1,47 +1,24 @@
-import { ExecResult } from '@docker/extension-api-client-types/dist/v1';
-import {
- Box,
- Button,
- CircularProgress,
- Dialog,
- DialogContent,
- Divider,
- FormControl,
- MenuItem,
- Paper,
- Select,
- Step,
- StepLabel,
- Stepper,
- Typography,
-} from '@mui/material';
-import React, { ReactElement, useEffect, useState } from 'react';
-import {
- getOSsFromBinary,
- getUsersFromBinaryUnix,
- getUsersFromBinaryWindows,
- useDDClient,
- useMountPoint,
-} from '../../../services';
-import { ConfirmableButton } from '../../Feedback';
-
-const ShrinkedCircularProgress = (): ReactElement => ;
+import { Dialog, DialogContent, Step, StepLabel, Stepper } from '@mui/material';
+import React, { ReactElement, useState } from 'react';
+import { useDDClient } from '../../../services';
+import { StepZero, StepOne, StepTwo } from './Stepper';
interface MountPointFormProps {
initialState: number;
}
-export const SettingsForm = ({ initialState }: MountPointFormProps): ReactElement => {
-
- const [userState, setUserState] = useState({ loading: false, selectedUser: '', users: [] });
- const [osState, setOsState] = useState({ loading: false, selectedOS: '', OSs: [] });
- const [triggerUserCheck, setTriggerUserCheck] = useState(false);
+export const SettingsForm = ({
+ initialState,
+}: MountPointFormProps): ReactElement => {
const [activeStep, setActiveStep] = useState(initialState);
- const { setMountPointData, user, os } = useMountPoint();
const { client: ddClient } = useDDClient();
- const steps = ['Enable Docker Desktop option', 'Launching pro container', 'Set mount point'];
+ const steps = [
+ 'Enable Docker Desktop option',
+ 'Launching pro container',
+ 'Set mount point',
+ ];
const handleNext = () => {
if (activeStep !== steps.length - 1) {
@@ -53,98 +30,15 @@ export const SettingsForm = ({ initialState }: MountPointFormProps): ReactElemen
setActiveStep(activeStep - 1);
};
- const getMountPointPath = (): string => {
- if (ddClient.host.platform === 'darwin') {
- return `/Users/${userState.selectedUser || 'loading...'}/Library/Caches/localstack/volume`;
- }
- return `/home/${userState.selectedUser || 'loading...'}/.cache/localstack/volume`;
- };
-
- const checkWindowsDistro = async () => {
- setOsState({ ...osState, loading: true });
-
- const res = await ddClient.extension.host?.cli.exec('checkWSLOS.cmd', []);
-
- const foundOSs = getOSsFromBinary(res.stdout);
-
- setOsState({ loading: false, selectedOS: os || foundOSs[0], OSs: foundOSs });
- setTriggerUserCheck(true);
- };
-
- const checkUser = async () => {
- setUserState({ ...userState, loading: true });
-
- let res: ExecResult;
- let foundUsers = [];
- if (ddClient.host.platform === 'win32') {
- res = await ddClient.extension.host?.cli.exec('checkUser.cmd', [osState.selectedOS]);
- foundUsers = getUsersFromBinaryWindows(res.stdout);
- } else {
- res = await ddClient.extension.host?.cli.exec('checkUser.sh', []);
- foundUsers = getUsersFromBinaryUnix(res.stdout);
- }
-
- if (res.stderr || !res.stdout) {
- ddClient.desktopUI.toast.error(`Error while locating users: ${res.stderr} using /tmp as mount point`);
- closeWithoutSetting();
- }
-
- setUserState({ loading: false, selectedUser: user || foundUsers[0], users: foundUsers });
- };
-
- const locateMountPoint = async () => {
- if (ddClient.host.platform === 'win32') {
- checkWindowsDistro();
- } else {
- checkUser();
- }
- };
-
- useEffect(() => {
- const execChecks = async () => {
- if (userState.users.length === 0
- || (ddClient.host.platform === 'win32' && osState.OSs.length === 0)) {
- locateMountPoint();
- }
- };
-
- execChecks();
- }, []);
-
- useEffect(() => {
- if (osState.selectedOS) {
- checkUser();
- }
- }, [triggerUserCheck]);
-
- const saveAndClose = () => {
- setMountPointData({
- user: userState.selectedUser,
- os: osState.selectedOS,
- showForm: false,
- showSetupWarning: false,
- hasSkippedConfiguration: false,
- });
- };
-
- const closeWithoutSetting = () => {
- setMountPointData({
- user: userState.selectedUser,
- os: osState.selectedOS,
- showForm: false,
- showSetupWarning: false,
- hasSkippedConfiguration: true,
- });
- };
-
const onClose = () => {
ddClient.desktopUI.toast.warning('Complete the setup first');
};
- const handleOsChange = (target: string) => {
- setOsState({ ...osState, selectedOS: target });
- checkUser();
- };
+ const stepsList = [
+ ,
+ ,
+ ,
+ ];
return (
+
);
};
diff --git a/ui/src/components/Views/Configs/Stepper/StepOne.tsx b/ui/src/components/Views/Configs/Stepper/StepOne.tsx
new file mode 100644
index 0000000..fed9715
--- /dev/null
+++ b/ui/src/components/Views/Configs/Stepper/StepOne.tsx
@@ -0,0 +1,20 @@
+import { Typography } from '@mui/material';
+import React, { ReactElement } from 'react';
+import { StepTemplate, StepTemplateProps } from './StepTemplate';
+
+type Props = Pick;
+
+export const StepOne = ({ handleBack, handleNext }: Props): ReactElement => (
+
+
+ In order to start the Pro container, add a configuration with the variable
+ LOCALSTACK_AUTH_TOKEN set to your auth token and select that configuration
+ in the top right corner. API Keys are also supported, but will be
+ deprecated in the future.
+
+
+);
diff --git a/ui/src/components/Views/Configs/Stepper/StepTemplate.tsx b/ui/src/components/Views/Configs/Stepper/StepTemplate.tsx
new file mode 100644
index 0000000..229b771
--- /dev/null
+++ b/ui/src/components/Views/Configs/Stepper/StepTemplate.tsx
@@ -0,0 +1,34 @@
+import { Box, Button } from '@mui/material';
+import React, { ReactElement } from 'react';
+
+export type StepTemplateProps = {
+ children: ReactElement;
+ isFirstElement: boolean;
+ handleBack?: () => void;
+ handleNext?: () => void;
+ FinishActions?: ReactElement;
+};
+
+export const StepTemplate = ({
+ children,
+ isFirstElement,
+ handleNext,
+ handleBack,
+ FinishActions,
+}: StepTemplateProps): ReactElement => (
+ <>
+ {children}
+
+
+
+ {FinishActions ? (
+ { FinishActions }
+ ) : (
+
+ )}
+
+
+ >
+);
diff --git a/ui/src/components/Views/Configs/Stepper/StepTwo.tsx b/ui/src/components/Views/Configs/Stepper/StepTwo.tsx
new file mode 100644
index 0000000..0c2ed76
--- /dev/null
+++ b/ui/src/components/Views/Configs/Stepper/StepTwo.tsx
@@ -0,0 +1,251 @@
+import {
+ Button,
+ CircularProgress,
+ Divider,
+ FormControl,
+ MenuItem,
+ Paper,
+ Select,
+ Typography,
+} from '@mui/material';
+import React, { ReactElement, useEffect, useState } from 'react';
+import { ExecResult } from '@docker/extension-api-client-types/dist/v1';
+import { MAC_OS, WIN_OS } from '../../../../constants';
+import {
+ getOSsFromBinary,
+ getUsersFromBinaryUnix,
+ getUsersFromBinaryWindows,
+ useDDClient,
+ useMountPoint,
+} from '../../../../services';
+import { StepTemplate, StepTemplateProps } from './StepTemplate';
+import { ConfirmableButton } from '../../../Feedback';
+
+const ShrunkCircularProgress = (): ReactElement => (
+
+);
+
+type Props = Pick;
+export const StepTwo = ({ handleBack }: Props): ReactElement => {
+ const [userState, setUserState] = useState({
+ loading: false,
+ selectedUser: '',
+ users: [],
+ });
+ const [osState, setOsState] = useState({
+ loading: false,
+ selectedOS: '',
+ OSs: [],
+ });
+ const [triggerUserCheck, setTriggerUserCheck] = useState(false);
+
+ const { client: ddClient } = useDDClient();
+ const { setMountPointData, user, os } = useMountPoint();
+
+ const saveAndClose = () => {
+ setMountPointData({
+ user: userState.selectedUser,
+ os: osState.selectedOS,
+ showForm: false,
+ showSetupWarning: false,
+ hasSkippedConfiguration: false,
+ });
+ };
+
+ const closeWithoutSetting = () => {
+ setMountPointData({
+ user: userState.selectedUser,
+ os: osState.selectedOS,
+ showForm: false,
+ showSetupWarning: false,
+ hasSkippedConfiguration: true,
+ });
+ };
+ const getMountPointPath = (): string => {
+ if (ddClient.host.platform === MAC_OS) {
+ return `/Users/${
+ userState.selectedUser || 'loading...'
+ }/Library/Caches/localstack/volume`;
+ }
+ return `/home/${
+ userState.selectedUser || 'loading...'
+ }/.cache/localstack/volume`;
+ };
+
+ const checkUser = async () => {
+ setUserState({ ...userState, loading: true });
+
+ let res: ExecResult;
+ let foundUsers = [];
+ if (ddClient.host.platform === WIN_OS) {
+ res = await ddClient.extension.host?.cli.exec('checkUser.cmd', [
+ osState.selectedOS,
+ ]);
+ foundUsers = getUsersFromBinaryWindows(res.stdout);
+ } else {
+ res = await ddClient.extension.host?.cli.exec('checkUser.sh', []);
+ foundUsers = getUsersFromBinaryUnix(res.stdout);
+ }
+
+ if (res.stderr || !res.stdout) {
+ ddClient.desktopUI.toast.error(
+ `Error while locating users: ${res.stderr} using /tmp as mount point`,
+ );
+ closeWithoutSetting();
+ }
+
+ setUserState({
+ loading: false,
+ selectedUser: user || foundUsers[0],
+ users: foundUsers,
+ });
+ };
+
+ const checkWindowsDistro = async () => {
+ setOsState({ ...osState, loading: true });
+
+ const res = await ddClient.extension.host?.cli.exec('checkWSLOS.cmd', []);
+
+ const foundOSs = getOSsFromBinary(res.stdout);
+
+ setOsState({
+ loading: false,
+ selectedOS: os || foundOSs[0],
+ OSs: foundOSs,
+ });
+ setTriggerUserCheck(true);
+ };
+
+ const locateMountPoint = async () => {
+ if (ddClient.host.platform === WIN_OS) {
+ checkWindowsDistro();
+ } else {
+ checkUser();
+ }
+ };
+ useEffect(() => {
+ const execChecks = async () => {
+ if (
+ userState.users.length === 0 ||
+ (ddClient.host.platform === WIN_OS && osState.OSs.length === 0)
+ ) {
+ locateMountPoint();
+ }
+ };
+
+ execChecks();
+ }, []);
+
+ useEffect(() => {
+ if (osState.selectedOS) {
+ checkUser();
+ }
+ }, [triggerUserCheck]);
+
+ const handleOsChange = (target: string) => {
+ setOsState({ ...osState, selectedOS: target });
+ checkUser();
+ };
+
+ return (
+
+
+ Close
+
+
+ >
+ }
+ >
+ <>
+ Default mount point settings
+
+
+ {ddClient.host.platform === WIN_OS && (
+ <>
+ WSL distro
+
+ Select in which WSL distro you want to mount the container
+
+ {osState.loading ? (
+
+ ) : (
+
+
+
+ )}
+
+ >
+ )}
+ <>
+ User
+
+ Select under which user you want to mount the container
+
+ {userState.loading || osState.loading ? (
+
+ ) : (
+
+
+
+ )}
+ >
+
+
+
+ {`The LocalStack container will be mounted under ${getMountPointPath()}`}
+
+
+ *You can still change this by overriding the LOCALSTACK_VOLUME_DIR
+ environment variable
+
+ >
+
+ );
+};
diff --git a/ui/src/components/Views/Configs/Stepper/StepZero.tsx b/ui/src/components/Views/Configs/Stepper/StepZero.tsx
new file mode 100644
index 0000000..393c87f
--- /dev/null
+++ b/ui/src/components/Views/Configs/Stepper/StepZero.tsx
@@ -0,0 +1,24 @@
+import { Typography } from '@mui/material';
+import React, { ReactElement } from 'react';
+import { StepTemplate, StepTemplateProps } from './StepTemplate';
+
+type Props = Pick;
+
+export const StepZero = ({ handleNext }: Props): ReactElement => (
+
+ <>
+
+ Make sure to have the option "Show Docker Extensions system
+ containers" enabled. To enable it visit your settings:
+
+
+ - Navigate to Settings
+ - Select the Extensions tab
+ -
+ Next to Show Docker Extensions system containers, select the checkbox
+
+ - In the bottom-right corner, select Apply & Restart
+
+ >
+
+);
diff --git a/ui/src/components/Views/Configs/Stepper/index.ts b/ui/src/components/Views/Configs/Stepper/index.ts
new file mode 100644
index 0000000..254519c
--- /dev/null
+++ b/ui/src/components/Views/Configs/Stepper/index.ts
@@ -0,0 +1,3 @@
+export * from './StepOne';
+export * from './StepTwo';
+export * from './StepZero';
diff --git a/ui/src/constants/common.ts b/ui/src/constants/common.ts
index 2d44d1c..4e36850 100644
--- a/ui/src/constants/common.ts
+++ b/ui/src/constants/common.ts
@@ -2,3 +2,5 @@ export const DEFAULT_CONFIGURATION_ID = '00000000-0000-0000-0000-000000000000';
export const CORS_ALLOW_DEFAULT = 'http://localhost:3000';
export const COMMUNITY_IMAGE = 'localstack/localstack';
export const PRO_IMAGE = 'localstack/localstack-pro';
+export const WIN_OS = 'win32';
+export const MAC_OS = 'darwin';
diff --git a/ui/src/services/hooks/utils.ts b/ui/src/services/hooks/utils.ts
index cc22d13..a5e2cef 100644
--- a/ui/src/services/hooks/utils.ts
+++ b/ui/src/services/hooks/utils.ts
@@ -1,6 +1,7 @@
import { DockerDesktopClient } from '@docker/extension-api-client-types/dist/v1';
import { useContext } from 'react';
import { GlobalDDContext } from '../context/GlobalDDContext';
+import { MAC_OS, WIN_OS } from '../../constants';
export interface useDDClientReturn {
@@ -23,9 +24,9 @@ export const useDDClient = (): useDDClientReturn => {
}
let os = '';
- if (client.host.platform === 'darwin' || client.host.platform === 'linux') {
+ if (client.host.platform === MAC_OS || client.host.platform === 'linux') {
os = client.host.platform;
- } else if (client.host.platform === 'win32' && architecture === 'amd') {
+ } else if (client.host.platform === WIN_OS && architecture === 'amd') {
os = 'windows';
} else {
client.desktopUI.toast.error(