Skip to content

Commit

Permalink
🪟 🎨 Add FCP enrollment banner on source/destination item page (#7082)
Browse files Browse the repository at this point in the history
  • Loading branch information
josephkmh committed Jun 7, 2023
1 parent 7caff75 commit 7649bf0
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 14 deletions.
2 changes: 1 addition & 1 deletion airbyte-webapp/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,7 @@
"tables.name": "Name",
"tables.connector": "Connector",
"tables.connections": "Connections",
"tables.connections.pluralized": "{value, plural, one {connection} other {# connections}}",
"tables.connections.pluralized": "{value, plural, one {# connection} other {# connections}}",
"tables.sourceConnectWith": "Destination",
"tables.destinationConnectWith": "Source",
"tables.sources": "Sources",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { mockConnection } from "test-utils";
import { mockDestinationDefinition } from "test-utils/mock-data/mockDestination";
import { mockSourceDefinition } from "test-utils/mock-data/mockSource";

import { DestinationDefinitionRead, SourceDefinitionRead, WebBackendConnectionRead } from "core/request/AirbyteClient";

import {
isConnectionEligibleForFCP,
isDestinationDefinitionEligibleForFCP,
isSourceDefinitionEligibleForFCP,
} from "./model";

const deprecatedConnection: WebBackendConnectionRead = { ...mockConnection, status: "deprecated" };
const alphaSource: SourceDefinitionRead = { ...mockSourceDefinition, releaseStage: "alpha" };
const betaSource: SourceDefinitionRead = { ...mockSourceDefinition, releaseStage: "beta" };
const gaSource: SourceDefinitionRead = {
...mockSourceDefinition,
releaseStage: "generally_available",
};
const customSource: SourceDefinitionRead = { ...mockSourceDefinition, releaseStage: "custom" };
const alphaDestination: DestinationDefinitionRead = { ...mockDestinationDefinition, releaseStage: "alpha" };
const betaDestination: DestinationDefinitionRead = { ...mockDestinationDefinition, releaseStage: "beta" };
const gaDestination: DestinationDefinitionRead = {
...mockDestinationDefinition,
releaseStage: "generally_available",
};
const customDestination: DestinationDefinitionRead = { ...mockDestinationDefinition, releaseStage: "custom" };

describe(`${isConnectionEligibleForFCP.name}`, () => {
it("returns true for an alpha source and GA destination", () => {
expect(isConnectionEligibleForFCP(mockConnection, alphaSource, gaDestination)).toBe(true);
});
it("returns true for a GA source and alpha destination", () => {
expect(isConnectionEligibleForFCP(mockConnection, gaSource, alphaDestination)).toBe(true);
});
it("returns false for a deprecated connection", () => {
expect(isConnectionEligibleForFCP(deprecatedConnection, alphaSource, alphaDestination)).toBe(false);
});
it("returns false for a custom source", () => {
expect(isConnectionEligibleForFCP(deprecatedConnection, customSource, alphaDestination)).toBe(false);
});
});

describe(`${isSourceDefinitionEligibleForFCP.name}`, () => {
it("returns true for an alpha destination", () => {
expect(isSourceDefinitionEligibleForFCP(alphaSource)).toBe(true);
});
it("returns true for an beta destination", () => {
expect(isSourceDefinitionEligibleForFCP(betaSource)).toBe(true);
});
it("returns false for an GA destination", () => {
expect(isSourceDefinitionEligibleForFCP(gaSource)).toBe(false);
});
it("returns false for a custom destination", () => {
expect(isSourceDefinitionEligibleForFCP(customSource)).toBe(false);
});
});

describe(`${isDestinationDefinitionEligibleForFCP.name}`, () => {
it("returns true for an alpha destination", () => {
expect(isDestinationDefinitionEligibleForFCP(alphaDestination)).toBe(true);
});
it("returns true for an beta destination", () => {
expect(isDestinationDefinitionEligibleForFCP(betaDestination)).toBe(true);
});
it("returns false for an GA destination", () => {
expect(isDestinationDefinitionEligibleForFCP(gaDestination)).toBe(false);
});
it("returns false for a custom destination", () => {
expect(isDestinationDefinitionEligibleForFCP(customDestination)).toBe(false);
});
});
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@
import { ReleaseStage } from "core/request/AirbyteClient";
import { DestinationDefinitionRead, SourceDefinitionRead, WebBackendConnectionRead } from "core/request/AirbyteClient";

export const freeReleaseStages: ReleaseStage[] = ["alpha", "beta"];
export const freeReleaseStages = ["alpha", "beta"];

export const isConnectionEligibleForFCP = (
connection: WebBackendConnectionRead,
sourceDefinition: SourceDefinitionRead,
destinationDefinition: DestinationDefinitionRead
): boolean => {
return !!(
connection.status !== "deprecated" &&
sourceDefinition.releaseStage &&
destinationDefinition.releaseStage &&
(freeReleaseStages.includes(sourceDefinition.releaseStage) ||
freeReleaseStages.includes(destinationDefinition.releaseStage))
);
};

export const isSourceDefinitionEligibleForFCP = (sourceDefinition: SourceDefinitionRead): boolean => {
return !!(sourceDefinition.releaseStage && freeReleaseStages.includes(sourceDefinition.releaseStage));
};

export const isDestinationDefinitionEligibleForFCP = (destinationDefinition: DestinationDefinitionRead): boolean => {
return !!(destinationDefinition.releaseStage && freeReleaseStages.includes(destinationDefinition.releaseStage));
};
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { useSchemaChanges } from "hooks/connection/useSchemaChanges";
import { useConnectionEditService } from "hooks/services/ConnectionEdit/ConnectionEditService";
import { useConnectionFormService } from "hooks/services/ConnectionForm/ConnectionFormService";
import { InlineEnrollmentCallout } from "packages/cloud/components/experiments/FreeConnectorProgram/InlineEnrollmentCallout";
import { isConnectionEligibleForFCP } from "packages/cloud/components/experiments/FreeConnectorProgram/lib/model";
import { RoutePaths } from "pages/routePaths";

import styles from "./ConnectionTitleBlock.module.scss";
Expand Down Expand Up @@ -49,9 +50,8 @@ const ConnectorBlock: React.FC<ConnectorBlockProps> = ({ name, icon, id, stage,
};

export const ConnectionTitleBlock = () => {
const {
connection: { name, source, destination, schemaChange, status },
} = useConnectionEditService();
const { connection } = useConnectionEditService();
const { name, source, destination, schemaChange, status } = connection;
const { sourceDefinition, destDefinition } = useConnectionFormService();
const { hasBreakingSchemaChange } = useSchemaChanges(schemaChange);
const fcpEnabled = useFeature(FeatureItem.FreeConnectorProgram);
Expand Down Expand Up @@ -90,10 +90,9 @@ export const ConnectionTitleBlock = () => {
text={<FormattedMessage id="connection.connectionDeletedView" />}
/>
)}
{fcpEnabled &&
status !== ConnectionStatus.deprecated &&
(sourceDefinition.releaseStage !== ReleaseStage.generally_available ||
destDefinition.releaseStage !== ReleaseStage.generally_available) && <InlineEnrollmentCallout />}
{fcpEnabled && isConnectionEligibleForFCP(connection, sourceDefinition, destDefinition) && (
<InlineEnrollmentCallout />
)}
</FlexContainer>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,8 @@ import { NextPageHeaderWithNavigation } from "components/ui/PageHeader/NextPageH
import { StepsIndicator } from "components/ui/StepsIndicator";

import { useTrackPage, PageTrackingCodes } from "core/services/analytics";
import { FeatureItem, useFeature } from "core/services/features";
import { AppActionCodes, useAppMonitoringService } from "hooks/services/AppMonitoringService";
import { useFormChangeTrackerService } from "hooks/services/FormChangeTracker";
import { InlineEnrollmentCallout } from "packages/cloud/components/experiments/FreeConnectorProgram/InlineEnrollmentCallout";
import { RoutePaths } from "pages/routePaths";
import { useCurrentWorkspaceId } from "services/workspaces/WorkspacesService";
import { ConnectorDocumentationWrapper } from "views/Connector/ConnectorDocumentationLayout";
Expand All @@ -35,7 +33,6 @@ export const CreateConnectionPage: React.FC = () => {
useTrackPage(PageTrackingCodes.CONNECTIONS_NEW);
const location = useLocation();
const { formatMessage } = useIntl();
const fcpEnabled = useFeature(FeatureItem.FreeConnectorProgram);
const workspaceId = useCurrentWorkspaceId();
const { trackAction } = useAppMonitoringService();

Expand Down Expand Up @@ -158,7 +155,7 @@ export const CreateConnectionPage: React.FC = () => {
}
/>
)}
{fcpEnabled && <InlineEnrollmentCallout withMargin />}

{renderStep()}
</FormPageContent>
</ConnectorDocumentationWrapper>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ import { StepsTypes } from "components/ConnectorBlocks";
import { NextPageHeaderWithNavigation } from "components/ui/PageHeader/NextPageHeaderWithNavigation";

import { useTrackPage, PageTrackingCodes } from "core/services/analytics";
import { FeatureItem, useFeature } from "core/services/features";
import { useAppMonitoringService } from "hooks/services/AppMonitoringService";
import InlineEnrollmentCallout from "packages/cloud/components/experiments/FreeConnectorProgram/InlineEnrollmentCallout";
import { isDestinationDefinitionEligibleForFCP } from "packages/cloud/components/experiments/FreeConnectorProgram/lib/model";
import { RoutePaths } from "pages/routePaths";
import { useDestinationDefinition } from "services/connector/DestinationDefinitionService";
import { ResourceNotFoundErrorBoundary } from "views/common/ResourceNotFoundErrorBoundary";
Expand All @@ -26,6 +29,7 @@ export const DestinationItemPage: React.FC = () => {
const destination = useGetDestinationFromParams();
const destinationDefinition = useDestinationDefinition(destination.destinationDefinitionId);
const { formatMessage } = useIntl();
const fcpEnabled = useFeature(FeatureItem.FreeConnectorProgram);

const { trackError } = useAppMonitoringService();

Expand All @@ -45,6 +49,7 @@ export const DestinationItemPage: React.FC = () => {
<HeadTitle titles={[{ id: "admin.destinations" }, { title: destination.name }]} />
<NextPageHeaderWithNavigation breadcrumbsData={breadcrumbsData}>
<ConnectorTitleBlock connector={destination} connectorDefinition={destinationDefinition} />
{fcpEnabled && isDestinationDefinitionEligibleForFCP(destinationDefinition) && <InlineEnrollmentCallout />}
<ConnectorNavigationTabs connectorType="destination" connector={destination} id={destination.destinationId} />
</NextPageHeaderWithNavigation>
<Suspense fallback={<LoadingPage />}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ import LoadingPage from "components/LoadingPage";
import { NextPageHeaderWithNavigation } from "components/ui/PageHeader/NextPageHeaderWithNavigation";

import { useTrackPage, PageTrackingCodes } from "core/services/analytics";
import { FeatureItem, useFeature } from "core/services/features";
import { useAppMonitoringService } from "hooks/services/AppMonitoringService";
import InlineEnrollmentCallout from "packages/cloud/components/experiments/FreeConnectorProgram/InlineEnrollmentCallout";
import { isSourceDefinitionEligibleForFCP } from "packages/cloud/components/experiments/FreeConnectorProgram/lib/model";
import { RoutePaths } from "pages/routePaths";
import { useSourceDefinition } from "services/connector/SourceDefinitionService";
import { ResourceNotFoundErrorBoundary } from "views/common/ResourceNotFoundErrorBoundary";
Expand All @@ -26,6 +29,7 @@ export const SourceItemPage: React.FC = () => {
const source = useGetSourceFromParams();
const sourceDefinition = useSourceDefinition(source.sourceDefinitionId);
const { formatMessage } = useIntl();
const fcpEnabled = useFeature(FeatureItem.FreeConnectorProgram);

const breadcrumbBasePath = `/${RoutePaths.Workspaces}/${params.workspaceId}/${RoutePaths.Source}`;

Expand All @@ -45,6 +49,7 @@ export const SourceItemPage: React.FC = () => {
<HeadTitle titles={[{ id: "admin.sources" }, { title: source.name }]} />
<NextPageHeaderWithNavigation breadcrumbsData={breadcrumbsData}>
<ConnectorTitleBlock connector={source} connectorDefinition={sourceDefinition} />
{fcpEnabled && isSourceDefinitionEligibleForFCP(sourceDefinition) && <InlineEnrollmentCallout />}
<ConnectorNavigationTabs connectorType="source" connector={source} id={source.sourceId} />
</NextPageHeaderWithNavigation>
<Suspense fallback={<LoadingPage />}>
Expand Down

0 comments on commit 7649bf0

Please sign in to comment.