diff --git a/airbyte-webapp/src/packages/cloud/lib/domain/cloudWorkspaces/types.ts b/airbyte-webapp/src/packages/cloud/lib/domain/cloudWorkspaces/types.ts index ad9b1e5bfe182..9997fdfbefbc0 100644 --- a/airbyte-webapp/src/packages/cloud/lib/domain/cloudWorkspaces/types.ts +++ b/airbyte-webapp/src/packages/cloud/lib/domain/cloudWorkspaces/types.ts @@ -1,8 +1,16 @@ +export enum CreditStatus { + "POSITIVE" = "positive", + "NEGATIVE_WITHIN_GRACE_PERIOD" = "negative_within_grace_period", + "NEGATIVE_BEYOND_GRACE_PERIOD" = "negative_beyond_grace_period", + "NEGATIVE_MAX_THRESHOLD" = "negative_max_threshold", +} + export interface CloudWorkspace { name: string; workspaceId: string; billingUserId: string; remainingCredits: number; + creditStatus?: CreditStatus; } export interface CreditConsumptionByConnector { diff --git a/airbyte-webapp/src/packages/cloud/locales/en.json b/airbyte-webapp/src/packages/cloud/locales/en.json index 4d345496e2c70..7a37ac93c98af 100644 --- a/airbyte-webapp/src/packages/cloud/locales/en.json +++ b/airbyte-webapp/src/packages/cloud/locales/en.json @@ -100,6 +100,10 @@ "credits.connection": "Connection", "credits.usage": "Usage", "credits.noData": "Data is empty", + "credits.creditsProblem.negative_within_grace_period": "Your workspace is out of credits! Please add more credits to make sure your syncs keep running!", + "credits.creditsProblem.negative_beyond_grace_period": "No syncs can run because this workspace is out of credits! Add more credits to resume syncing.", + "credits.creditsProblem.negative_max_threshold": "No syncs can run because this workspace is out of credits! Add more credits to resume syncing.", + "credits.creditsProblem.link": "Visit credits page", "firebase.auth.success": "A new confirmation email has been sent to you", "firebase.auth.error.invalidPassword": "Incorrect password", diff --git a/airbyte-webapp/src/packages/cloud/views/layout/MainView/MainView.tsx b/airbyte-webapp/src/packages/cloud/views/layout/MainView/MainView.tsx index e1e5c1375251b..7e01f2c9a5e4c 100644 --- a/airbyte-webapp/src/packages/cloud/views/layout/MainView/MainView.tsx +++ b/airbyte-webapp/src/packages/cloud/views/layout/MainView/MainView.tsx @@ -8,6 +8,10 @@ import SideBar from "packages/cloud/views/layout/SideBar"; import { InsufficientPermissionsErrorBoundary } from "./InsufficientPermissionsErrorBoundary"; import { StartOverErrorView } from "views/common/StartOverErrorView"; import { ResourceNotFoundErrorBoundary } from "views/common/ResorceNotFoundErrorBoundary"; +import { useCurrentWorkspace } from "services/workspaces/WorkspacesService"; +import { useGetCloudWorkspace } from "packages/cloud/services/workspaces/WorkspacesService"; +import { CreditStatus } from "packages/cloud/lib/domain/cloudWorkspaces/types"; +import { CreditsProblemBanner } from "./components/CreditsProblemBanner"; const MainContainer = styled.div` width: 100%; @@ -24,21 +28,46 @@ const Content = styled.div` height: 100%; `; -const MainView: React.FC = (props) => ( - - } - > - - - }> - }> - {props.children ?? } - - - - - -); +const DataBlock = styled.div<{ hasBanner?: boolean }>` + width: 100%; + height: 100%; + padding-top: ${({ hasBanner }) => (hasBanner ? 30 : 0)}px; +`; + +const MainView: React.FC = (props) => { + const workspace = useCurrentWorkspace(); + const cloudWorkspace = useGetCloudWorkspace(workspace.workspaceId); + const showBanner = + cloudWorkspace.creditStatus && + [ + CreditStatus.NEGATIVE_BEYOND_GRACE_PERIOD, + CreditStatus.NEGATIVE_MAX_THRESHOLD, + CreditStatus.NEGATIVE_WITHIN_GRACE_PERIOD, + ].includes(cloudWorkspace.creditStatus); + + return ( + + } + > + + + {cloudWorkspace.creditStatus && showBanner && ( + + )} + + } + > + }> + {props.children ?? } + + + + + + + ); +}; export default MainView; diff --git a/airbyte-webapp/src/packages/cloud/views/layout/MainView/components/CreditsProblemBanner.tsx b/airbyte-webapp/src/packages/cloud/views/layout/MainView/components/CreditsProblemBanner.tsx new file mode 100644 index 0000000000000..57847e063c549 --- /dev/null +++ b/airbyte-webapp/src/packages/cloud/views/layout/MainView/components/CreditsProblemBanner.tsx @@ -0,0 +1,40 @@ +import React from "react"; +import styled from "styled-components"; +import { FormattedMessage } from "react-intl"; + +import { CreditStatus } from "packages/cloud/lib/domain/cloudWorkspaces/types"; +import { Link } from "components/Link"; +import { CloudRoutes } from "packages/cloud/cloudRoutes"; + +const Container = styled.div` + height: 30px; + width: 100%; + background: ${({ theme }) => theme.redColor}; + color: ${({ theme }) => theme.blackColor}; + text-align: center; + position: fixed; + z-index: 3; + font-size: 12px; + line-height: 30px; +`; +const CreditsLink = styled(Link)` + color: ${({ theme }) => theme.blackColor}; + margin-left: 8px; +`; + +type CreditsProblemBannerProps = { + status: CreditStatus; +}; + +const CreditsProblemBanner: React.FC = ({ + status, +}) => ( + + + + + + +); + +export { CreditsProblemBanner }; diff --git a/airbyte-webapp/src/theme.ts b/airbyte-webapp/src/theme.ts index 7b24a87a90242..f4ae6f365a603 100644 --- a/airbyte-webapp/src/theme.ts +++ b/airbyte-webapp/src/theme.ts @@ -37,6 +37,7 @@ export const theme = { greyColor0: "#F7F7FA", whiteColor: "#FFFFFF", + blackColor: "#000000", beigeColor: "#FEF9F4", darkBeigeColor: "#FFEBD7", borderTableColor: "#D3DCE4",