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",