diff --git a/console/src/Globals.ts b/console/src/Globals.ts index 4c2ad53d57d..c9fe78281f1 100644 --- a/console/src/Globals.ts +++ b/console/src/Globals.ts @@ -5,6 +5,8 @@ import { stripTrailingSlash } from './components/Common/utils/urlUtils'; import { isEmpty } from './components/Common/utils/jsUtils'; import { Nullable } from './components/Common/utils/tsUtils'; +type ConsoleType = 'oss' | 'cloud' | 'pro' | 'pro-cloud'; + declare global { interface Window { __env: { @@ -27,6 +29,7 @@ declare global { projectID: Nullable; userRole: Nullable; cloudRootDomain: Nullable; + consoleType: ConsoleType; }; } const CONSOLE_ASSET_VERSION: string; @@ -63,6 +66,8 @@ const globals = { hasuraCloudTenantId: window.__env.tenantID, hasuraCloudProjectId: window.__env.projectID, cloudDataApiUrl: `${window.location.protocol}//data.${window.__env.cloudRootDomain}`, + userRole: undefined, // userRole is not applicable for the OSS console + consoleType: window.__env.consoleType, }; if (globals.consoleMode === SERVER_CONSOLE_MODE) { if (!window.__env.dataApiUrl) { diff --git a/console/src/components/App/Actions.js b/console/src/components/App/Actions.js index d1cca0c724b..7f0fd369375 100644 --- a/console/src/components/App/Actions.js +++ b/console/src/components/App/Actions.js @@ -1,6 +1,10 @@ import defaultState from './State'; import { loadConsoleOpts } from '../../telemetry/Actions'; -import { fetchServerConfig, fetchHerokuSession } from '../Main/Actions'; +import { + fetchServerConfig, + fetchHerokuSession, + fetchCloudProjectInfo, +} from '../Main/Actions'; const LOAD_REQUEST = 'App/ONGOING_REQUEST'; const DONE_REQUEST = 'App/DONE_REQUEST'; @@ -18,6 +22,7 @@ export const requireAsyncGlobals = ( shouldLoadOpts && dispatch(loadConsoleOpts()), shouldLoadServerConfig && dispatch(fetchServerConfig), dispatch(fetchHerokuSession()), + dispatch(fetchCloudProjectInfo()), ]).finally(callback); }; }; diff --git a/console/src/components/App/App.js b/console/src/components/App/App.js index d05a54d9397..bb4d56a627b 100644 --- a/console/src/components/App/App.js +++ b/console/src/components/App/App.js @@ -33,8 +33,7 @@ const App = ({ }, []); const telemetryShown = React.useRef(false); // should be true only in the case of hasura cloud - const isContextCloud = - window.__env.userRole || window.location.host.includes('cloud'); + const isContextCloud = globals.consoleType === 'cloud'; React.useEffect(() => { if ( diff --git a/console/src/components/Main/Actions.js b/console/src/components/Main/Actions.js index 727fd87b9b9..0235c2c62fe 100644 --- a/console/src/components/Main/Actions.js +++ b/console/src/components/Main/Actions.js @@ -41,6 +41,7 @@ const FETCH_CONSOLE_NOTIFICATIONS_ERROR = const FETCHING_HEROKU_SESSION = 'Main/FETCHING_HEROKU_SESSION'; const FETCHING_HEROKU_SESSION_FAILED = 'Main/FETCHING_HEROKU_SESSION_FAILED'; const SET_HEROKU_SESSION = 'Main/SET_HEROKU_SESSION'; +const SET_CLOUD_PROJECT_INFO = 'Main/SET_CLOUD_PROJECT_INFO'; const RUN_TIME_ERROR = 'Main/RUN_TIME_ERROR'; const registerRunTimeError = data => ({ @@ -465,7 +466,7 @@ export const setHerokuSession = session => ({ // TODO to be queried via Apollo client export const fetchHerokuSession = () => dispatch => { - if (!globals.herokuOAuthClientId || !globals.hasuraCloudTenantId) { + if (globals.consoleType !== 'cloud') { return; } dispatch({ @@ -503,6 +504,83 @@ export const fetchHerokuSession = () => dispatch => { }); }; +const fetchCloudProjectInfo = () => dispatch => { + if (globals.consoleType !== 'cloud') { + return; + } + if (!Endpoints.hasuraCloudDataGraphql) { + return; + } + + // TODO: this needs to be addressed in a better way with Apollo Client + const projectID = globals.hasuraCloudProjectId; + const query = ` + query ProjectsQuery($id: uuid!) { + projects_by_pk(id: $id) { + name + plan_name + tenant { + active + region + custom_domains { + id + fqdn + dns_validation + created_at + cert + } + } + heroku_integrations { + app_id + app_name + project_id + var_name + webhook_id + } + owner { + id + email + } + collaborators { + collaborator { + email + id + } + } + } + } + `; + const variables = { + id: projectID, + }; + return fetch(Endpoints.hasuraCloudDataGraphql, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + credentials: 'include', + body: JSON.stringify({ + query, + variables, + }), + }) + .then(r => r.json()) + .then(data => { + const projectData = data?.data?.projects_by_pk; + dispatch({ + type: SET_CLOUD_PROJECT_INFO, + data: projectData, + }); + }) + .catch(e => { + console.error(e); + dispatch({ + type: SET_CLOUD_PROJECT_INFO, + data: undefined, + }); + }); +}; + const mainReducer = (state = defaultState, action) => { switch (action.type) { case SET_MIGRATION_STATUS_SUCCESS: @@ -646,6 +724,13 @@ const mainReducer = (state = defaultState, action) => { session: action.data, }, }; + case SET_CLOUD_PROJECT_INFO: + return { + ...state, + cloud: { + project: action.data, + }, + }; default: return state; } @@ -670,4 +755,5 @@ export { RUN_TIME_ERROR, registerRunTimeError, fetchConsoleNotifications, + fetchCloudProjectInfo, }; diff --git a/console/src/components/Main/State.ts b/console/src/components/Main/State.ts index d49027b2fe6..64697c18c0e 100644 --- a/console/src/components/Main/State.ts +++ b/console/src/components/Main/State.ts @@ -1,6 +1,39 @@ import { ConsoleNotification } from './ConsoleNotification'; import { HerokuSession } from '../Services/Data/DataSources/CreateDataSource/Heroku/types'; +export type CloudProjectInfo = { + name: string; + plan_name: string; + heroku_integrations: { + app_id: string; + app_name: string; + project_id: string; + var_name: string; + webhook_id: string; + }; + owner: { + id: string; + email: string; + }; + collaborators: { + collaborator: { + id: string; + email: string; + }; + }[]; + tenant: { + active: boolean; + region: string; + custom_domains: { + id: string; + fqdn: string; + dns_validation: string; + created_at: string; + cert: string; + }; + }; +}; + export interface MainState { migrationError: unknown | null; hasuractlEnv: unknown | null; @@ -38,6 +71,9 @@ export interface MainState { heroku: { session?: HerokuSession; }; + cloud: { + project?: CloudProjectInfo; + }; } const defaultState: MainState = { @@ -77,6 +113,9 @@ const defaultState: MainState = { heroku: { session: undefined, }, + cloud: { + project: undefined, + }, }; export default defaultState; diff --git a/console/src/components/Services/Settings/Sidebar.tsx b/console/src/components/Services/Settings/Sidebar.tsx index 42d2774650a..52f95445529 100644 --- a/console/src/components/Services/Settings/Sidebar.tsx +++ b/console/src/components/Services/Settings/Sidebar.tsx @@ -68,11 +68,10 @@ const Sidebar: React.FC = ({ location, metadata }) => { const adminSecret = getAdminSecret(); - // userRole is only present on team console if ( adminSecret && globals.consoleMode !== CLI_CONSOLE_MODE && - (!window.__env.userRole || !window.location.host.includes('cloud')) + globals.consoleType !== 'cloud' ) { sectionsData.push({ key: 'logout', diff --git a/console/src/telemetry/Actions.ts b/console/src/telemetry/Actions.ts index 9bbfd272924..f4e400dcda9 100644 --- a/console/src/telemetry/Actions.ts +++ b/console/src/telemetry/Actions.ts @@ -111,8 +111,7 @@ const setOnboardingCompletedInDB = ( ) => { const successCb = () => { // the success notification won't be shown on cloud - const isCloudContext = - window.__env.userRole || window.location.host.includes('cloud'); + const isCloudContext = globals.consoleType !== 'cloud'; if (!isCloudContext) { dispatch( showSuccessNotification('Success', 'Dismissed console onboarding') diff --git a/server/src-rsr/console.html b/server/src-rsr/console.html index 31972993c8b..0e52fa5b78a 100644 --- a/server/src-rsr/console.html +++ b/server/src-rsr/console.html @@ -12,6 +12,7 @@ assetsVersion: "{{assetsVersion}}", cdnAssets: {{cdnAssets}}, serverVersion: "{{serverVersion}}", + consoleType: "oss", }; window.__env.versionedAssetsPath = window.__env.assetsPath;