diff --git a/src/__tests__/api/integrations/storage/active.spec.ts b/src/__tests__/api/integrations/storage/active.spec.ts new file mode 100644 index 000000000..b2125b7b7 --- /dev/null +++ b/src/__tests__/api/integrations/storage/active.spec.ts @@ -0,0 +1,171 @@ +import activeHandler from "pages/api/integrations/storage/active"; +import credentialsHandler from "pages/api/integrations/storage/credentials"; +import { + createAuthenticatedMocks, + setupAllTestData, +} from "__tests__/api/_test-utils"; +import { createKeyValueDomainPersistenceService } from "backend/lib/key-value"; + +describe("/api/integrations/actions/[key]/index", () => { + beforeAll(async () => { + const _currentStorageKeyValueStoreApiService = + createKeyValueDomainPersistenceService("current-storage"); + + _currentStorageKeyValueStoreApiService.clearItem(); + + await setupAllTestData(["users", "credentials"]); + }); + + describe("CREATE", () => { + describe("with invalid input", () => { + it("should throw error on request", async () => { + const { req, res } = createAuthenticatedMocks({ + method: "POST", + body: { + storageKey: "s3", + configuration: { + region: "some invalid region", + }, + }, + }); + await activeHandler(req, res); + + expect(res._getStatusCode()).toBe(400); + expect(res._getJSONData()).toMatchInlineSnapshot(` + { + "message": "Invalid Request", + "method": "POST", + "name": "BadRequestError", + "path": "", + "statusCode": 400, + "validations": { + "accessKeyId": "Access Key Id is required", + "secretAccessKey": "Secret Access Key is required", + }, + } + `); + }); + + it("should not save the credentials", async () => { + const { req: credentialsReq, res: credentialsRes } = + createAuthenticatedMocks({ + method: "POST", + body: { + _password: "password", + }, + }); + await credentialsHandler(credentialsReq, credentialsRes); + + expect(credentialsRes._getJSONData()).toMatchInlineSnapshot(`{}`); + }); + }); + + describe("valid", () => { + it("should activate a storage key", async () => { + const { req, res } = createAuthenticatedMocks({ + method: "POST", + body: { + storageKey: "s3", + configuration: { + key1: "should not be saved", + accessKeyId: "some-access-key-id", + secretAccessKey: "some-secret-access-key", + region: "some-region", + }, + }, + }); + await activeHandler(req, res); + + expect(res._getStatusCode()).toBe(201); + }); + + it("should show the activated storage", async () => { + const { req: activeReq, res: activeRes } = createAuthenticatedMocks({ + method: "GET", + }); + + await activeHandler(activeReq, activeRes); + + expect(activeRes._getJSONData()).toMatchInlineSnapshot(` + { + "data": "s3", + } + `); + }); + + it("should save the credentials", async () => { + const { req: credentialsReq, res: credentialsRes } = + createAuthenticatedMocks({ + method: "POST", + body: { + _password: "password", + }, + }); + await credentialsHandler(credentialsReq, credentialsRes); + + expect(credentialsRes._getStatusCode()).toBe(201); + expect(credentialsRes._getJSONData()).toMatchInlineSnapshot(` + { + "accessKeyId": "some-access-key-id", + "region": "some-region", + "secretAccessKey": "some-secret-access-key", + } + `); + }); + }); + }); + + describe("UPDATE", () => { + it("should update storage configuration", async () => { + const { req, res } = createAuthenticatedMocks({ + method: "POST", + body: { + storageKey: "cloudinary", + configuration: { + invalid: "should not show up", + apiKey: "updated some-api-key", + apiSecret: "updated some-api-secret", + cloudName: "updated some-cloud-name", + }, + }, + }); + await activeHandler(req, res); + + expect(res._getStatusCode()).toBe(201); + }); + + it("should show the activated storage", async () => { + const { req: activeReq, res: activeRes } = createAuthenticatedMocks({ + method: "GET", + }); + + await activeHandler(activeReq, activeRes); + + expect(activeRes._getJSONData()).toMatchInlineSnapshot(` + { + "data": "cloudinary", + } + `); + }); + + it("should return updated storage config", async () => { + const { req: credentialsReq, res: credentialsRes } = + createAuthenticatedMocks({ + method: "POST", + body: { + _password: "password", + }, + }); + await credentialsHandler(credentialsReq, credentialsRes); + + expect(credentialsRes._getStatusCode()).toBe(201); + expect(credentialsRes._getJSONData()).toMatchInlineSnapshot(` + { + "apiKey": "updated some-api-key", + "apiSecret": "updated some-api-secret", + "cloudName": "updated some-cloud-name", + } + `); + }); + }); +}); diff --git a/src/frontend/_layouts/app/IsSignedIn.tsx b/src/frontend/_layouts/app/IsSignedIn.tsx index cb9f3c6fe..de3d4a8d8 100644 --- a/src/frontend/_layouts/app/IsSignedIn.tsx +++ b/src/frontend/_layouts/app/IsSignedIn.tsx @@ -1,23 +1,19 @@ import React, { ReactNode, useEffect } from "react"; -import { useRouter } from "next/router"; import { AUTHENTICATED_ACCOUNT_URL } from "frontend/hooks/auth/user.store"; import { useUserAuthenticatedState } from "frontend/hooks/auth/useAuthenticateUser"; import { useQueryClient } from "react-query"; import { removeAuthToken } from "frontend/hooks/auth/auth.store"; import { getQueryCachekey } from "frontend/lib/data/constants/getQueryCacheKey"; import { ComponentIsLoading } from "frontend/design-system/components/ComponentIsLoading"; -import { NAVIGATION_LINKS } from "frontend/lib/routing/links"; import { useAppTheme } from "../useAppTheme"; const useUserAuthCheck = () => { const userAuthenticatedState = useUserAuthenticatedState(); - const router = useRouter(); const queryClient = useQueryClient(); useEffect(() => { if (userAuthenticatedState === false) { removeAuthToken(); - router.replace(NAVIGATION_LINKS.AUTH_SIGNIN); queryClient.invalidateQueries( getQueryCachekey(AUTHENTICATED_ACCOUNT_URL) ); diff --git a/src/frontend/design-system/components/DropdownMenu/index.tsx b/src/frontend/design-system/components/DropdownMenu/index.tsx index e9802f4ce..594289d30 100644 --- a/src/frontend/design-system/components/DropdownMenu/index.tsx +++ b/src/frontend/design-system/components/DropdownMenu/index.tsx @@ -23,7 +23,6 @@ export interface IDropDownMenuItem extends IGroupActionButton { export interface IProps { menuItems: IDropDownMenuItem[]; - isMakingActionRequest?: boolean; ariaLabel: string; disabled?: boolean; ellipsis?: true; @@ -125,7 +124,6 @@ const CurrentButton = styled(SoftButtonStyled)` `; export function DropDownMenu({ menuItems: menuItems$1, - isMakingActionRequest, disabled, ellipsis, ariaLabel, @@ -135,7 +133,7 @@ export function DropDownMenu({ const router = useRouter(); const toggleDropDown = () => { - if (!isMakingActionRequest && !disabled) { + if (!disabled) { setDropDownOpen(togglePreviousState); } }; @@ -185,12 +183,11 @@ export function DropDownMenu({ const currentItem = ( - {/* eslint-disable-next-line no-nested-ternary */} - {isMakingActionRequest ? ( + {currentMenuItem.isMakingRequest ? ( - ) : systemIcon ? ( + ) : ( - ) : null} + )} ); @@ -199,7 +196,7 @@ export function DropDownMenu({ return ( runAction(currentMenuItem)} > {currentItem} @@ -228,7 +225,7 @@ export function DropDownMenu({ <> runAction(currentMenuItem)} type="button" > @@ -248,11 +245,15 @@ export function DropDownMenu({ type="button" > - + {currentMenuItem.isMakingRequest ? ( + + ) : ( + + )} { }; export function useAuthenticateUser() { - const router = useRouter(); const setIsAuthenticated = useIsAuthenticatedStore( (store) => store.setIsAuthenticated ); @@ -44,9 +39,5 @@ export function useAuthenticateUser() { AuthStore.setAuthToken(authToken, rememberMe); setIsAuthenticated(true); - router.push( - TemporayStorageService.getString(STORAGE_CONSTANTS.PREVIOUS_AUTH_URL) || - NAVIGATION_LINKS.DASHBOARD.HOME - ); }; } diff --git a/src/frontend/lib/data/makeRequest.ts b/src/frontend/lib/data/makeRequest.ts index 0d9f14479..b3e388a33 100644 --- a/src/frontend/lib/data/makeRequest.ts +++ b/src/frontend/lib/data/makeRequest.ts @@ -3,6 +3,7 @@ import { REQUEST_ERROR_CODES } from "shared/constants/auth"; import { TemporayStorageService } from "frontend/lib/storage"; import { STORAGE_CONSTANTS } from "frontend/lib/storage/constants"; import { ApiRequestError } from "./_errors"; +import { NAVIGATION_LINKS } from "../routing/links"; const pathWithBaseUrl = (path: string) => { if (path.startsWith("http")) { @@ -35,7 +36,7 @@ const handleRequestError = async (response: Response, errorMessage: string) => { STORAGE_CONSTANTS.PREVIOUS_AUTH_URL, window.location.href ); - window.location.replace("/auth"); + window.location.replace(NAVIGATION_LINKS.AUTH_SIGNIN); } } throw new ApiRequestError(response.status, error.message || errorMessage); diff --git a/src/frontend/views/entity/Actions/Form.tsx b/src/frontend/views/entity/Actions/Form.tsx index 9d91838e1..07a214bd1 100644 --- a/src/frontend/views/entity/Actions/Form.tsx +++ b/src/frontend/views/entity/Actions/Form.tsx @@ -39,17 +39,16 @@ export function ActionForm({ value: integration, })); - const [formValues, setFormValues] = useState>({}); + const [integration, setIntegration] = useState(""); + const [action, setAction] = useState(""); - const implementations = useIntegrationImplementationsList( - formValues.integration - ); + const implementations = useIntegrationImplementationsList(integration); - const currentActionTitle = integrationsListMap[formValues.integration]?.title; + const currentActionTitle = integrationsListMap[integration]?.title; const selectedImplementation = Object.fromEntries( Object.entries( - implementations.data.find(({ key }) => key === formValues.action) + implementations.data.find(({ key }) => key === action) ?.configurationSchema || {} ).map(([key, value]) => [ `${CONFIGURATION_FORM_PREFIX}${key}`, @@ -89,6 +88,7 @@ export function ActionForm({ formState: ($) => ({ disabled: $.action === "update" || !$.formValues.trigger, }), + onChange: setIntegration, }, action: { label: "Action", @@ -101,6 +101,7 @@ export function ActionForm({ formState: ($) => ({ disabled: !$.formValues.trigger, }), + onChange: setAction, }, ...selectedImplementation, }; @@ -122,7 +123,6 @@ export function ActionForm({ initialValues={initialValues$1} fields={fields} systemIcon={formAction === "create" ? "Plus" : "Save"} - onChange={setFormValues} action={formAction} onSubmit={async (value) => { const cleanedConfigurationForm = Object.entries(value).reduce( diff --git a/src/frontend/views/integrations/storage/Credentials.tsx b/src/frontend/views/integrations/storage/Credentials.tsx index 281e2c79b..582f66cbc 100644 --- a/src/frontend/views/integrations/storage/Credentials.tsx +++ b/src/frontend/views/integrations/storage/Credentials.tsx @@ -46,6 +46,7 @@ export function StorageCredentialsSettings() { label: datum.title, value: datum.key, })), + onChange: setCurrentStorage, validations: [ { validationType: "required", @@ -89,9 +90,6 @@ export function StorageCredentialsSettings() { ) : ( - onChange={(data) => { - setCurrentStorage(data.storageKey); - }} fields={{ storageKey: storageFormConfig, ...(currentStorageDetails?.configurationSchema || {}), diff --git a/src/frontend/views/settings/_Base.tsx b/src/frontend/views/settings/_Base.tsx index 44a335bea..a3eb6395b 100644 --- a/src/frontend/views/settings/_Base.tsx +++ b/src/frontend/views/settings/_Base.tsx @@ -63,7 +63,7 @@ export function BaseSettingsLayout({ children }: IProps) { const menuItems = useMutateBaseSettingsMenu(baseMenuItems); return ( - {/* {false && ( // TODO log the user who click on the button to not disturb again + {/* {true && ( TODO <>

- Awesome!, + Hi There!

- You have been using DashPress for about a week now. Hope you - are enjoying it so far. -

-

- We have spent countless hours developing this free app, and we - would really appreciate it if you could drop a star on Github, - It would mean a lot to us + Looks like you are enjoying DashPress, We have worked hard + developing this app, and you can tell us thank you by giving + us a star on Github. It would mean a lot to us!

}