diff --git a/.github/workflows/deployment-test.yml b/.github/workflows/deployment-test.yml
index 19d9e761..3c8dc91d 100644
--- a/.github/workflows/deployment-test.yml
+++ b/.github/workflows/deployment-test.yml
@@ -104,7 +104,7 @@ jobs:
test:
needs: [deploy]
- timeout-minutes: 15
+ timeout-minutes: 30
runs-on: ubuntu-latest
steps:
diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml
index 3df55c88..24733694 100644
--- a/.github/workflows/playwright.yml
+++ b/.github/workflows/playwright.yml
@@ -10,7 +10,7 @@ on:
jobs:
playwright:
- timeout-minutes: 15
+ timeout-minutes: 30
runs-on: ubuntu-latest
steps:
diff --git a/apps/client/index.html b/apps/client/index.html
index cceaf540..977e87aa 100644
--- a/apps/client/index.html
+++ b/apps/client/index.html
@@ -8,6 +8,7 @@
+
diff --git a/apps/client/package.json b/apps/client/package.json
index 26053975..e442916e 100644
--- a/apps/client/package.json
+++ b/apps/client/package.json
@@ -27,17 +27,17 @@
"@aws-sdk/client-iot-events": "3.515.0",
"@aws-sdk/client-iotsitewise": "3.515.0",
"@aws-sdk/credential-providers": "3.515.0",
- "@cloudscape-design/collection-hooks": "^1.0.36",
+ "@cloudscape-design/collection-hooks": "^1.0.37",
"@cloudscape-design/component-toolkit": "^1.0.0-beta.38",
"@cloudscape-design/components": "^3.0.518",
"@cloudscape-design/design-tokens": "3.0.34",
"@cloudscape-design/global-styles": "^1.0.23",
- "@iot-app-kit/core": "10.0.0",
- "@iot-app-kit/dashboard": "10.0.0",
- "@tanstack/react-query": "^5.22.2",
+ "@iot-app-kit/core": "10.2.0",
+ "@iot-app-kit/dashboard": "10.2.0",
+ "@tanstack/react-query": "^5.24.1",
"aws-amplify": "^5.3.11",
"axios": "^1.6.7",
- "cytoscape": "^3.27.0",
+ "cytoscape": "^3.28.1",
"jotai": "^2.6.4",
"nanoid": "3.1.31",
"react": "^18.2.0",
@@ -49,7 +49,7 @@
"react-use": "^17.4.2",
"tiny-invariant": "^1.3.1",
"uuid": "^9.0.1",
- "vite": "^5.0.12",
+ "vite": "^5.1.5",
"web-vitals": "^3.5.0"
},
"devDependencies": {
@@ -59,12 +59,12 @@
"@hookform/devtools": "^4.3.1",
"@originjs/vite-plugin-federation": "^1.3.3",
"@tanstack/eslint-plugin-query": "^5.20.1",
- "@tanstack/react-query-devtools": "^5.24.0",
+ "@tanstack/react-query-devtools": "^5.24.1",
"@testing-library/jest-dom": "^6.4.2",
"@testing-library/react": "^14.1.0",
"@testing-library/react-hooks": "^8.0.1",
"@testing-library/user-event": "^14.5.2",
- "@types/react": "^18.2.57",
+ "@types/react": "^18.2.61",
"@types/react-dom": "^18.2.19",
"@types/uuid": "^9.0.8",
"@vitejs/plugin-react": "^4.2.1",
@@ -72,7 +72,7 @@
"@vitest/ui": "^1.1.1",
"aws-sdk-client-mock": "^3.0.0",
"aws-sdk-client-mock-jest": "^3.0.0",
- "babel-plugin-formatjs": "^10.5.12",
+ "babel-plugin-formatjs": "^10.5.13",
"customize-cra": "^1.0.0",
"eslint-config-custom": "*",
"eslint-plugin-formatjs": "^4.11.1",
diff --git a/apps/client/src/auth/auth-service.interface.ts b/apps/client/src/auth/auth-service.interface.ts
index c7fcceb0..b75dd0be 100644
--- a/apps/client/src/auth/auth-service.interface.ts
+++ b/apps/client/src/auth/auth-service.interface.ts
@@ -31,4 +31,9 @@ export interface AuthService {
* @param callback the callback function to call when application is signed-in
*/
onSignedIn(callback: () => unknown): void;
+
+ // TODO: Refactor interface to only include shared methods
+ getEdgeEndpoint?(): string;
+
+ setEdgeEndpoint?(endpoint: string): void;
}
diff --git a/apps/client/src/auth/auth-service.ts b/apps/client/src/auth/auth-service.ts
index 8e1d221f..a9cd3066 100644
--- a/apps/client/src/auth/auth-service.ts
+++ b/apps/client/src/auth/auth-service.ts
@@ -34,6 +34,19 @@ class ClientAuthService {
onSignedIn(callback: () => unknown) {
return this.authService.onSignedIn(callback);
}
+
+ setEdgeEndpoint(endpoint: string) {
+ if (this.authService.setEdgeEndpoint) {
+ this.authService.setEdgeEndpoint(endpoint);
+ }
+ }
+
+ getEdgeEndpoint() {
+ if (this.authService.getEdgeEndpoint) {
+ return this.authService.getEdgeEndpoint();
+ }
+ return '';
+ }
}
export const authService = new ClientAuthService();
diff --git a/apps/client/src/auth/edge-auth-service.ts b/apps/client/src/auth/edge-auth-service.ts
index 5c61a9b9..e70a5b14 100644
--- a/apps/client/src/auth/edge-auth-service.ts
+++ b/apps/client/src/auth/edge-auth-service.ts
@@ -7,6 +7,15 @@ export class EdgeAuthService implements AuthService {
accessKeyId: '',
secretAccessKey: '',
};
+ private edgeEndpoint = '0.0.0.0';
+
+ setEdgeEndpoint(endpoint: string) {
+ this.edgeEndpoint = endpoint;
+ }
+
+ getEdgeEndpoint() {
+ return this.edgeEndpoint;
+ }
setAwsCredentials(credentials: AwsCredentialIdentity) {
this.credentials = credentials;
diff --git a/apps/client/src/constants/format.ts b/apps/client/src/constants/format.ts
index 44c19079..a21b5e6d 100644
--- a/apps/client/src/constants/format.ts
+++ b/apps/client/src/constants/format.ts
@@ -4,3 +4,4 @@ export const ROOT_INDEX_PAGE_FORMAT: Format = 'default';
export const DASHBOARDS_INDEX_PAGE_FORMAT: Format = 'table';
export const CREATE_DASHBOARD_PAGE_FORMAT: Format = 'form';
export const DASHBOARD_PAGE_FORMAT: Format = 'default';
+export const EDGE_LOGIN_PAGE_FORMAT: Format = 'form';
diff --git a/apps/client/src/constants/index.ts b/apps/client/src/constants/index.ts
index eed633bf..d09c2b6c 100644
--- a/apps/client/src/constants/index.ts
+++ b/apps/client/src/constants/index.ts
@@ -11,6 +11,7 @@ export const DASHBOARD_PATH = ':dashboardId';
export const ROOT_HREF = '/';
export const DASHBOARDS_HREF = '/dashboards';
export const CREATE_DASHBOARD_HREF = '/dashboards/create';
+export const EDGE_LOGIN_HREF = '/edge-login';
export const DEFAULT_CONTENT_DENSITY: ContentDensity = 'comfortable';
export const CONTENT_DENSITY_KEY = 'content-density';
diff --git a/apps/client/src/helpers/meta-tags.ts b/apps/client/src/helpers/meta-tags.ts
index 05768978..dc67f8f0 100644
--- a/apps/client/src/helpers/meta-tags.ts
+++ b/apps/client/src/helpers/meta-tags.ts
@@ -10,6 +10,7 @@ export const extractedMetaTags = (
applicationName: '',
authenticationFlowType: '',
cognitoEndpoint: '',
+ edgeEndpoint: '',
identityPoolId: '',
region: '',
userPoolId: '',
diff --git a/apps/client/src/helpers/strings/is-string-with-value.ts b/apps/client/src/helpers/strings/is-string-with-value.ts
new file mode 100644
index 00000000..e534f19d
--- /dev/null
+++ b/apps/client/src/helpers/strings/is-string-with-value.ts
@@ -0,0 +1,25 @@
+const isString = (value: unknown): value is string => {
+ return typeof value === 'string';
+};
+
+export const isStringWithValue = (value: unknown): value is string => {
+ return isString(value) && value !== '';
+};
+
+if (import.meta.vitest) {
+ it('returns true for string with value', () => {
+ expect(isStringWithValue('abc')).toBe(true);
+ });
+
+ it('returns false for string with no value', () => {
+ expect(isStringWithValue('')).toBe(false);
+ });
+
+ it('returns false for non-string value', () => {
+ expect(isStringWithValue({})).toBe(false);
+ });
+
+ it('returns false for undefined value', () => {
+ expect(isStringWithValue(undefined)).toBe(false);
+ });
+}
diff --git a/apps/client/src/hooks/dashboard/use-viewport.ts b/apps/client/src/hooks/dashboard/use-viewport.ts
index 03a10ef9..63f20e3c 100644
--- a/apps/client/src/hooks/dashboard/use-viewport.ts
+++ b/apps/client/src/hooks/dashboard/use-viewport.ts
@@ -1,7 +1,7 @@
import { useLocalStorage } from 'react-use';
import type { Viewport } from '@iot-app-kit/core';
-const DEFAULT_VIEWPORT: Viewport = { duration: '5 minutes' };
+const DEFAULT_VIEWPORT: Viewport = { duration: '5 minute' };
export const useViewport = (dashboardId: string) => {
return useLocalStorage(
`dashboard-${dashboardId}-viewport`,
diff --git a/apps/client/src/index.tsx b/apps/client/src/index.tsx
index 35bd11fa..f39e3096 100644
--- a/apps/client/src/index.tsx
+++ b/apps/client/src/index.tsx
@@ -13,14 +13,13 @@ import { queryClient } from './data/query-client';
import { setServiceUrl } from './services';
import metricHandler from './metrics/metric-handler';
import { extractedMetaTags } from './helpers/meta-tags';
+import { isStringWithValue } from './helpers/strings/is-string-with-value';
import { registerServiceWorker } from './register-service-worker';
import { authService } from './auth/auth-service';
import { initializeAuthDependents } from './initialize-auth-dependents';
import { registerLogger } from './register-loggers';
import { registerMetricsRecorder } from './register-metrics-recorder';
-import { EdgeLoginPage } from './routes/edge-login/edge-login-page';
-
import '@aws-amplify/ui-react/styles.css';
import '@cloudscape-design/global-styles/index.css';
@@ -36,6 +35,7 @@ const {
authenticationFlowType,
cognitoEndpoint,
domainName,
+ edgeEndpoint,
identityPoolId,
logMode,
metricsMode,
@@ -44,7 +44,11 @@ const {
userPoolWebClientId,
} = metadata;
-if (domainName && domainName !== '') {
+if (isStringWithValue(edgeEndpoint)) {
+ authService.setEdgeEndpoint(edgeEndpoint);
+}
+
+if (isStringWithValue(domainName)) {
Amplify.configure({
Auth: {
authenticationFlowType,
@@ -95,10 +99,8 @@ if (authMode === 'edge') {
-
-
-
-
+
+
,
diff --git a/apps/client/src/layout/components/top-navigation/top-navigation.tsx b/apps/client/src/layout/components/top-navigation/top-navigation.tsx
index 5771bbe3..8d31a782 100644
--- a/apps/client/src/layout/components/top-navigation/top-navigation.tsx
+++ b/apps/client/src/layout/components/top-navigation/top-navigation.tsx
@@ -4,11 +4,12 @@ import { useState } from 'react';
import { useIntl } from 'react-intl';
import { SettingsModal } from './components/settings-modal';
-import { ROOT_HREF } from '~/constants';
+import { EDGE_LOGIN_HREF, ROOT_HREF } from '~/constants';
import { preventFullPageLoad } from '~/helpers/events';
import { useApplication } from '~/hooks/application/use-application';
import { getAuthMode } from '~/helpers/authMode';
+import { authService } from '~/auth/auth-service';
function EdgeNavigation() {
const [isSettingsModalVisible, setIsSettingsModalVisible] = useState(false);
@@ -59,7 +60,11 @@ function EdgeNavigation() {
iconName: 'user-profile',
onItemClick: (event) => {
if (event.detail.id === 'signout') {
- // TODO: call signout for edge mode
+ authService.setAwsCredentials({
+ accessKeyId: '',
+ secretAccessKey: '',
+ });
+ navigate(EDGE_LOGIN_HREF);
}
},
items: [
diff --git a/apps/client/src/routes/dashboards/dashboard/dashboard-configuration.ts b/apps/client/src/routes/dashboards/dashboard/dashboard-configuration.ts
new file mode 100644
index 00000000..57824d54
--- /dev/null
+++ b/apps/client/src/routes/dashboards/dashboard/dashboard-configuration.ts
@@ -0,0 +1,43 @@
+import { type DashboardClientConfiguration } from '@iot-app-kit/dashboard';
+import { IoTSiteWiseClient } from '@aws-sdk/client-iotsitewise';
+import { IoTEventsClient } from '@aws-sdk/client-iot-events';
+import { IoTTwinMakerClient } from '@aws-sdk/client-iottwinmaker';
+import { getAuthMode } from '~/helpers/authMode';
+
+import { authService } from '~/auth/auth-service';
+
+export function getDashboardClientConfiguration(): DashboardClientConfiguration {
+ if (getAuthMode() === 'edge') {
+ return getEdgeClientConfig();
+ }
+
+ return getCloudClientConfig();
+}
+
+function getCloudClientConfig(): DashboardClientConfiguration {
+ return {
+ awsCredentials: () => authService.getAwsCredentials(),
+ awsRegion: authService.awsRegion,
+ };
+}
+
+function getEdgeClientConfig(): DashboardClientConfiguration {
+ const clientConfig = {
+ endpoint: authService.getEdgeEndpoint(),
+ credentials: () => authService.getAwsCredentials(),
+ region: authService.awsRegion,
+ disableHostPrefix: true,
+ };
+
+ const iotSiteWiseClient = new IoTSiteWiseClient(clientConfig);
+ const iotEventsClient = new IoTEventsClient(clientConfig);
+ const iotTwinMakerClient = new IoTTwinMakerClient(clientConfig);
+
+ const clients = {
+ iotSiteWiseClient,
+ iotEventsClient,
+ iotTwinMakerClient,
+ };
+
+ return clients;
+}
diff --git a/apps/client/src/routes/dashboards/dashboard/dashboard-page.tsx b/apps/client/src/routes/dashboards/dashboard/dashboard-page.tsx
index 62489d90..6600c746 100644
--- a/apps/client/src/routes/dashboards/dashboard/dashboard-page.tsx
+++ b/apps/client/src/routes/dashboards/dashboard/dashboard-page.tsx
@@ -18,9 +18,10 @@ import { useEmitNotification } from '~/hooks/notifications/use-emit-notification
import { useDisplaySettings } from '~/hooks/dashboard/use-displaySettings';
import { getDashboardEditMode, setDashboardEditMode } from '~/store/viewMode';
import { GenericErrorNotification } from '~/structures/notifications/generic-error-notification';
+import { getDashboardClientConfiguration } from './dashboard-configuration';
+import { getAuthMode } from '~/helpers/authMode';
import './styles.css';
-import { authService } from '~/auth/auth-service';
export function DashboardPage() {
const params = useParams<{ dashboardId: string }>();
@@ -65,14 +66,10 @@ export function DashboardPage() {
return ;
}
- const awsRegion = authService.awsRegion;
-
return (
authService.getAwsCredentials(),
- awsRegion,
- }}
+ edgeMode={getAuthMode() === 'edge' ? 'enabled' : 'disabled'}
+ clientConfiguration={getDashboardClientConfiguration()}
dashboardConfiguration={{
...dashboardDefinition,
displaySettings,
diff --git a/apps/client/src/routes/edge-login/components/edge-endpoint-field.tsx b/apps/client/src/routes/edge-login/components/edge-endpoint-field.tsx
deleted file mode 100644
index 6b038f84..00000000
--- a/apps/client/src/routes/edge-login/components/edge-endpoint-field.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import FormField from '@cloudscape-design/components/form-field';
-import Input from '@cloudscape-design/components/input';
-import { Controller } from 'react-hook-form';
-
-import type { Control } from 'react-hook-form';
-import type { EdgeLoginFormValues } from '../hooks/use-edge-login-form';
-import { isJust } from '~/helpers/predicates/is-just';
-
-interface EdgeEndpointFieldProps {
- control: Control;
-}
-
-export function EdgeEndpointField(props: EdgeEndpointFieldProps) {
- return (
- (
-
- field.onChange(event.detail.value)}
- value={field.value}
- placeholder="Enter hostname or IP address"
- />
-
- )}
- />
- );
-}
diff --git a/apps/client/src/routes/edge-login/edge-login-page.spec.tsx b/apps/client/src/routes/edge-login/edge-login-page.spec.tsx
index a0b15014..f17015f8 100644
--- a/apps/client/src/routes/edge-login/edge-login-page.spec.tsx
+++ b/apps/client/src/routes/edge-login/edge-login-page.spec.tsx
@@ -3,24 +3,27 @@ import { render, screen } from '~/helpers/tests/testing-library';
import userEvent from '@testing-library/user-event';
import { EdgeLoginPage } from './edge-login-page';
+import { edgeLogin } from '~/services';
-const getHostField = () =>
- screen.getByPlaceholderText('Enter hostname or IP address');
const getUsernameField = () => screen.getByPlaceholderText('Enter username');
const getPasswordField = () => screen.getByPlaceholderText('Enter password');
const getSigninButton = () => screen.getByRole('button', { name: 'Sign in' });
-const hostName = '1.2.3.4.5';
const username = 'username';
const password = 'password';
vi.mock('~/services', () => ({
edgeLogin: vi.fn().mockReturnValue({
- data: {
- accessKey: '',
- secretKeyId: '',
- },
+ accessKey: '',
+ secretAccessKey: '',
+ }),
+}));
+
+const navigateMock = vi.fn();
+vi.mock('~/hooks/application/use-application', () => ({
+ useApplication: () => ({
+ navigate: navigateMock,
}),
}));
@@ -43,9 +46,6 @@ describe('', () => {
const signInText = screen.getByText('Sign in to edge gateway');
expect(signInText).toBeInTheDocument();
- await user.type(getHostField(), hostName);
- expect(getHostField()).toHaveValue(hostName);
-
await user.type(getUsernameField(), username);
expect(getUsernameField()).toHaveValue(username);
@@ -54,9 +54,45 @@ describe('', () => {
await user.click(getSigninButton());
- // Sign in successful, so children are rendered instead of sign in page
- expect(signInText).not.toBeInTheDocument();
+ // Sign in successful, so should navigate to app
+ expect(navigateMock).toBeCalledWith('/dashboards');
});
- // TODO: error tests
+ it('does not sign in if there was an api error', async () => {
+ vi.resetAllMocks();
+ const errorMessage = 'Incorrect username or password';
+ const errorResponse = {
+ response: {
+ body: {
+ message: errorMessage,
+ },
+ status: 401,
+ },
+ isAxiosError: true,
+ toJSON: () => {
+ return {};
+ },
+ name: '',
+ message: '',
+ };
+
+ vi.mocked(edgeLogin).mockRejectedValue(errorResponse);
+
+ const user = userEvent.setup();
+ render();
+
+ const signInText = screen.getByText('Sign in to edge gateway');
+ expect(signInText).toBeInTheDocument();
+
+ await user.type(getUsernameField(), username);
+ expect(getUsernameField()).toHaveValue(username);
+
+ await user.type(getPasswordField(), password);
+ expect(getPasswordField()).toHaveValue(password);
+
+ await user.click(getSigninButton());
+
+ // Expect login failure
+ expect(signInText).toBeInTheDocument();
+ });
});
diff --git a/apps/client/src/routes/edge-login/edge-login-page.tsx b/apps/client/src/routes/edge-login/edge-login-page.tsx
index 144c612d..39b9074e 100644
--- a/apps/client/src/routes/edge-login/edge-login-page.tsx
+++ b/apps/client/src/routes/edge-login/edge-login-page.tsx
@@ -9,79 +9,83 @@ import ColumnLayout from '@cloudscape-design/components/column-layout';
import { colorBackgroundHomeHeader } from '@cloudscape-design/design-tokens';
import { DevTool } from '@hookform/devtools';
import { authService } from '../../auth/auth-service';
-import { PropsWithChildren } from 'react';
import { useEdgeLoginForm } from './hooks/use-edge-login-form';
-import { EdgeEndpointField } from './components/edge-endpoint-field';
import { EdgeUsernameField } from './components/edge-username-field';
import { EdgeMechanismField } from './components/edge-mechanism-field';
import { EdgePasswordField } from './components/edge-password-field';
import { edgeLogin } from '~/services';
+import { ApiError } from '~/services/generated/core/ApiError';
+import { useApplication } from '~/hooks/application/use-application';
-export function EdgeLoginPage({ children }: PropsWithChildren) {
- const [isLoggedIn, setIsLoggedIn] = useState(false);
+// Adding type since ApiError types body as any
+interface ApiErrorBody {
+ message: string;
+}
+
+export function EdgeLoginPage() {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState('');
const { control, handleSubmit } = useEdgeLoginForm();
+ const { navigate } = useApplication();
const isProdEnv: boolean = process.env.NODE_ENV === 'production';
- if (isLoggedIn) {
- return children;
- } else {
- return (
-
-
-
-
- {!isProdEnv && }
-
-
-
- );
- }
+
+ Sign in
+
+
+ }
+ errorText={error}
+ >
+ Sign in to edge gateway}
+ >
+
+
+
+
+
+
+
+
+ {!isProdEnv && }
+
+
+
+ );
}
diff --git a/apps/client/src/routes/edge-login/edge-login-route.tsx b/apps/client/src/routes/edge-login/edge-login-route.tsx
new file mode 100644
index 00000000..552ac70c
--- /dev/null
+++ b/apps/client/src/routes/edge-login/edge-login-route.tsx
@@ -0,0 +1,15 @@
+import { type RouteObject } from 'react-router-dom';
+import { EDGE_LOGIN_PAGE_FORMAT } from '~/constants/format';
+import { EdgeLoginPage } from './edge-login-page';
+
+export const edgeLoginRoute = {
+ path: 'edge-login',
+ element: ,
+ handle: {
+ crumb: () => ({
+ text: 'Edge login',
+ href: '/edge-login',
+ }),
+ format: EDGE_LOGIN_PAGE_FORMAT,
+ },
+} satisfies RouteObject;
diff --git a/apps/client/src/routes/edge-login/hooks/use-edge-login-form.ts b/apps/client/src/routes/edge-login/hooks/use-edge-login-form.ts
index 87c8cb42..4c8c1feb 100644
--- a/apps/client/src/routes/edge-login/hooks/use-edge-login-form.ts
+++ b/apps/client/src/routes/edge-login/hooks/use-edge-login-form.ts
@@ -3,14 +3,12 @@ import { useForm } from 'react-hook-form';
export type EdgeAuthMechanisms = 'linux' | 'ldap';
export interface EdgeLoginFormValues {
- edgeEndpoint: string;
username: string;
password: string;
authMechanism: EdgeAuthMechanisms;
}
export const DEFAULT_VALUES: EdgeLoginFormValues = {
- edgeEndpoint: '',
username: '',
password: '',
authMechanism: 'linux',
diff --git a/apps/client/src/routes/root-index/index.ts b/apps/client/src/routes/root-index/index.ts
index 97908525..b4e392d7 100644
--- a/apps/client/src/routes/root-index/index.ts
+++ b/apps/client/src/routes/root-index/index.ts
@@ -1 +1 @@
-export { rootIndexRoute } from './root-index-route';
+export { rootIndexRoute, rootIndexEdgeRoute } from './root-index-route';
diff --git a/apps/client/src/routes/root-index/root-index-route.tsx b/apps/client/src/routes/root-index/root-index-route.tsx
index 10f062ec..4c53f253 100644
--- a/apps/client/src/routes/root-index/root-index-route.tsx
+++ b/apps/client/src/routes/root-index/root-index-route.tsx
@@ -1,5 +1,8 @@
import { Navigate, type RouteObject } from 'react-router-dom';
-import { ROOT_INDEX_PAGE_FORMAT } from '~/constants/format';
+import {
+ ROOT_INDEX_PAGE_FORMAT,
+ EDGE_LOGIN_PAGE_FORMAT,
+} from '~/constants/format';
export const rootIndexRoute = {
index: true,
@@ -8,3 +11,11 @@ export const rootIndexRoute = {
format: ROOT_INDEX_PAGE_FORMAT,
},
} satisfies RouteObject;
+
+export const rootIndexEdgeRoute = {
+ index: true,
+ element: ,
+ handle: {
+ format: EDGE_LOGIN_PAGE_FORMAT,
+ },
+} satisfies RouteObject;
diff --git a/apps/client/src/routes/root/root-route.tsx b/apps/client/src/routes/root/root-route.tsx
index 9e5c6896..078e0e23 100644
--- a/apps/client/src/routes/root/root-route.tsx
+++ b/apps/client/src/routes/root/root-route.tsx
@@ -1,12 +1,25 @@
import { RootPage } from './root-page';
-import { rootIndexRoute } from '../root-index/index';
+import { rootIndexRoute, rootIndexEdgeRoute } from '../root-index/index';
import { rootDashboardsRoute } from '../dashboards/root-dashboards';
+import { edgeLoginRoute } from '../edge-login/edge-login-route';
import { ROOT_PATH, ROOT_HREF } from '~/constants';
-import { intl } from '~/services';
+import { getAuthMode } from '~/helpers/authMode';
import type { RouteObject } from 'react-router-dom';
import { RootErrorPage } from './root-error-page';
import { Layout } from '~/layout/layout';
+import { intl } from '~/services';
+
+let children: RouteObject[] = [rootIndexRoute, rootDashboardsRoute];
+
+if (getAuthMode() === 'edge') {
+ children = [
+ rootIndexEdgeRoute,
+ edgeLoginRoute,
+ rootIndexRoute,
+ rootDashboardsRoute,
+ ];
+}
export const rootRoute = {
path: ROOT_PATH,
@@ -30,5 +43,5 @@ export const rootRoute = {
href: ROOT_HREF,
}),
},
- children: [rootIndexRoute, rootDashboardsRoute],
+ children,
} satisfies RouteObject;
diff --git a/apps/client/src/services/generated/models/EdgeLoginBody.ts b/apps/client/src/services/generated/models/EdgeLoginBody.ts
index bb634827..f646ec9d 100644
--- a/apps/client/src/services/generated/models/EdgeLoginBody.ts
+++ b/apps/client/src/services/generated/models/EdgeLoginBody.ts
@@ -1,5 +1,4 @@
export type EdgeLoginBody = {
- edgeEndpoint: string;
username: string;
password: string;
authMechanism: string;
diff --git a/apps/client/src/types/metadata.ts b/apps/client/src/types/metadata.ts
index 74a6836b..0b183ad6 100644
--- a/apps/client/src/types/metadata.ts
+++ b/apps/client/src/types/metadata.ts
@@ -1,16 +1,17 @@
export interface Metadata {
+ applicationName: string;
+ authenticationFlowType: string;
+ authMode: string;
awsAccessKeyId: string;
awsSecretAccessKey: string;
awsSessionToken: string;
- applicationName: string;
- authenticationFlowType: string;
cognitoEndpoint: string;
+ domainName?: string;
+ edgeEndpoint?: string;
identityPoolId: string;
+ logMode: string;
+ metricsMode: string;
region: string;
userPoolId: string;
userPoolWebClientId: string;
- logMode: string;
- metricsMode: string;
- authMode: string;
- domainName?: string;
}
diff --git a/apps/core/.example.edge.env b/apps/core/.example.edge.env
new file mode 100644
index 00000000..86b2d301
--- /dev/null
+++ b/apps/core/.example.edge.env
@@ -0,0 +1,20 @@
+EDGE_ENDPOINT=xxxx
+
+APPLICATION_NAME=IotApp
+AUTH_MODE=edge
+AWS_ACCESS_KEY_ID=fakeMyKeyId
+AWS_REGION=edge
+AWS_SECRET_ACCESS_KEY=fakeSecretAccessKey
+AWS_SESSION_TOKEN=
+COGNITO_IDENTITY_POOL_ID=fakeIdentiyPoolId
+COGNITO_USE_LOCAL_VERIFIER=true
+COGNITO_USER_POOL_ID=us-west-2_h23TJjQR9
+COGNITO_USER_POOL_CLIENT_ID=9cehli62qxmki9mg5adjmucuq
+COGNITO_DOMAIN_NAME=https://test.auth.us-west-2.amazoncognito.com
+DATABASE_ENDPOINT=http://127.0.0.1:8000
+DATABASE_LAUNCH_LOCAL=true
+DATABASE_PORT=8000
+DATABASE_TABLE_NAME=ApiResourceTable
+NODE_ENV=development
+# WebPack Server, Local Cognito and DDB endpoints, and AWS endpoints
+SERVICE_ENDPOINTS='ws://localhost:3001 http://localhost:9229 http://localhost:8000 https://*.amazonaws.com'
diff --git a/apps/core/package.json b/apps/core/package.json
index 075cfc33..2e4e5691 100644
--- a/apps/core/package.json
+++ b/apps/core/package.json
@@ -23,11 +23,11 @@
"@aws-sdk/client-iotsitewise": "^3.450.0",
"@aws-sdk/lib-dynamodb": "3.518.0",
"@aws-sdk/client-iotsitewise": "3.515.0",
- "@fastify/cookie": "^9.1.0",
+ "@fastify/cookie": "^9.3.1",
"@fastify/csrf-protection": "^6.4.1",
"@fastify/helmet": "^11.1.1",
"@fastify/static": "^7.0.1",
- "@fastify/view": "^8.2.0",
+ "@fastify/view": "^9.0.0",
"@nestjs/axios": "^1.0.1",
"@nestjs/common": "^9.4.3",
"@nestjs/config": "^3.1.1",
diff --git a/apps/core/src/app.module.ts b/apps/core/src/app.module.ts
index 1d209972..fe0e6dcf 100644
--- a/apps/core/src/app.module.ts
+++ b/apps/core/src/app.module.ts
@@ -3,23 +3,24 @@ import { ConfigModule } from '@nestjs/config';
import { APP_GUARD } from '@nestjs/core';
import { ThrottlerModule } from '@nestjs/throttler';
+import { authConfig } from './config/auth.config';
import { databaseConfig } from './config/database.config';
+import { edgeConfig } from './config/edge.config';
+import { globalConfig } from './config/global.config';
+import { jwtConfig } from './config/jwt.config';
import { DashboardsModule } from './dashboards/dashboards.module';
import { HealthModule } from './health/health.module';
import { DynamoDbLocalSetupService } from './lifecycle-hooks/dynamodb-local-setup';
import { CognitoJwtAuthGuard } from './auth/cognito-jwt-auth.guard';
-import { authConfig } from './config/auth.config';
import { MvcModule } from './mvc/mvc.module';
-import { jwtConfig } from './config/jwt.config';
import { MigrationModule } from './migration/migration.module';
import { EdgeLoginModule } from './edge-login/edge-login.module';
import { LoggerModule } from './logging/logger.module';
-import { globalConfig } from './config/global.config';
@Module({
imports: [
ConfigModule.forRoot({
- load: [authConfig, databaseConfig, globalConfig, jwtConfig],
+ load: [authConfig, databaseConfig, edgeConfig, globalConfig, jwtConfig],
isGlobal: true,
}),
DashboardsModule,
diff --git a/apps/core/src/bootstrap/security.bootstrap.ts b/apps/core/src/bootstrap/security.bootstrap.ts
index e35d8090..270da46d 100644
--- a/apps/core/src/bootstrap/security.bootstrap.ts
+++ b/apps/core/src/bootstrap/security.bootstrap.ts
@@ -16,14 +16,16 @@ import invariant from 'tiny-invariant';
* @see {@link https://docs.nestjs.com/security/csrf | CSRF Protection}
*/
export const bootstrapSecurity = async (app: NestFastifyApplication) => {
- const { SERVICE_ENDPOINTS } = process.env;
+ const { EDGE_ENDPOINT, SERVICE_ENDPOINTS } = process.env;
+
+ const edge_endpoint = isDefined(EDGE_ENDPOINT) ? [EDGE_ENDPOINT] : [];
// Split the space separated service endpoints
invariant(
isDefined(SERVICE_ENDPOINTS),
envVarRequiredMsg('SERVICE_ENDPOINTS'),
);
- const serviceEndpoints = SERVICE_ENDPOINTS.split(' ');
+ const serviceEndpoints = [...SERVICE_ENDPOINTS.split(' '), ...edge_endpoint];
// Upgrade insecure requests for all non DEV environment
const upgradeInsecureRequests = isDevEnv() ? null : [];
diff --git a/apps/core/src/config/edge.config.ts b/apps/core/src/config/edge.config.ts
new file mode 100644
index 00000000..0ce6530c
--- /dev/null
+++ b/apps/core/src/config/edge.config.ts
@@ -0,0 +1,11 @@
+import { registerAs } from '@nestjs/config';
+
+export const configFactory = () => {
+ const { EDGE_ENDPOINT: edgeEndpoint } = process.env;
+
+ return {
+ edgeEndpoint,
+ };
+};
+
+export const edgeConfig = registerAs('edge', configFactory);
diff --git a/apps/core/src/edge-login/edge-login.e2e.spec.ts b/apps/core/src/edge-login/edge-login.e2e.spec.ts
index dcb314a7..e031b0fc 100644
--- a/apps/core/src/edge-login/edge-login.e2e.spec.ts
+++ b/apps/core/src/edge-login/edge-login.e2e.spec.ts
@@ -5,10 +5,11 @@ import {
} from '@nestjs/platform-fastify';
import { Test } from '@nestjs/testing';
import { AppModule } from '../app.module';
-import { configureTestProcessEnv } from '../testing/aws-configuration';
+import { configureEdgeTestProcessEnv } from '../testing/aws-configuration';
import { EdgeLoginService } from './edge-login.service';
import { HttpModule, HttpService } from '@nestjs/axios';
import { EdgeCredentials } from './entities/edge-credentials.entity';
+import { AxiosError } from '@nestjs/terminus/dist/errors/axios.error';
describe('EdgeLoginModule', () => {
let app: NestFastifyApplication;
@@ -34,7 +35,7 @@ describe('EdgeLoginModule', () => {
};
beforeEach(async () => {
- configureTestProcessEnv(process.env);
+ configureEdgeTestProcessEnv(process.env);
const moduleRef = await Test.createTestingModule({
imports: [AppModule, HttpModule],
@@ -71,7 +72,6 @@ describe('EdgeLoginModule', () => {
describe('POST /api/migration HTTP/1.1', () => {
test('correctly proxies the edge credential request', async () => {
const requestBody = {
- edgeEndpoint: '1.2.3.4.5',
username: 'testUser',
password: 'testPassword',
authMechanism: 'linux',
@@ -102,7 +102,6 @@ describe('EdgeLoginModule', () => {
.mockRejectedValueOnce(errorResponse);
const requestBody = {
- edgeEndpoint: '1.2.3.4.5',
username: 'testUser',
password: 'testPassword',
authMechanism: 'linux',
@@ -118,5 +117,50 @@ describe('EdgeLoginModule', () => {
expect(httpServiceSpy).toHaveBeenCalled();
expect(response.statusCode).toBe(500);
});
+
+ test('returns incorrect username/password if the axios call results in 401', async () => {
+ const errorResponse: AxiosError = {
+ response: {
+ body: {
+ message: 'Incorrect username or password',
+ },
+ status: 401,
+ },
+ isAxiosError: true,
+ toJSON: () => {
+ return {};
+ },
+ name: '',
+ message: '',
+ };
+
+ httpServiceSpy.mockReset();
+ httpServiceSpy = jest
+ .spyOn(httpService.axiosRef, 'post')
+ .mockRejectedValueOnce(errorResponse);
+
+ const requestBody = {
+ username: 'testUser',
+ password: 'testPassword',
+ authMechanism: 'linux',
+ };
+
+ const { body } = await app.inject({
+ method: 'POST',
+ url: '/api/edge-login',
+ payload: requestBody,
+ });
+
+ const expectedResponse = {
+ statusCode: 401,
+ message: 'Incorrect username or password',
+ error: 'Unauthorized',
+ };
+
+ expect(edgeLoginSpy).toHaveBeenCalled();
+ expect(httpServiceSpy).toHaveBeenCalled();
+
+ expect(body).toBe(JSON.stringify(expectedResponse));
+ });
});
});
diff --git a/apps/core/src/edge-login/edge-login.module.ts b/apps/core/src/edge-login/edge-login.module.ts
index 1718aae0..45904c9d 100644
--- a/apps/core/src/edge-login/edge-login.module.ts
+++ b/apps/core/src/edge-login/edge-login.module.ts
@@ -1,11 +1,13 @@
+import { HttpModule } from '@nestjs/axios';
import { Module, ModuleMetadata } from '@nestjs/common';
+import { ConfigModule } from '@nestjs/config';
import { EdgeLoginController } from './edge-login.controller';
import { EdgeLoginService } from './edge-login.service';
-import { HttpModule } from '@nestjs/axios';
+import { edgeConfig } from '../config/edge.config';
export const edgeLoginModuleMetadata: ModuleMetadata = {
- imports: [HttpModule],
+ imports: [ConfigModule.forFeature(edgeConfig), HttpModule],
controllers: [EdgeLoginController],
providers: [EdgeLoginService],
};
diff --git a/apps/core/src/edge-login/edge-login.service.ts b/apps/core/src/edge-login/edge-login.service.ts
index 1b9c12fa..643edb98 100644
--- a/apps/core/src/edge-login/edge-login.service.ts
+++ b/apps/core/src/edge-login/edge-login.service.ts
@@ -1,13 +1,26 @@
import { HttpService } from '@nestjs/axios';
-import { Injectable } from '@nestjs/common';
+import {
+ Inject,
+ Injectable,
+ RequestTimeoutException,
+ UnauthorizedException,
+} from '@nestjs/common';
+import { ConfigType } from '@nestjs/config';
+import { isAxiosError } from '@nestjs/terminus/dist/utils';
import { Agent } from 'https';
+
import { EdgeCredentials } from './entities/edge-credentials.entity';
import { EdgeLoginBody } from './entities/edge-login-body.entity';
+import { edgeConfig } from '../config/edge.config';
import { Result, err, ok } from '../types';
+import { isStringWithValue } from '../types/strings/is-string-with-value';
@Injectable()
export class EdgeLoginService {
- constructor(private readonly httpService: HttpService) {}
+ constructor(
+ @Inject(edgeConfig.KEY) private edge: ConfigType,
+ private readonly httpService: HttpService,
+ ) {}
public async login(
body: EdgeLoginBody,
@@ -15,8 +28,13 @@ export class EdgeLoginService {
const httpsAgent = new Agent({ rejectUnauthorized: false });
try {
+ const { edgeEndpoint } = this.edge;
+ if (!isStringWithValue(edgeEndpoint)) {
+ throw new Error();
+ }
+
const result = await this.httpService.axiosRef.post(
- `https://${body.edgeEndpoint}/authenticate`,
+ `${edgeEndpoint}/authenticate`,
{
username: body.username,
password: body.password,
@@ -37,6 +55,20 @@ export class EdgeLoginService {
sessionExpiryTime,
});
} catch (error) {
+ if (isAxiosError(error)) {
+ // If response field, server responded with status code thats not 2xx
+ if (error.response) {
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
+ if (error.response.status && error.response.status === 401) {
+ return err(
+ new UnauthorizedException('Incorrect username or password'),
+ );
+ }
+ } else if (error.request) {
+ // If request field, no response from server
+ return err(new RequestTimeoutException('Request timed out'));
+ }
+ }
return error instanceof Error
? err(error)
: err(new Error('Error getting edge credentials'));
diff --git a/apps/core/src/edge-login/entities/edge-login-body.entity.ts b/apps/core/src/edge-login/entities/edge-login-body.entity.ts
index efea199e..48a3218a 100644
--- a/apps/core/src/edge-login/entities/edge-login-body.entity.ts
+++ b/apps/core/src/edge-login/entities/edge-login-body.entity.ts
@@ -1,12 +1,6 @@
import { IsString } from 'class-validator';
export class EdgeLoginBody {
- /**
- * @example "192.168.0.1"
- */
- @IsString()
- public readonly edgeEndpoint: string;
-
/**
* @example "user"
*/
diff --git a/apps/core/src/migration/service/convert-monitor-to-app-definition.ts b/apps/core/src/migration/service/convert-monitor-to-app-definition.ts
index 4efd9066..4b3d331a 100644
--- a/apps/core/src/migration/service/convert-monitor-to-app-definition.ts
+++ b/apps/core/src/migration/service/convert-monitor-to-app-definition.ts
@@ -162,7 +162,17 @@ const lineChartProperties = {
style: 'solid',
},
legend: {
+ width: '30%',
+ visibleContent: {
+ unit: true,
+ latestValue: true,
+ minValue: false,
+ asset: true,
+ maxValue: false,
+ },
visible: true,
+ position: 'right',
+ height: '30%',
},
};
@@ -410,6 +420,10 @@ const convertKpiAndGridWidget = (
secondaryFont: {},
title: monitorWidget.title,
...queryConfig,
+ showTimestamp: true,
+ showAggregationAndResolution: true,
+ resolution: '0',
+ showUnit: true,
},
};
appWidgets.push(newAppWidget);
diff --git a/apps/core/src/mvc/mvc.controller.ts b/apps/core/src/mvc/mvc.controller.ts
index 0f8254df..1bafed66 100644
--- a/apps/core/src/mvc/mvc.controller.ts
+++ b/apps/core/src/mvc/mvc.controller.ts
@@ -2,6 +2,7 @@ import { Get, Controller, Render, Inject, Header } from '@nestjs/common';
import { ConfigType } from '@nestjs/config';
import { Public } from '../auth/public.decorator';
import { authConfig } from '../config/auth.config';
+import { edgeConfig } from '../config/edge.config';
import { globalConfig } from '../config/global.config';
// Responds with the index page for all of the client routes.
@@ -11,6 +12,7 @@ const CLIENT_ROUTES = ['', 'dashboards', 'dashboards/*'];
export class MvcController {
constructor(
@Inject(authConfig.KEY) private auth: ConfigType,
+ @Inject(edgeConfig.KEY) private edge: ConfigType,
@Inject(globalConfig.KEY) private global: ConfigType,
) {}
@@ -21,35 +23,38 @@ export class MvcController {
root() {
const {
authenticationFlowType,
+ authMode,
clientAwsAccessKeyId,
clientAwsSecretAccessKey,
clientAwsSessionToken,
cognitoEndpoint,
+ domainName,
identityPoolId,
region,
- userPoolWebClientId,
userPoolId,
- domainName,
- authMode,
+ userPoolWebClientId,
} = this.auth;
+ const { edgeEndpoint } = this.edge;
+
const { applicationName, logMode, metricsMode } = this.global;
return {
applicationName,
authenticationFlowType,
+ authMode,
clientAwsAccessKeyId,
clientAwsSecretAccessKey,
clientAwsSessionToken,
cognitoEndpoint,
+ domainName,
+ edgeEndpoint,
identityPoolId,
+ logMode,
+ metricsMode,
region,
userPoolId,
userPoolWebClientId,
- logMode,
- metricsMode,
- domainName,
- authMode,
};
}
}
diff --git a/apps/core/src/mvc/mvc.module.ts b/apps/core/src/mvc/mvc.module.ts
index da8f88b4..6fea7352 100644
--- a/apps/core/src/mvc/mvc.module.ts
+++ b/apps/core/src/mvc/mvc.module.ts
@@ -1,8 +1,17 @@
import { Module } from '@nestjs/common';
+import { ConfigModule } from '@nestjs/config';
+
import { MvcController } from './mvc.controller';
+import { authConfig } from '../config/auth.config';
+import { edgeConfig } from '../config/edge.config';
+import { globalConfig } from '../config/global.config';
@Module({
- imports: [],
+ imports: [
+ ConfigModule.forFeature(authConfig),
+ ConfigModule.forFeature(edgeConfig),
+ ConfigModule.forFeature(globalConfig),
+ ],
controllers: [MvcController],
providers: [],
})
diff --git a/apps/core/src/testing/aws-configuration.ts b/apps/core/src/testing/aws-configuration.ts
index d32af705..f5cf02fe 100644
--- a/apps/core/src/testing/aws-configuration.ts
+++ b/apps/core/src/testing/aws-configuration.ts
@@ -13,11 +13,17 @@ export const databasePort = '8001';
export const databaseTableName = 'dashboard-api-e2e-test';
export const configureTestProcessEnv = (env: NodeJS.ProcessEnv) => {
+ env.AWS_ACCESS_KEY_ID = accessKeyId;
+ env.AWS_SECRET_ACCESS_KEY = secretAccessKey;
+ env.AWS_REGION = region;
env.DATABASE_PORT = databasePort;
env.DATABASE_ENDPOINT = databaseEndpoint;
env.DATABASE_TABLE_NAME = databaseTableName;
env.DATABASE_LAUNCH_LOCAL = databaseLaunchLocal;
- env.AWS_ACCESS_KEY_ID = accessKeyId;
- env.AWS_SECRET_ACCESS_KEY = secretAccessKey;
- env.AWS_REGION = region;
+};
+
+export const configureEdgeTestProcessEnv = (env: NodeJS.ProcessEnv) => {
+ configureTestProcessEnv(env);
+ env.AUTH_MODE = 'edge';
+ env.EDGE_ENDPOINT = 'https://1.2.3.4';
};
diff --git a/apps/core/src/types/strings/is-string-with-value.ts b/apps/core/src/types/strings/is-string-with-value.ts
new file mode 100644
index 00000000..0398855e
--- /dev/null
+++ b/apps/core/src/types/strings/is-string-with-value.ts
@@ -0,0 +1,7 @@
+const isString = (value: unknown): value is string => {
+ return typeof value === 'string';
+};
+
+export const isStringWithValue = (value: unknown): value is string => {
+ return isString(value) && value !== '';
+};
diff --git a/cdk/lib/core/core-service.ts b/cdk/lib/core/core-service.ts
index 644539d2..f1d41ac7 100644
--- a/cdk/lib/core/core-service.ts
+++ b/cdk/lib/core/core-service.ts
@@ -23,6 +23,7 @@ export interface CoreServiceProps {
readonly userPoolId: string;
readonly authMode: string;
readonly domainName?: string;
+ readonly edgeEndpoint?: string;
}
export class CoreService extends Construct {
@@ -40,6 +41,7 @@ export class CoreService extends Construct {
userPoolId,
authMode,
domainName,
+ edgeEndpoint,
} = props;
const serviceSourceRolePrincipal = new ServicePrincipal(
@@ -141,6 +143,10 @@ export class CoreService extends Construct {
name: 'AUTH_MODE',
value: authMode,
},
+ {
+ name: 'EDGE_ENDPOINT',
+ value: edgeEndpoint ? edgeEndpoint : '',
+ },
],
},
},
diff --git a/cdk/lib/iot-application-stack.ts b/cdk/lib/iot-application-stack.ts
index 8fc85cf6..5fc5718e 100644
--- a/cdk/lib/iot-application-stack.ts
+++ b/cdk/lib/iot-application-stack.ts
@@ -21,6 +21,7 @@ export class IotApplicationStack extends Stack {
super(scope, id, props);
const authMode = this.node.tryGetContext('authMode') as string;
+ const edgeEndpoint = this.node.tryGetContext('edgeEndpoint') as string;
const {
logGroup: { logGroupArn },
@@ -98,6 +99,7 @@ export class IotApplicationStack extends Stack {
userPoolClientId: userPoolClientId,
userPoolId: userPoolId,
authMode: authMode ? authMode : AuthModeOptions.COGNITO,
+ edgeEndpoint,
},
});
diff --git a/cdk/package.json b/cdk/package.json
index 7d954d6b..b4dc2edb 100644
--- a/cdk/package.json
+++ b/cdk/package.json
@@ -20,7 +20,7 @@
"lint:fix": "eslint \"{bin,lib}/**/*.ts\" --fix"
},
"dependencies": {
- "aws-cdk-lib": "2.130.0",
+ "aws-cdk-lib": "2.131.0",
"constructs": "^10.2.70",
"source-map-support": "^0.5.21"
},
diff --git a/deployCdk.js b/deployCdk.js
index 479a6b3b..8c896919 100755
--- a/deployCdk.js
+++ b/deployCdk.js
@@ -5,6 +5,7 @@ const { execSync } = require('child_process');
const cognito = 'AWS Cognito';
const sso = 'AWS IAM Identity Center (formerly AWS SSO)';
+const edge = 'Edge';
const askQuestions = () => {
const questions = [
@@ -13,7 +14,7 @@ const askQuestions = () => {
name: 'AUTH',
message: 'Welcome to IoT Application. Please select an authentication mode.',
default: cognito,
- choices: [cognito, sso],
+ choices: [cognito, sso, edge],
}
];
@@ -30,6 +31,16 @@ const run = async () => {
} else if (AUTH === sso) {
execSync("yarn workspace cdk deploy:no-review:sso", { stdio: 'inherit' });
console.log('Please follow README instructions to complete SSO setup after deployment: https://github.com/awslabs/iot-application/tree/main/deploymentguide');
+ } else if (AUTH === edge) {
+ const edgeQuestion = [
+ {
+ type: 'input',
+ name: 'ENDPOINT',
+ message: 'What is the ip/hostname of your edge gateway? (example: htttps://1.2.3.4.5)',
+ }
+ ];
+ const { ENDPOINT } = await inquirer.prompt(edgeQuestion);
+ execSync(`yarn workspace cdk cdk deploy -c authMode=edge -c edgeEndpoint="${ENDPOINT}" --all --require-approval never`, { stdio: 'inherit' });
} else {
execSync("yarn workspace cdk deploy:no-review:cognito", {stdio: 'inherit' });
}
diff --git a/turbo.json b/turbo.json
index bd5875d6..68b625c0 100644
--- a/turbo.json
+++ b/turbo.json
@@ -31,6 +31,7 @@
"DATABASE_TABLE_NAME",
"DATABASE_PORT",
"DATABASE_LAUNCH_LOCAL",
+ "EDGE_ENDPOINT",
"PUBLIC_URL",
"NODE_ENV",
"SERVICE_ENDPOINTS",
diff --git a/yarn.lock b/yarn.lock
index f17f2111..ff66f593 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1048,48 +1048,6 @@
"@aws-sdk/util-utf8-node" "3.6.1"
tslib "^2.0.0"
-"@aws-sdk/client-iot-events@3.354.0":
- version "3.354.0"
- resolved "https://registry.yarnpkg.com/@aws-sdk/client-iot-events/-/client-iot-events-3.354.0.tgz#dc5932dc9315dd0b320ea3cc1e59b83ccba2d9b7"
- integrity sha512-rD+a6qWB6wWOO97lNZdcYizR55Skmn8Tvs1WMEWw2xZBg7H0RcUJ3+ErxMPHnd41R/9fwyoNOjXPlC5eBACQ4g==
- dependencies:
- "@aws-crypto/sha256-browser" "3.0.0"
- "@aws-crypto/sha256-js" "3.0.0"
- "@aws-sdk/client-sts" "3.354.0"
- "@aws-sdk/config-resolver" "3.354.0"
- "@aws-sdk/credential-provider-node" "3.354.0"
- "@aws-sdk/fetch-http-handler" "3.353.0"
- "@aws-sdk/hash-node" "3.347.0"
- "@aws-sdk/invalid-dependency" "3.347.0"
- "@aws-sdk/middleware-content-length" "3.347.0"
- "@aws-sdk/middleware-endpoint" "3.347.0"
- "@aws-sdk/middleware-host-header" "3.347.0"
- "@aws-sdk/middleware-logger" "3.347.0"
- "@aws-sdk/middleware-recursion-detection" "3.347.0"
- "@aws-sdk/middleware-retry" "3.354.0"
- "@aws-sdk/middleware-serde" "3.347.0"
- "@aws-sdk/middleware-signing" "3.354.0"
- "@aws-sdk/middleware-stack" "3.347.0"
- "@aws-sdk/middleware-user-agent" "3.352.0"
- "@aws-sdk/node-config-provider" "3.354.0"
- "@aws-sdk/node-http-handler" "3.350.0"
- "@aws-sdk/smithy-client" "3.347.0"
- "@aws-sdk/types" "3.347.0"
- "@aws-sdk/url-parser" "3.347.0"
- "@aws-sdk/util-base64" "3.310.0"
- "@aws-sdk/util-body-length-browser" "3.310.0"
- "@aws-sdk/util-body-length-node" "3.310.0"
- "@aws-sdk/util-defaults-mode-browser" "3.353.0"
- "@aws-sdk/util-defaults-mode-node" "3.354.0"
- "@aws-sdk/util-endpoints" "3.352.0"
- "@aws-sdk/util-retry" "3.347.0"
- "@aws-sdk/util-user-agent-browser" "3.347.0"
- "@aws-sdk/util-user-agent-node" "3.354.0"
- "@aws-sdk/util-utf8" "3.310.0"
- "@smithy/protocol-http" "^1.0.1"
- "@smithy/types" "^1.0.0"
- tslib "^2.5.0"
-
"@aws-sdk/client-iot-events@3.515.0":
version "3.515.0"
resolved "https://registry.yarnpkg.com/@aws-sdk/client-iot-events/-/client-iot-events-3.515.0.tgz#1242849f5948a81fb82b1391c29450fd25cd31ff"
@@ -6863,15 +6821,15 @@
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
-"@cloudscape-design/collection-hooks@1.0.36", "@cloudscape-design/collection-hooks@^1.0.36":
+"@cloudscape-design/collection-hooks@1.0.36":
version "1.0.36"
resolved "https://registry.yarnpkg.com/@cloudscape-design/collection-hooks/-/collection-hooks-1.0.36.tgz#689ce98918274d74bb15d03d21139192779fd638"
integrity sha512-IInI1NLKnv4ihIglkI1se33TxiUjQ/0shZ3t8n02VLv0fhhT4p0ObISoxHScNfWk9eJ1+EYL1fTcc8yJQF/7/Q==
-"@cloudscape-design/collection-hooks@^1.0.0":
- version "1.0.25"
- resolved "https://registry.yarnpkg.com/@cloudscape-design/collection-hooks/-/collection-hooks-1.0.25.tgz#6444158d1a6dbc2094ea068d7787525cab6d41d4"
- integrity sha512-2p6sa7eYko1VqMwjEWG3H/Ka5DlsPhwEBAqmY+pNQ9IunSLv/i3JFTSun5W1OUUXCbeqTSndagjsZG0gIlXvFw==
+"@cloudscape-design/collection-hooks@^1.0.0", "@cloudscape-design/collection-hooks@^1.0.37":
+ version "1.0.37"
+ resolved "https://registry.yarnpkg.com/@cloudscape-design/collection-hooks/-/collection-hooks-1.0.37.tgz#c91d3197275520d4fc09a1b4242300662df385ef"
+ integrity sha512-uXGfKwhF3cqLFRYDOhA9DGWcnwwZfL6N81wFdMG5qN0WsFgIUBvDCP7XWfSnMS77Y1TSdUXGWsW5Fnoi9XJpnQ==
"@cloudscape-design/component-toolkit@^1.0.0-beta":
version "1.0.0-beta.27"
@@ -7508,12 +7466,12 @@
resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.0.0.tgz#f22824caff3ae506b18207bad4126dbc6ccdb6b8"
integrity sha512-JUFJad5lv7jxj926GPgymrWQxxjPYuJNiNjNMzqT+HiuP6Vl3dk5xzG+8sTX96np0ZAluvaMzPsjhHZ5rNuNQQ==
-"@fastify/cookie@^9.1.0":
- version "9.1.0"
- resolved "https://registry.yarnpkg.com/@fastify/cookie/-/cookie-9.1.0.tgz#b9ca95fcb934a21915ab6f228a63dd73013738df"
- integrity sha512-w/LlQjj7cmYlQNhEKNm4jQoLkFXCL73kFu1Jy3aL7IFbYEojEKur0f7ieCKUxBBaU65tpaWC83UM8xW7AzY6uw==
+"@fastify/cookie@^9.3.1":
+ version "9.3.1"
+ resolved "https://registry.yarnpkg.com/@fastify/cookie/-/cookie-9.3.1.tgz#48b89a356a23860c666e2fe522a084cc5c943d33"
+ integrity sha512-h1NAEhB266+ZbZ0e9qUE6NnNR07i7DnNXWG9VbbZ8uC6O/hxHpl+Zoe5sw1yfdZ2U6XhToUGDnzQtWJdCaPwfg==
dependencies:
- cookie "^0.5.0"
+ cookie-signature "^1.1.0"
fastify-plugin "^4.0.0"
"@fastify/cors@8.3.0":
@@ -7604,10 +7562,10 @@
fastq "^1.17.0"
glob "^10.3.4"
-"@fastify/view@^8.2.0":
- version "8.2.0"
- resolved "https://registry.yarnpkg.com/@fastify/view/-/view-8.2.0.tgz#80ef9569198ca3a0f3207fa25b2dd6d0c12fc4c7"
- integrity sha512-hBSiBofCnJNlPHEMZWpO1SL84eqOaqujJ1hR3jntFyZZCkweH5jMs12DKYyGesjVll7SJFRRxPUBB8kmUmneRQ==
+"@fastify/view@^9.0.0":
+ version "9.0.0"
+ resolved "https://registry.yarnpkg.com/@fastify/view/-/view-9.0.0.tgz#563386b06eb26fb9a17db872c46f8b77af23c2cb"
+ integrity sha512-4KSM75Ad7Q9adQWJK17XAJlmwNE9HhIe8TdSTnvFzDvt0aOwmS4iY6k+Xd4NWuEk0JbteS6kzo0eZOr0ZZgPVg==
dependencies:
fastify-plugin "^4.0.0"
hashlru "^2.3.0"
@@ -7703,13 +7661,13 @@
"@formatjs/icu-skeleton-parser" "1.7.0"
tslib "^2.4.0"
-"@formatjs/icu-messageformat-parser@2.7.5":
- version "2.7.5"
- resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.7.5.tgz#6c12c08544eafef874df13b30729daf7b4dbd089"
- integrity sha512-zCB53HdGDibh6/2ISEN3TGsFQruQ6gGKMFV94qHNyVrs0tNO6ncKhV0vq0n3Ydz8ipIQ2GaYAvfCoimNOVvKqA==
+"@formatjs/icu-messageformat-parser@2.7.6":
+ version "2.7.6"
+ resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.7.6.tgz#3d69806de056d2919d53dad895a5ff4851e4e9ff"
+ integrity sha512-etVau26po9+eewJKYoiBKP6743I1br0/Ie00Pb/S/PtmYfmjTcOn2YCh2yNkSZI12h6Rg+BOgQYborXk46BvkA==
dependencies:
"@formatjs/ecma402-abstract" "1.18.2"
- "@formatjs/icu-skeleton-parser" "1.7.2"
+ "@formatjs/icu-skeleton-parser" "1.8.0"
tslib "^2.4.0"
"@formatjs/icu-skeleton-parser@1.6.0":
@@ -7736,10 +7694,10 @@
"@formatjs/ecma402-abstract" "1.18.0"
tslib "^2.4.0"
-"@formatjs/icu-skeleton-parser@1.7.2":
- version "1.7.2"
- resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.7.2.tgz#ffbdd535c33249635ad0e54a34813194287a1567"
- integrity sha512-nlIXVv280bjGW3ail5Np1+xgGKBnMhwQQIivgbk9xX0af8ESQO+y2VW9TOY7mCrs3WH786uVpZlLimXAlXH7SA==
+"@formatjs/icu-skeleton-parser@1.8.0":
+ version "1.8.0"
+ resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.0.tgz#5f3d3a620c687d6f8c180d80d1241e8f213acf79"
+ integrity sha512-QWLAYvM0n8hv7Nq5BEs4LKIjevpVpbGLAJgOaYzg9wABEoX1j0JO1q2/jVkO6CVlq0dbsxZCngS5aXbysYueqA==
dependencies:
"@formatjs/ecma402-abstract" "1.18.2"
tslib "^2.4.0"
@@ -7834,12 +7792,12 @@
intl-messageformat "10.5.8"
tslib "^2.4.0"
-"@formatjs/ts-transformer@3.13.11", "@formatjs/ts-transformer@^3.13.9":
- version "3.13.11"
- resolved "https://registry.yarnpkg.com/@formatjs/ts-transformer/-/ts-transformer-3.13.11.tgz#c3603ff59c4b3e54535a26b8e204f6ccdacd5a91"
- integrity sha512-qOAGGUQC7GSMMaAFy2MAlC8REM58lUNi8W+VlRb57cDUpge46x2hP33Mzu5N1xmm6OCqDQTRXws5jEOcRI3C8Q==
+"@formatjs/ts-transformer@3.13.12", "@formatjs/ts-transformer@^3.13.9":
+ version "3.13.12"
+ resolved "https://registry.yarnpkg.com/@formatjs/ts-transformer/-/ts-transformer-3.13.12.tgz#5984b7b92492580bfd09deb09a5b57589b757c5f"
+ integrity sha512-uf1+DgbsCrzHAg7uIf0QlzpIkHYxRSRig5iJa9FaoUNIDZzNEE2oW/uLLLq7I9Z2FLIPhbmgq8hbW40FoQv+Fg==
dependencies:
- "@formatjs/icu-messageformat-parser" "2.7.5"
+ "@formatjs/icu-messageformat-parser" "2.7.6"
"@types/json-stable-stringify" "^1.0.32"
"@types/node" "14 || 16 || 17"
chalk "^4.0.0"
@@ -7934,34 +7892,32 @@
dependencies:
"@iot-app-kit/charts-core" "^2.1.2"
-"@iot-app-kit/components@10.0.0":
- version "10.0.0"
- resolved "https://registry.yarnpkg.com/@iot-app-kit/components/-/components-10.0.0.tgz#bb9800684fa8f983640f26e68994ca79ae554b97"
- integrity sha512-icP1RqjS/+dzXPo/nzWqInLKH8+TombkCjzRczJ5VNOWilrMrvhXspW+yCRpVNl3q3gti9KpCbXjs6BI93Wu+g==
+"@iot-app-kit/components@10.2.0":
+ version "10.2.0"
+ resolved "https://registry.yarnpkg.com/@iot-app-kit/components/-/components-10.2.0.tgz#564ec1d6f88ad4032b9e328424e513d31aa02fff"
+ integrity sha512-NIxMXLAlq0smjsmHbHbXjl6FV6jAQ0EFxkRfkrOBTrY/65u3DYr0jpWxZeeKNexWrZuDhC1MyJpYIiQrf6IMaQ==
dependencies:
"@awsui/collection-hooks" "^1.0.51"
"@awsui/components-react" "^3.0.0"
"@awsui/design-tokens" "^3.0.41"
- "@iot-app-kit/core" "10.0.0"
- "@iot-app-kit/related-table" "10.0.0"
+ "@iot-app-kit/core" "10.2.0"
+ "@iot-app-kit/related-table" "10.2.0"
"@stencil/core" "^2.7.0"
"@synchro-charts/core" "7.2.0"
styled-components "^5.3.11"
-"@iot-app-kit/core-util@10.0.0":
- version "10.0.0"
- resolved "https://registry.yarnpkg.com/@iot-app-kit/core-util/-/core-util-10.0.0.tgz#2ae41f48520d13c470dc3f80151ddca95bcc2eb8"
- integrity sha512-Ny+ge/aLE3daaVkwSJ2EephxmTenKkmYkXy7CRd0vezkO9wuqeQiJvgbzdVO7dfujDwdnVNir7tiCny1H/1Byw==
+"@iot-app-kit/core-util@10.2.0":
+ version "10.2.0"
+ resolved "https://registry.yarnpkg.com/@iot-app-kit/core-util/-/core-util-10.2.0.tgz#d4e4b83df4c1cb0659a96fbf153cc96c8b0f1115"
+ integrity sha512-lmVuLLDSt+ZSWGCa/KJjOt8P+M5VeEDGQ2rgn/A2/mRIvURSqD2CF0qBS1dsycBNeUII4tYNmq/88BxBHwz16A==
dependencies:
- "@aws-sdk/client-iot-events" "3.354.0"
- "@aws-sdk/client-iotsitewise" "3.456.0"
- "@iot-app-kit/core" "10.0.0"
+ "@iot-app-kit/core" "10.2.0"
lodash.difference "4.5.0"
-"@iot-app-kit/core@10.0.0":
- version "10.0.0"
- resolved "https://registry.yarnpkg.com/@iot-app-kit/core/-/core-10.0.0.tgz#7aaad5e0ff7335e62e9fc4b8b3a9faffee0801d8"
- integrity sha512-Cizxn0AtaEssThJ4CWpWwvXiLZ5NBOKUy1RvpTfjo0BFYDyM0yT7Dmqh1fvtBTe87+8F7mFSg+EoDbbglfNeHA==
+"@iot-app-kit/core@10.2.0":
+ version "10.2.0"
+ resolved "https://registry.yarnpkg.com/@iot-app-kit/core/-/core-10.2.0.tgz#c4eb294c1f9837e4288003303dde18d32e916552"
+ integrity sha512-y+MVAe5CrnLPyvWqiPLsuQo1PlTLSWrj3r2vdNML5IGO+ui75Ez109tXJ9LG7isECqW1jjbf0Fh8H21rKgPDpg==
dependencies:
d3-array "^3.2.4"
intervals-fn "^3.0.3"
@@ -7970,17 +7926,17 @@
rxjs "^7.8.1"
uuid "^9.0.0"
-"@iot-app-kit/dashboard@10.0.0":
- version "10.0.0"
- resolved "https://registry.yarnpkg.com/@iot-app-kit/dashboard/-/dashboard-10.0.0.tgz#f528662c0054746306070af3323969763abd773d"
- integrity sha512-SLx/qLz/x1a/qLB15jBddZtd4b5oanWPKMiGxLgWJgvckqw0Ca/ENnxzPu25e8xO/MrThH63zjVJ7z/kUi4V8A==
+"@iot-app-kit/dashboard@10.2.0":
+ version "10.2.0"
+ resolved "https://registry.yarnpkg.com/@iot-app-kit/dashboard/-/dashboard-10.2.0.tgz#ce10a78927fe4be1c520502750ca1249f4ba90ca"
+ integrity sha512-VanHPUX/FbzKWx+jDnBU2ef7tXl4AvKdhejKO/hTXJ4tvXfe1e2tbV2WJMHPUZaEyZGuKGmAzJBe5N3CmaPqvQ==
dependencies:
"@iot-app-kit/charts-core" "2.1.2"
- "@iot-app-kit/components" "10.0.0"
- "@iot-app-kit/core" "10.0.0"
- "@iot-app-kit/core-util" "10.0.0"
- "@iot-app-kit/react-components" "10.0.0"
- "@iot-app-kit/source-iotsitewise" "10.0.0"
+ "@iot-app-kit/components" "10.2.0"
+ "@iot-app-kit/core" "10.2.0"
+ "@iot-app-kit/core-util" "10.2.0"
+ "@iot-app-kit/react-components" "10.2.0"
+ "@iot-app-kit/source-iotsitewise" "10.2.0"
"@popperjs/core" "^2.11.8"
"@tanstack/react-query" "^4.29.15"
aws-sdk-client-mock "^3.0.0"
@@ -8001,20 +7957,20 @@
turbowatch "^2.29.4"
uuid "^9.0.0"
-"@iot-app-kit/react-components@10.0.0":
- version "10.0.0"
- resolved "https://registry.yarnpkg.com/@iot-app-kit/react-components/-/react-components-10.0.0.tgz#3bbdf5f99743adb6d48dcf2d698be882b46fc681"
- integrity sha512-iRB/RCnkp3SbzqdwSd/IQOUebC9JRNcZpO9Wmaf8lUGjNyZ5xRhpmo7vxEISXvWD1sPJpAvK+oDVUyX5ryxzpA==
+"@iot-app-kit/react-components@10.2.0":
+ version "10.2.0"
+ resolved "https://registry.yarnpkg.com/@iot-app-kit/react-components/-/react-components-10.2.0.tgz#3d9f0d73cb84bccb2c6da74f0c94ce25f1699d76"
+ integrity sha512-HB4ZY5AruBGiZZ07VSRy5SYK5AwPgyMq/LILxnrSYtTa1KdCZfiiBiVDLSESdpVHfB3aUgIRS6xdpE7uvcOmDA==
dependencies:
"@cloudscape-design/collection-hooks" "1.0.36"
"@cloudscape-design/components" "3.0.518"
"@cloudscape-design/design-tokens" "3.0.34"
"@iot-app-kit/charts" "2.1.2"
"@iot-app-kit/charts-core" "2.1.2"
- "@iot-app-kit/components" "10.0.0"
- "@iot-app-kit/core" "10.0.0"
- "@iot-app-kit/core-util" "10.0.0"
- "@iot-app-kit/source-iottwinmaker" "10.0.0"
+ "@iot-app-kit/components" "10.2.0"
+ "@iot-app-kit/core" "10.2.0"
+ "@iot-app-kit/core-util" "10.2.0"
+ "@iot-app-kit/source-iottwinmaker" "10.2.0"
color "^4.2.3"
copy-to-clipboard "^3.3.3"
d3-array "^3.2.3"
@@ -8045,22 +8001,20 @@
video.js "8.3.0"
zustand "^4.3.9"
-"@iot-app-kit/related-table@10.0.0":
- version "10.0.0"
- resolved "https://registry.yarnpkg.com/@iot-app-kit/related-table/-/related-table-10.0.0.tgz#114066a3a276cf9529c5bb2db8747bb1f06a39fd"
- integrity sha512-VZXshigJhKG6p9zJWPwe+r+vfglMd2mO4N5ozGrQJVSTC4Yyb1rfVpV+2fyzA+ivUvIwPjw/MRModuNr9XZjdw==
+"@iot-app-kit/related-table@10.2.0":
+ version "10.2.0"
+ resolved "https://registry.yarnpkg.com/@iot-app-kit/related-table/-/related-table-10.2.0.tgz#4143aeb19f2ae006538d38723f9476a37e75f1d5"
+ integrity sha512-w/4Vu0jR+5bzSnSspATInXhtI6KajyoLVLI6nbufm97+0DSguW+gIHakE+h4SxV+CChP6IKBL7TzVeUGM/6rXQ==
dependencies:
uuid "^9.0.0"
-"@iot-app-kit/source-iotsitewise@10.0.0":
- version "10.0.0"
- resolved "https://registry.yarnpkg.com/@iot-app-kit/source-iotsitewise/-/source-iotsitewise-10.0.0.tgz#4a4010a5109cd1fed791b65d0a2afbb488dc066c"
- integrity sha512-RNLPFY9e0aHfq7CirFEetWd+dSIkoeuU2aKjeeCLIkBiT+T7LQmvRUFrQW92aNykgsqILhEtB2gEtlmNls1DLA==
+"@iot-app-kit/source-iotsitewise@10.2.0":
+ version "10.2.0"
+ resolved "https://registry.yarnpkg.com/@iot-app-kit/source-iotsitewise/-/source-iotsitewise-10.2.0.tgz#1fd862bcea76f53c2bb71e10ee6cb2dea9ae5268"
+ integrity sha512-XJQjSP5tbwBZCD9qxfz+BQLszklR6kkcI4AuRW4hP5uGWwtd5WBIO/PMzkSDNsosZnYdQQuFK2CdLl2lfjUmYg==
dependencies:
- "@aws-sdk/client-iot-events" "3.354.0"
- "@aws-sdk/client-iotsitewise" "3.456.0"
- "@iot-app-kit/core" "10.0.0"
- "@iot-app-kit/core-util" "10.0.0"
+ "@iot-app-kit/core" "10.2.0"
+ "@iot-app-kit/core-util" "10.2.0"
"@synchro-charts/core" "7.2.0"
dataloader "^2.2.2"
lodash.isequal "^4.5.0"
@@ -8068,10 +8022,10 @@
lodash.uniqwith "^4.5.0"
rxjs "^7.8.1"
-"@iot-app-kit/source-iottwinmaker@10.0.0":
- version "10.0.0"
- resolved "https://registry.yarnpkg.com/@iot-app-kit/source-iottwinmaker/-/source-iottwinmaker-10.0.0.tgz#bad79af524dd4a43ccc9add399a42aa9e3a38e7e"
- integrity sha512-WBMI1b7kH+M9H8joLT781e9ZZS9Wy4H8k4FVMJxDCPGvGSZJuC0n9AXp1uqXqJO1FSsWk7ejNFx6di+9qgS8rA==
+"@iot-app-kit/source-iottwinmaker@10.2.0":
+ version "10.2.0"
+ resolved "https://registry.yarnpkg.com/@iot-app-kit/source-iottwinmaker/-/source-iottwinmaker-10.2.0.tgz#48d1dec9c42ef4788819f1acaa8189920dea8a7d"
+ integrity sha512-Q8lq8cfFkB6NvQIOlfEEbMXggXQiLTDP9TWkixf+D27s3Shg1KaUldMmN5Mh/mDRFEQxTpTxqMyLdIMi4RklWw==
dependencies:
"@aws-sdk/client-iotsitewise" "3.456.0"
"@aws-sdk/client-iottwinmaker" "3.335.0"
@@ -8080,7 +8034,7 @@
"@aws-sdk/client-s3" "3.335.0"
"@aws-sdk/client-secrets-manager" "3.353.0"
"@aws-sdk/url-parser" "3.374.0"
- "@iot-app-kit/core" "10.0.0"
+ "@iot-app-kit/core" "10.2.0"
"@tanstack/query-core" "^4.29.15"
lodash "^4.17.21"
rxjs "^7.8.1"
@@ -10102,20 +10056,20 @@
resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-4.36.1.tgz#79f8c1a539d47c83104210be2388813a7af2e524"
integrity sha512-DJSilV5+ytBP1FbFcEJovv4rnnm/CokuVvrBEtW/Va9DvuJ3HksbXUJEpI0aV1KtuL4ZoO9AVE6PyNLzF7tLeA==
-"@tanstack/query-core@5.22.2":
- version "5.22.2"
- resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.22.2.tgz#af67d41b0b4a3e846c2325f32540f39ca0d4788d"
- integrity sha512-z3PwKFUFACMUqe1eyesCIKg3Jv1mysSrYfrEW5ww5DCDUD4zlpTKBvUDaEjsfZzL3ULrFLDM9yVUxI/fega1Qg==
+"@tanstack/query-core@5.24.1":
+ version "5.24.1"
+ resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.24.1.tgz#d40928dec22b47df97fb2648e8c499772e8d7eb2"
+ integrity sha512-DZ6Nx9p7BhjkG50ayJ+MKPgff+lMeol7QYXkvuU5jr2ryW/4ok5eanaS9W5eooA4xN0A/GPHdLGOZGzArgf5Cg==
"@tanstack/query-devtools@5.24.0":
version "5.24.0"
resolved "https://registry.yarnpkg.com/@tanstack/query-devtools/-/query-devtools-5.24.0.tgz#b9b7828d42d5034415b1973ff4a154e880b17d59"
integrity sha512-pThim455t69zrZaQKa7IRkEIK8UBTS+gHVAdNfhO72Xh4rWpMc63ovRje5/n6iw63+d6QiJzVadsJVdPoodSeQ==
-"@tanstack/react-query-devtools@^5.24.0":
- version "5.24.0"
- resolved "https://registry.yarnpkg.com/@tanstack/react-query-devtools/-/react-query-devtools-5.24.0.tgz#a3d0cfdc9ef72977e3c905230d4cd805dc377920"
- integrity sha512-ae3TSg9hKSicLP6TZMj4hglLsLBaS8O3ex/mgHZNQ8yKCDLnVoLO1a9EqYWPzw2k+uaK5uMCKBAVbLVBLx93oA==
+"@tanstack/react-query-devtools@^5.24.1":
+ version "5.24.1"
+ resolved "https://registry.yarnpkg.com/@tanstack/react-query-devtools/-/react-query-devtools-5.24.1.tgz#e3a8ea71115fb899119126e1507fc340ee9d9496"
+ integrity sha512-qa4SEugN+EF8JJXcpsM9Lu05HfUv5cvHvLuB0uw/81eJZyNHFdtHFBi5RLCgpBrOyVMDfH8UQ3VBMqXzFKV68A==
dependencies:
"@tanstack/query-devtools" "5.24.0"
@@ -10127,12 +10081,12 @@
"@tanstack/query-core" "4.36.1"
use-sync-external-store "^1.2.0"
-"@tanstack/react-query@^5.22.2":
- version "5.22.2"
- resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.22.2.tgz#e5fce278fbdd026fc1d561a4505142b9f93549d7"
- integrity sha512-TaxJDRzJ8/NWRT4lY2jguKCrNI6MRN+67dELzPjNUlvqzTxGANlMp68l7aC7hG8Bd1uHNxHl7ihv7MT50i/43A==
+"@tanstack/react-query@^5.24.1":
+ version "5.24.1"
+ resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.24.1.tgz#bcb913febe0d813cec1fda7783298d07aa998b20"
+ integrity sha512-4+09JEdO4d6+Gc8Y/g2M/MuxDK5IY0QV8+2wL2304wPKJgJ54cBbULd3nciJ5uvh/as8rrxx6s0mtIwpRuGd1g==
dependencies:
- "@tanstack/query-core" "5.22.2"
+ "@tanstack/query-core" "5.24.1"
"@testing-library/dom@^9.0.0":
version "9.2.0"
@@ -10820,10 +10774,10 @@
dependencies:
"@types/react" "*"
-"@types/react@*", "@types/react@16 || 17 || 18", "@types/react@^18.2.57":
- version "18.2.57"
- resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.57.tgz#147b516d8bdb2900219acbfc6f939bdeecca7691"
- integrity sha512-ZvQsktJgSYrQiMirAN60y4O/LRevIV8hUzSOSNB6gfR3/o3wCBFQx3sPwIYtuDMeiVgsSS3UzCV26tEzgnfvQw==
+"@types/react@*", "@types/react@16 || 17 || 18", "@types/react@^18.2.61":
+ version "18.2.61"
+ resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.61.tgz#5607308495037436779939ec0348a5816c08799d"
+ integrity sha512-NURTN0qNnJa7O/k4XUkEW2yfygA+NxS0V5h1+kp9jPwhzZy95q3ADoGMP0+JypMhrZBTTgjKAUlTctde1zzeQA==
dependencies:
"@types/prop-types" "*"
"@types/scheduler" "*"
@@ -11917,10 +11871,10 @@ aws-amplify@^5.3.11:
"@aws-amplify/storage" "5.9.5"
tslib "^2.0.0"
-aws-cdk-lib@2.130.0:
- version "2.130.0"
- resolved "https://registry.yarnpkg.com/aws-cdk-lib/-/aws-cdk-lib-2.130.0.tgz#ce1b8cd1bcf9ca040d600c2570dfbac9b2df3cfb"
- integrity sha512-yK7ibePipdjlI4AFM94fwwtsCkmpWJ0JFZTMPahahC/3Pxe/BA/nnI/4Namvl5QPxW5QlU0xQYU7cywioq3RQg==
+aws-cdk-lib@2.131.0:
+ version "2.131.0"
+ resolved "https://registry.yarnpkg.com/aws-cdk-lib/-/aws-cdk-lib-2.131.0.tgz#6e336e9a3e77b07052d28c017ea020f5c9948341"
+ integrity sha512-9XLgiTgY+q0S3K93VPeJO0chIN8BZwZ3aSrILvF868Dz+0NTNrD2m5M0xGK5Rw0uoJS+N+DvGaz/2hLAiVqcBw==
dependencies:
"@aws-cdk/asset-awscli-v1" "^2.2.202"
"@aws-cdk/asset-kubectl-v20" "^2.1.2"
@@ -12061,18 +12015,18 @@ babel-loader@^8.2.3:
make-dir "^3.1.0"
schema-utils "^2.6.5"
-babel-plugin-formatjs@^10.5.12:
- version "10.5.12"
- resolved "https://registry.yarnpkg.com/babel-plugin-formatjs/-/babel-plugin-formatjs-10.5.12.tgz#d7af7e1d224bc5fc1581371d3a9b55da38fdacfa"
- integrity sha512-pOkJoD5nURdes/6NpL5JeEoF8Nz18yAUmbjhc0jyWtK26QDPUDLsXk2kas5jbu5TFMFI+GFUQ9cSVCewbuvC7g==
+babel-plugin-formatjs@^10.5.13:
+ version "10.5.13"
+ resolved "https://registry.yarnpkg.com/babel-plugin-formatjs/-/babel-plugin-formatjs-10.5.13.tgz#2856143aae4b7fb0376765e96053d79baadea2f1"
+ integrity sha512-0dtMhoa6q0P5lUHBphLd8/y+CRlh5IG3Rq+Wk64kOEDwUVZF8xq1qMSjC3iw1wH4tmP2qTzBL+Bz1xEjyBd/ew==
dependencies:
"@babel/core" "^7.10.4"
"@babel/helper-plugin-utils" "^7.10.4"
"@babel/plugin-syntax-jsx" "7"
"@babel/traverse" "7"
"@babel/types" "^7.12.11"
- "@formatjs/icu-messageformat-parser" "2.7.5"
- "@formatjs/ts-transformer" "3.13.11"
+ "@formatjs/icu-messageformat-parser" "2.7.6"
+ "@formatjs/ts-transformer" "3.13.12"
"@types/babel__core" "^7.1.7"
"@types/babel__helper-plugin-utils" "^7.10.0"
"@types/babel__traverse" "^7.1.7"
@@ -13035,6 +12989,11 @@ cookie-signature@1.0.6:
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==
+cookie-signature@^1.1.0:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.2.1.tgz#790dea2cce64638c7ae04d9fabed193bd7ccf3b4"
+ integrity sha512-78KWk9T26NhzXtuL26cIJ8/qNHANyJ/ZYrmEXFzUmhZdjpBv+DlWlOANRTGBt48YcyslsLrj0bMLFTmXvLRCOw==
+
cookie@0.5.0, cookie@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b"
@@ -13389,10 +13348,10 @@ cwd@0.10.0:
find-pkg "^0.1.2"
fs-exists-sync "^0.1.0"
-cytoscape@^3.27.0:
- version "3.27.0"
- resolved "https://registry.yarnpkg.com/cytoscape/-/cytoscape-3.27.0.tgz#5141cd694570807c91075b609181bce102e0bb88"
- integrity sha512-pPZJilfX9BxESwujODz5pydeGi+FBrXq1rcaB1mfhFXXFJ9GjE6CNndAk+8jPzoXGD+16LtSS4xlYEIUiW4Abg==
+cytoscape@^3.28.1:
+ version "3.28.1"
+ resolved "https://registry.yarnpkg.com/cytoscape/-/cytoscape-3.28.1.tgz#f32c3e009bdf32d47845a16a4cd2be2bbc01baf7"
+ integrity sha512-xyItz4O/4zp9/239wCcH8ZcFuuZooEeF8KHRmzjDfGdXsj3OG9MFSMA0pJE0uX3uCN/ygof6hHf4L7lst+JaDg==
dependencies:
heap "^0.2.6"
lodash "^4.17.21"
@@ -16086,12 +16045,7 @@ ieee754@^1.1.13, ieee754@^1.1.4, ieee754@^1.2.1:
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
-ignore@^5.2.0, ignore@^5.2.4:
- version "5.3.0"
- resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.0.tgz#67418ae40d34d6999c95ff56016759c718c82f78"
- integrity sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==
-
-ignore@^5.3.1:
+ignore@^5.2.0, ignore@^5.2.4, ignore@^5.3.1:
version "5.3.1"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef"
integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==
@@ -19893,10 +19847,10 @@ postcss@^7.0.35:
picocolors "^0.2.1"
source-map "^0.6.1"
-postcss@^8.3.5, postcss@^8.4.19, postcss@^8.4.23, postcss@^8.4.27, postcss@^8.4.32, postcss@^8.4.4:
- version "8.4.32"
- resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.32.tgz#1dac6ac51ab19adb21b8b34fd2d93a86440ef6c9"
- integrity sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==
+postcss@^8.3.5, postcss@^8.4.19, postcss@^8.4.23, postcss@^8.4.27, postcss@^8.4.35, postcss@^8.4.4:
+ version "8.4.35"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.35.tgz#60997775689ce09011edf083a549cea44aabe2f7"
+ integrity sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==
dependencies:
nanoid "^3.3.7"
picocolors "^1.0.0"
@@ -21235,14 +21189,7 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0, semver@^6.3.1:
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
-semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.0, semver@^7.5.3, semver@^7.5.4:
- version "7.5.4"
- resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
- integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
- dependencies:
- lru-cache "^6.0.0"
-
-semver@^7.6.0:
+semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.0, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0:
version "7.6.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d"
integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==
@@ -23083,13 +23030,13 @@ vite-plugin-dynamic-import@^1.5.0:
optionalDependencies:
fsevents "~2.3.2"
-"vite@^3.1.0 || ^4.0.0 || ^5.0.0-0", vite@^5.0.12:
- version "5.0.12"
- resolved "https://registry.yarnpkg.com/vite/-/vite-5.0.12.tgz#8a2ffd4da36c132aec4adafe05d7adde38333c47"
- integrity sha512-4hsnEkG3q0N4Tzf1+t6NdN9dg/L3BM+q8SWgbSPnJvrgH2kgdyzfVJwbR1ic69/4uMJJ/3dqDZZE5/WwqW8U1w==
+"vite@^3.1.0 || ^4.0.0 || ^5.0.0-0", vite@^5.1.5:
+ version "5.1.5"
+ resolved "https://registry.yarnpkg.com/vite/-/vite-5.1.5.tgz#bdbc2b15e8000d9cc5172f059201178f9c9de5fb"
+ integrity sha512-BdN1xh0Of/oQafhU+FvopafUp6WaYenLU/NFoL5WyJL++GxkNfieKzBhM24H3HVsPQrlAqB7iJYTHabzaRed5Q==
dependencies:
esbuild "^0.19.3"
- postcss "^8.4.32"
+ postcss "^8.4.35"
rollup "^4.2.0"
optionalDependencies:
fsevents "~2.3.3"