Skip to content

Commit

Permalink
Jamakase/workspace fixes (#5323)
Browse files Browse the repository at this point in the history
* Add workspace sidebar. Add workspace localstorage save

* Add invite user modal

* Add fix for name in sidebar
  • Loading branch information
jamakase authored Aug 11, 2021
1 parent 94ea6fe commit ce2bca9
Show file tree
Hide file tree
Showing 46 changed files with 1,124 additions and 123 deletions.
35 changes: 25 additions & 10 deletions airbyte-webapp/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,27 @@ import LoadingPage from "./components/LoadingPage";
import ApiErrorBoundary from "./components/ApiErrorBoundary";
import NotificationService from "components/hooks/services/Notification";
import { AnalyticsInitializer } from "views/common/AnalyticsInitializer";
import { useCurrentWorkspace } from "components/hooks/services/useWorkspace";
import {
useCurrentWorkspace,
usePickFirstWorkspace,
} from "components/hooks/services/useWorkspace";
import { Feature, FeatureService } from "components/hooks/services/Feature";
import { registerService } from "./core/servicesProvider";

registerService("currentWorkspaceProvider", usePickFirstWorkspace);

function useCustomerIdProvider() {
const workspace = useCurrentWorkspace();

return workspace.customerId;
}

const Features: Feature[] = [
{
id: "ALLOW_UPLOAD_CUSTOM_IMAGE",
},
];

const App: React.FC = () => {
return (
<React.StrictMode>
Expand All @@ -28,15 +41,17 @@ const App: React.FC = () => {
<IntlProvider locale="en" messages={en}>
<CacheProvider>
<Suspense fallback={<LoadingPage />}>
<ApiErrorBoundary>
<NotificationService>
<AnalyticsInitializer
customerIdProvider={useCustomerIdProvider}
>
<Routing />
</AnalyticsInitializer>
</NotificationService>
</ApiErrorBoundary>
<FeatureService features={Features}>
<ApiErrorBoundary>
<NotificationService>
<AnalyticsInitializer
customerIdProvider={useCustomerIdProvider}
>
<Routing />
</AnalyticsInitializer>
</NotificationService>
</ApiErrorBoundary>
</FeatureService>
</Suspense>
</CacheProvider>
</IntlProvider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ const LoadingButton: React.FC<IProps> = (props) => {
</>
) : (
props.children
)}{" "}
)}
</ButtonView>
);
}
Expand Down
12 changes: 10 additions & 2 deletions airbyte-webapp/src/components/base/Popout/Popout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ const PopupOpener: React.FC<{
);

type PopoutProps = DropdownProps & {
targetComponent: (props: { onOpen: () => void; value: Value }) => ReactNode;
targetComponent: (props: {
onOpen: () => void;
isOpen: boolean;
value: Value;
}) => ReactNode;
};

const selectStyles = {
Expand Down Expand Up @@ -68,7 +72,11 @@ const Popout: React.FC<PopoutProps> = ({
data-testid={props["data-testid"]}
isOpen={isOpen}
onClose={toggleOpen}
target={targetComponent({ onOpen: toggleOpen, value: props.value })}
target={targetComponent({
onOpen: toggleOpen,
isOpen,
value: props.value,
})}
>
<DropDown
autoFocus
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React, { useContext, useMemo } from "react";
import { Feature, FeatureServiceApi } from "./types";

const featureServiceContext = React.createContext<FeatureServiceApi | null>(
null
);

export function FeatureService({
children,
features = [],
}: {
children: React.ReactNode;
features?: Feature[];
}) {
const featureService = useMemo(
() => ({
features,
hasFeature: (featureId: string): boolean =>
!!features.find((feature) => feature.id === featureId),
}),
[features]
);

return (
<>
<featureServiceContext.Provider value={featureService}>
{children}
</featureServiceContext.Provider>
</>
);
}

export const useFeatureService: () => FeatureServiceApi = () => {
const featureService = useContext(featureServiceContext);
if (!featureService) {
throw new Error("useFeatureService must be used within a FeatureService.");
}
return featureService;
};

export const WithFeature: React.FC<{ featureId: string }> = ({
featureId,
children,
}) => {
const { hasFeature } = useFeatureService();
return hasFeature(featureId) ? <>{children}</> : null;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./FeatureService";
export * from "./types";
10 changes: 10 additions & 0 deletions airbyte-webapp/src/components/hooks/services/Feature/types.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
type Feature = {
id: string;
};

type FeatureServiceApi = {
features: Feature[];
hasFeature: (featureId: string) => boolean;
};

export type { Feature, FeatureServiceApi };
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,21 @@ import WorkspaceResource, { Workspace } from "core/resources/Workspace";
import NotificationsResource, {
Notifications,
} from "core/resources/Notifications";
import { getService } from "core/servicesProvider";
import { useAnalytics } from "../useAnalytics";

const useCurrentWorkspace = (): Workspace => {
export const usePickFirstWorkspace = (): Workspace => {
const { workspaces } = useResource(WorkspaceResource.listShape(), {});

return workspaces[0];
};

const useCurrentWorkspace = (): Workspace => {
const workspaceProviderService = getService("currentWorkspaceProvider");

return workspaceProviderService();
};

const useWorkspace = (): {
workspace: Workspace;
updatePreferences: (data: {
Expand Down
48 changes: 48 additions & 0 deletions airbyte-webapp/src/core/servicesProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { useEffect, useMemo } from "react";
import { useMap } from "react-use";

type Service = any;

type ServicesProvider = {
register(name: string, rm: Service): void;
unregister(name: string): void;
services: Service[];
};

let services: {
[key: string]: Service;
} = {};

export function getServices() {
return Object.values(services);
}

export function getService(serviceId: string): Service {
return services[serviceId];
}

export function registerService(serviceId: string, service: Service): void {
services[serviceId] = service;
}

/**
*
*/
export const useServicesProvider = (): ServicesProvider => {
const [registeredServices, { remove, set }] = useMap<{
[key: string]: Service;
}>();

useEffect(() => {
services = registeredServices;
}, [registeredServices]);

return useMemo<ServicesProvider>(
() => ({
services: Object.values(registeredServices),
register: set,
unregister: remove,
}),
[registeredServices, remove, set]
);
};
37 changes: 26 additions & 11 deletions airbyte-webapp/src/packages/cloud/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ import {
AuthenticationProvider,
useAuthService,
} from "./services/auth/AuthService";
import { FeatureService } from "components/hooks/services/Feature";
import { registerService } from "core/servicesProvider";
import {
useGetWorkspace,
useWorkspaceService,
} from "./services/workspaces/WorkspacesService";

const queryClient = new QueryClient();

Expand All @@ -31,6 +37,13 @@ const useCustomerIdProvider = () => {
return user?.userId ?? "";
};

registerService("currentWorkspaceProvider", () => {
const { currentWorkspaceId } = useWorkspaceService();
const { data: workspace } = useGetWorkspace(currentWorkspaceId ?? "");

return workspace;
});

const App: React.FC = () => {
return (
<React.StrictMode>
Expand All @@ -40,17 +53,19 @@ const App: React.FC = () => {
<QueryClientProvider client={queryClient}>
<CacheProvider>
<Suspense fallback={<LoadingPage />}>
<ApiErrorBoundary>
<NotificationServiceProvider>
<AuthenticationProvider>
<AnalyticsInitializer
customerIdProvider={useCustomerIdProvider}
>
<Routing />
</AnalyticsInitializer>
</AuthenticationProvider>
</NotificationServiceProvider>
</ApiErrorBoundary>
<FeatureService>
<ApiErrorBoundary>
<NotificationServiceProvider>
<AuthenticationProvider>
<AnalyticsInitializer
customerIdProvider={useCustomerIdProvider}
>
<Routing />
</AnalyticsInitializer>
</AuthenticationProvider>
</NotificationServiceProvider>
</ApiErrorBoundary>
</FeatureService>
</Suspense>
</CacheProvider>
</QueryClientProvider>
Expand Down
1 change: 1 addition & 0 deletions airbyte-webapp/src/packages/cloud/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

```
REACT_APP_CLOUD=true
REACT_APP_CLOUD_API_URL=${url}
REACT_APP_API_URL=${url}
REACT_APP_FIREBASE_API_KEY=${key}
REACT_APP_FIREBASE_AUTH_DOMAIN=${domain}
Expand Down
2 changes: 1 addition & 1 deletion airbyte-webapp/src/packages/cloud/config/api.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export const api = {
cloud: "https://dev-cloud.airbyte.io/cloud/v1/",
cloud: process.env.REACT_APP_CLOUD_API_URL ?? "/",
};
18 changes: 18 additions & 0 deletions airbyte-webapp/src/packages/cloud/lib/auth/GoogleAuthService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,24 @@ export class GoogleAuthService implements AuthService {
});
}

async resetPassword(email: string): Promise<UserCredential> {
return firebaseApp
.auth()
.sendPasswordResetEmail(email)
.catch((err) => {
// switch (err.code) {
// case "auth/email-already-in-use":
// throw new FieldError("email", ErrorCodes.Duplicate);
// case "auth/invalid-email":
// throw new FieldError("email", ErrorCodes.Invalid);
// case "auth/weak-password":
// throw new FieldError("password", ErrorCodes.Invalid);
// }

throw err;
});
}

signOut(): Promise<void> {
return firebaseApp.auth().signOut();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ class CloudWorkspacesService extends AirbyteRequestService {
return cloudWorkspace;
}

public async remove(workspaceId: string): Promise<CloudWorkspace> {
return this.fetch<CloudWorkspace>(`${this.url}/delete`, {
public async remove(workspaceId: string): Promise<void> {
return this.fetch<void>(`${this.url}/delete`, {
workspaceId,
});
}
Expand Down
Loading

0 comments on commit ce2bca9

Please sign in to comment.