From 9dfaadd1104710e0235035a52d56a00af525bad5 Mon Sep 17 00:00:00 2001 From: LashaKakabadze Date: Fri, 19 May 2023 12:43:51 +0400 Subject: [PATCH 1/3] only display non-secule connection message if url exists --- .../AddDblabInstanceForm.tsx | 1217 +++++++++-------- .../DbLabInstances/DbLabInstances.tsx | 5 +- .../JoeInstanceForm/JoeInstanceForm.tsx | 4 +- .../components/JoeInstances/JoeInstances.tsx | 7 +- 4 files changed, 621 insertions(+), 612 deletions(-) diff --git a/ui/packages/platform/src/components/AddDbLabInstanceFormWrapper/AddDblabInstanceForm.tsx b/ui/packages/platform/src/components/AddDbLabInstanceFormWrapper/AddDblabInstanceForm.tsx index 6084b2dae..4fc65a8d4 100644 --- a/ui/packages/platform/src/components/AddDbLabInstanceFormWrapper/AddDblabInstanceForm.tsx +++ b/ui/packages/platform/src/components/AddDbLabInstanceFormWrapper/AddDblabInstanceForm.tsx @@ -5,611 +5,612 @@ *-------------------------------------------------------------------------- */ - import { Component } from 'react' - import { - Checkbox, - Grid, - Button, - TextField, - FormControlLabel, - } from '@material-ui/core' - import CheckCircleOutlineIcon from '@material-ui/icons/CheckCircleOutline' - import BlockIcon from '@material-ui/icons/Block' - import WarningIcon from '@material-ui/icons/Warning' - - import { styles } from '@postgres.ai/shared/styles/styles' - import { PageSpinner } from '@postgres.ai/shared/components/PageSpinner' - import { - ClassesType, - ProjectProps, - } from '@postgres.ai/platform/src/components/types' - - import Actions from '../../actions/actions' - import ConsolePageTitle from './../ConsolePageTitle' - import Store from '../../stores/store' - import Urls from '../../utils/urls' - import { generateToken, isHttps } from '../../utils/utils' - import { WarningWrapper } from 'components/Warning/WarningWrapper' - import { ConsoleBreadcrumbsWrapper } from 'components/ConsoleBreadcrumbs/ConsoleBreadcrumbsWrapper' - import { DbLabInstanceFormProps } from 'components/DbLabInstanceForm/DbLabInstanceFormWrapper' - - interface DbLabInstanceFormWithStylesProps extends DbLabInstanceFormProps { - classes: ClassesType - } - - interface DbLabInstanceFormState { - data: { - auth: { - token: string | null - } | null - projects: ProjectProps - newDbLabInstance: { - isUpdating: boolean - isChecking: boolean - isChecked: boolean - isCheckProcessed: boolean - errorMessage: string - error: boolean - isProcessed: boolean - data: { - id: string - } - } | null - dbLabInstances: { - isProcessing: boolean - error: boolean - isProcessed: boolean - data: unknown - } | null - } | null - url: string - token: string | null - useTunnel: boolean - instanceID: string - project: string - project_label: string - errorFields: string[] - sshServerUrl: string - } - - class DbLabInstanceForm extends Component< - DbLabInstanceFormWithStylesProps, - DbLabInstanceFormState - > { - state = { - url: 'https://', - token: null, - useTunnel: false, - instanceID: '', - project: this.props.project ? this.props.project : '', - project_label: '', - errorFields: [''], - sshServerUrl: '', - data: { - auth: { - token: null, - }, - projects: { - data: [], - error: false, - isProcessing: false, - isProcessed: false, - }, - newDbLabInstance: { - isUpdating: false, - isChecked: false, - isChecking: false, - isCheckProcessed: false, - isProcessed: false, - error: false, - errorMessage: '', - data: { - id: '', - }, - }, - dbLabInstances: { - isProcessing: false, - error: false, - isProcessed: false, - data: '', - }, - }, - } - - unsubscribe: () => void - componentDidMount() { - const that = this - const { orgId } = this.props - const url = window.location.href.split('/') - const instanceID = url[url.length - 1] - - this.unsubscribe = Store.listen(function () { - that.setState({ data: this.data, instanceID: instanceID }) - - const auth = this.data && this.data.auth ? this.data.auth : null - const projects = - this.data && this.data.projects ? this.data.projects : null - const dbLabInstances = - this.data && this.data.dbLabInstances ? this.data.dbLabInstances : null - - if (dbLabInstances.data) { - that.setState({ - project_label: dbLabInstances.data[instanceID]?.project_label_or_name, - token: dbLabInstances.data[instanceID]?.verify_token, - useTunnel: dbLabInstances.data[instanceID]?.use_tunnel, - url: dbLabInstances.data[instanceID]?.url, - sshServerUrl: dbLabInstances.data[instanceID]?.ssh_server_url, - }) - } - - if ( - auth && - auth.token && - !projects.isProcessing && - !projects.error && - !projects.isProcessed - ) { - Actions.getProjects(auth.token, orgId) - } - - if ( - auth && - auth.token && - !dbLabInstances?.isProcessing && - !dbLabInstances?.error && - !dbLabInstances?.isProcessed - ) { - Actions.getDbLabInstances(auth.token, orgId, 0) - } - }) - - Actions.refresh() - } - - componentWillUnmount() { - this.unsubscribe() - Actions.resetNewDbLabInstance() - } - - buttonHandler = () => { - const orgId = this.props.orgId ? this.props.orgId : null - const auth = - this.state.data && this.state.data.auth ? this.state.data.auth : null - const data = this.state.data ? this.state.data.newDbLabInstance : null - const errorFields = [] - - if (!this.state.url) { - errorFields.push('url') - } - - if (!this.state.project) { - errorFields.push('project') - } - - if (!this.state.token) { - errorFields.push('token') - } - - if (errorFields.length > 0) { - this.setState({ errorFields: errorFields }) - return - } - - this.setState({ errorFields: [] }) - - if ( - auth && - data && - !data.isUpdating && - this.state.url && - this.state.token && - this.state.project - ) { - Actions[`${this.props.edit ? 'edit' : 'add'}DbLabInstance`](auth.token, { - orgId: orgId, - project: this.state.project, - instanceId: this.props.edit ? this.state.instanceID : null, - projectLabel: this.state.project_label, - url: this.state.url, - instanceToken: this.state.token, - useTunnel: this.state.useTunnel, - sshServerUrl: this.state.sshServerUrl, - }) - } - } - - checkUrlHandler = () => { - const auth = - this.state.data && this.state.data.auth ? this.state.data.auth : null - const data = this.state.data ? this.state.data.newDbLabInstance : null - const errorFields = [] - - if (!this.state.url) { - errorFields.push('url') - return - } - - if (auth && data && !data.isChecking && this.state.url) { - Actions.checkDbLabInstanceUrl( - auth.token, - this.state.url, - this.state.token, - this.state.useTunnel, - ) - } - } - - returnHandler = () => { - this.props.history.push(Urls.linkDbLabInstances(this.props)) - } - - processedHandler = () => { - const data = this.state.data ? this.state.data.newDbLabInstance : null - - this.props.history.push( - Urls.linkDbLabInstance(this.props, data?.data?.id as string), - ) - } - - generateTokenHandler = () => { - this.setState({ token: generateToken() }) - } - - render() { - const { classes, orgPermissions } = this.props - const data = - this.state && this.state.data ? this.state.data.newDbLabInstance : null - const projects = - this.state && this.state.data && this.state.data.projects - ? this.state.data.projects - : null - const projectsList = [] - const dbLabInstances = - this.state && this.state.data && this.state.data.dbLabInstances - ? this.state.data.dbLabInstances - : null - - if (data && data.isProcessed && !data.error) { - this.processedHandler() - Actions.resetNewDbLabInstance() - } - - const breadcrumbs = ( - - ) - - const pageTitle = ( - - ) - - const permitted = !orgPermissions || orgPermissions.dblabInstanceCreate - const disabledOnEdit = this.props.edit - const instancesLoaded = dbLabInstances && dbLabInstances.data - - if (!projects || !projects.data || !instancesLoaded) { - return ( -
- {breadcrumbs} - - {pageTitle} - - -
- ) - } - - if (projects.data && projects.data?.length > 0) { - projects.data.map((p: { name: string; id: number }) => { - return projectsList.push({ title: p.name, value: p.id }) - }) - } - - const isDataUpdating = data && (data.isUpdating || data.isChecking) - - return ( -
- {breadcrumbs} - - {pageTitle} - - {!permitted && ( - - You do not have permission to {this.props.edit ? 'edit' : 'add'}{' '} - Database Lab instances. - - )} - - {!disabledOnEdit && ( - - Database Lab provisioning is currently semi-automated. -
- First, you need to prepare a Database Lab instance on a - separate  machine. Once the instance is ready, register it - here. -
- )} - -
- {data?.errorMessage ? data.errorMessage : null} -
- - -
- { - this.setState({ - project: e.target.value, - }) - Actions.resetNewDbLabInstance() - }} - margin="normal" - error={this.state.errorFields.indexOf('project') !== -1} - fullWidth - inputProps={{ - name: 'project', - id: 'project', - shrink: true, - }} - InputLabelProps={{ - shrink: true, - style: styles.inputFieldLabel, - }} - FormHelperTextProps={{ - style: styles.inputFieldHelper, - }} - /> -
- -
- { - this.setState({ - project_label: e.target.value, - }) - Actions.resetNewDbLabInstance() - }} - margin="normal" - error={this.state.errorFields.indexOf('project_label') !== -1} - fullWidth - inputProps={{ - name: 'project_label', - id: 'project_label', - shrink: true, - }} - InputLabelProps={{ - shrink: true, - style: styles.inputFieldLabel, - }} - FormHelperTextProps={{ - style: styles.inputFieldHelper, - }} - /> -
- - {!disabledOnEdit && ( -
- { - this.setState({ - token: e.target.value, - }) - Actions.resetNewDbLabInstance() - }} - margin="normal" - error={this.state.errorFields.indexOf('token') !== -1} - fullWidth - inputProps={{ - name: 'token', - id: 'token', - shrink: true, - }} - InputLabelProps={{ - shrink: true, - style: styles.inputFieldLabel, - }} - FormHelperTextProps={{ - style: styles.inputFieldHelper, - }} - /> -
- -
-
- )} - -
- { - this.setState({ - url: e.target.value, - }) - Actions.resetNewDbLabInstance() - }} - margin="normal" - helperText={ - !isHttps(this.state.url) && !this.state.useTunnel ? ( - - - - The connection to the Database Lab API is not secure. Use - HTTPS. - - - ) : null - } - error={this.state.errorFields.indexOf('url') !== -1} - fullWidth - inputProps={{ - name: 'url', - id: 'url', - shrink: true, - }} - InputLabelProps={{ - shrink: true, - style: styles.inputFieldLabel, - }} - FormHelperTextProps={{ - style: styles.inputFieldHelper, - }} - /> -
- -
- { - this.setState({ - useTunnel: e.target.checked, - }) - Actions.resetNewDbLabInstance() - }} - id="useTunnel" - name="useTunnel" - /> - } - label="Use tunnel" - labelPlacement="end" - /> -
- { - this.setState({ - sshServerUrl: e.target.value, - }) - Actions.resetNewDbLabInstance() - }} - margin="normal" - error={this.state.errorFields.indexOf('sshServerUrl') !== -1} - fullWidth - inputProps={{ - name: 'sshServerUrl', - id: 'sshServerUrl', - shrink: true, - }} - InputLabelProps={{ - shrink: true, - style: styles.inputFieldLabel, - }} - FormHelperTextProps={{ - style: styles.inputFieldHelper, - }} - /> -
-
-
- - - {data?.isCheckProcessed && - data?.isChecked && - (isHttps(this.state.url) || this.state.useTunnel) ? ( - - {' '} - Verified - - ) : null} - - {data?.isCheckProcessed && - data?.isChecked && - !isHttps(this.state.url) && - !this.state.useTunnel ? ( - - Verified but is - not secure - - ) : null} - - {data?.isCheckProcessed && !data?.isChecked ? ( - - Not available - - ) : null} -
- -
- -    - -
-
-
- ) - } - } - - export default DbLabInstanceForm - \ No newline at end of file +import { Component } from 'react' +import { + Checkbox, + Grid, + Button, + TextField, + FormControlLabel, +} from '@material-ui/core' +import CheckCircleOutlineIcon from '@material-ui/icons/CheckCircleOutline' +import BlockIcon from '@material-ui/icons/Block' +import WarningIcon from '@material-ui/icons/Warning' + +import { styles } from '@postgres.ai/shared/styles/styles' +import { PageSpinner } from '@postgres.ai/shared/components/PageSpinner' +import { + ClassesType, + ProjectProps, +} from '@postgres.ai/platform/src/components/types' + +import Actions from '../../actions/actions' +import ConsolePageTitle from './../ConsolePageTitle' +import Store from '../../stores/store' +import Urls from '../../utils/urls' +import { generateToken, isHttps } from '../../utils/utils' +import { WarningWrapper } from 'components/Warning/WarningWrapper' +import { ConsoleBreadcrumbsWrapper } from 'components/ConsoleBreadcrumbs/ConsoleBreadcrumbsWrapper' +import { DbLabInstanceFormProps } from 'components/DbLabInstanceForm/DbLabInstanceFormWrapper' + +interface DbLabInstanceFormWithStylesProps extends DbLabInstanceFormProps { + classes: ClassesType +} + +interface DbLabInstanceFormState { + data: { + auth: { + token: string | null + } | null + projects: ProjectProps + newDbLabInstance: { + isUpdating: boolean + isChecking: boolean + isChecked: boolean + isCheckProcessed: boolean + errorMessage: string + error: boolean + isProcessed: boolean + data: { + id: string + } + } | null + dbLabInstances: { + isProcessing: boolean + error: boolean + isProcessed: boolean + data: unknown + } | null + } | null + url: string + token: string | null + useTunnel: boolean + instanceID: string + project: string + project_label: string + errorFields: string[] + sshServerUrl: string +} + +class DbLabInstanceForm extends Component< + DbLabInstanceFormWithStylesProps, + DbLabInstanceFormState +> { + state = { + url: 'https://', + token: null, + useTunnel: false, + instanceID: '', + project: this.props.project ? this.props.project : '', + project_label: '', + errorFields: [''], + sshServerUrl: '', + data: { + auth: { + token: null, + }, + projects: { + data: [], + error: false, + isProcessing: false, + isProcessed: false, + }, + newDbLabInstance: { + isUpdating: false, + isChecked: false, + isChecking: false, + isCheckProcessed: false, + isProcessed: false, + error: false, + errorMessage: '', + data: { + id: '', + }, + }, + dbLabInstances: { + isProcessing: false, + error: false, + isProcessed: false, + data: '', + }, + }, + } + + unsubscribe: () => void + componentDidMount() { + const that = this + const { orgId } = this.props + const url = window.location.href.split('/') + const instanceID = url[url.length - 1] + + this.unsubscribe = Store.listen(function () { + that.setState({ data: this.data, instanceID: instanceID }) + + const auth = this.data && this.data.auth ? this.data.auth : null + const projects = + this.data && this.data.projects ? this.data.projects : null + const dbLabInstances = + this.data && this.data.dbLabInstances ? this.data.dbLabInstances : null + + if (dbLabInstances.data) { + that.setState({ + project_label: dbLabInstances.data[instanceID]?.project_label_or_name, + token: dbLabInstances.data[instanceID]?.verify_token, + useTunnel: dbLabInstances.data[instanceID]?.use_tunnel, + url: dbLabInstances.data[instanceID]?.url, + sshServerUrl: dbLabInstances.data[instanceID]?.ssh_server_url, + }) + } + + if ( + auth && + auth.token && + !projects.isProcessing && + !projects.error && + !projects.isProcessed + ) { + Actions.getProjects(auth.token, orgId) + } + + if ( + auth && + auth.token && + !dbLabInstances?.isProcessing && + !dbLabInstances?.error && + !dbLabInstances?.isProcessed + ) { + Actions.getDbLabInstances(auth.token, orgId, 0) + } + }) + + Actions.refresh() + } + + componentWillUnmount() { + this.unsubscribe() + Actions.resetNewDbLabInstance() + } + + buttonHandler = () => { + const orgId = this.props.orgId ? this.props.orgId : null + const auth = + this.state.data && this.state.data.auth ? this.state.data.auth : null + const data = this.state.data ? this.state.data.newDbLabInstance : null + const errorFields = [] + + if (!this.state.url) { + errorFields.push('url') + } + + if (!this.state.project) { + errorFields.push('project') + } + + if (!this.state.token) { + errorFields.push('token') + } + + if (errorFields.length > 0) { + this.setState({ errorFields: errorFields }) + return + } + + this.setState({ errorFields: [] }) + + if ( + auth && + data && + !data.isUpdating && + this.state.url && + this.state.token && + this.state.project + ) { + Actions[`${this.props.edit ? 'edit' : 'add'}DbLabInstance`](auth.token, { + orgId: orgId, + project: this.state.project, + instanceId: this.props.edit ? this.state.instanceID : null, + projectLabel: this.state.project_label, + url: this.state.url, + instanceToken: this.state.token, + useTunnel: this.state.useTunnel, + sshServerUrl: this.state.sshServerUrl, + }) + } + } + + checkUrlHandler = () => { + const auth = + this.state.data && this.state.data.auth ? this.state.data.auth : null + const data = this.state.data ? this.state.data.newDbLabInstance : null + const errorFields = [] + + if (!this.state.url) { + errorFields.push('url') + return + } + + if (auth && data && !data.isChecking && this.state.url) { + Actions.checkDbLabInstanceUrl( + auth.token, + this.state.url, + this.state.token, + this.state.useTunnel, + ) + } + } + + returnHandler = () => { + this.props.history.push(Urls.linkDbLabInstances(this.props)) + } + + processedHandler = () => { + const data = this.state.data ? this.state.data.newDbLabInstance : null + + this.props.history.push( + Urls.linkDbLabInstance(this.props, data?.data?.id as string), + ) + } + + generateTokenHandler = () => { + this.setState({ token: generateToken() }) + } + + render() { + const { classes, orgPermissions } = this.props + const data = + this.state && this.state.data ? this.state.data.newDbLabInstance : null + const projects = + this.state && this.state.data && this.state.data.projects + ? this.state.data.projects + : null + const projectsList = [] + const dbLabInstances = + this.state && this.state.data && this.state.data.dbLabInstances + ? this.state.data.dbLabInstances + : null + + if (data && data.isProcessed && !data.error) { + this.processedHandler() + Actions.resetNewDbLabInstance() + } + + const breadcrumbs = ( + + ) + + const pageTitle = ( + + ) + + const permitted = !orgPermissions || orgPermissions.dblabInstanceCreate + const disabledOnEdit = this.props.edit + const instancesLoaded = dbLabInstances && dbLabInstances.data + + if (!projects || !projects.data || !instancesLoaded) { + return ( +
+ {breadcrumbs} + + {pageTitle} + + +
+ ) + } + + if (projects.data && projects.data?.length > 0) { + projects.data.map((p: { name: string; id: number }) => { + return projectsList.push({ title: p.name, value: p.id }) + }) + } + + const isDataUpdating = data && (data.isUpdating || data.isChecking) + + return ( +
+ {breadcrumbs} + + {pageTitle} + + {!permitted && ( + + You do not have permission to {this.props.edit ? 'edit' : 'add'}{' '} + Database Lab instances. + + )} + + {!disabledOnEdit && ( + + Database Lab provisioning is currently semi-automated. +
+ First, you need to prepare a Database Lab instance on a + separate  machine. Once the instance is ready, register it + here. +
+ )} + +
+ {data?.errorMessage ? data.errorMessage : null} +
+ + +
+ { + this.setState({ + project: e.target.value, + }) + Actions.resetNewDbLabInstance() + }} + margin="normal" + error={this.state.errorFields.indexOf('project') !== -1} + fullWidth + inputProps={{ + name: 'project', + id: 'project', + shrink: true, + }} + InputLabelProps={{ + shrink: true, + style: styles.inputFieldLabel, + }} + FormHelperTextProps={{ + style: styles.inputFieldHelper, + }} + /> +
+ +
+ { + this.setState({ + project_label: e.target.value, + }) + Actions.resetNewDbLabInstance() + }} + margin="normal" + error={this.state.errorFields.indexOf('project_label') !== -1} + fullWidth + inputProps={{ + name: 'project_label', + id: 'project_label', + shrink: true, + }} + InputLabelProps={{ + shrink: true, + style: styles.inputFieldLabel, + }} + FormHelperTextProps={{ + style: styles.inputFieldHelper, + }} + /> +
+ + {!disabledOnEdit && ( +
+ { + this.setState({ + token: e.target.value, + }) + Actions.resetNewDbLabInstance() + }} + margin="normal" + error={this.state.errorFields.indexOf('token') !== -1} + fullWidth + inputProps={{ + name: 'token', + id: 'token', + shrink: true, + }} + InputLabelProps={{ + shrink: true, + style: styles.inputFieldLabel, + }} + FormHelperTextProps={{ + style: styles.inputFieldHelper, + }} + /> +
+ +
+
+ )} + +
+ { + this.setState({ + url: e.target.value, + }) + Actions.resetNewDbLabInstance() + }} + margin="normal" + helperText={ + this.state.url && + !isHttps(this.state.url) && + !this.state.useTunnel ? ( + + + + The connection to the Database Lab API is not secure. Use + HTTPS. + + + ) : null + } + error={this.state.errorFields.indexOf('url') !== -1} + fullWidth + inputProps={{ + name: 'url', + id: 'url', + shrink: true, + }} + InputLabelProps={{ + shrink: true, + style: styles.inputFieldLabel, + }} + FormHelperTextProps={{ + style: styles.inputFieldHelper, + }} + /> +
+ +
+ { + this.setState({ + useTunnel: e.target.checked, + }) + Actions.resetNewDbLabInstance() + }} + id="useTunnel" + name="useTunnel" + /> + } + label="Use tunnel" + labelPlacement="end" + /> +
+ { + this.setState({ + sshServerUrl: e.target.value, + }) + Actions.resetNewDbLabInstance() + }} + margin="normal" + error={this.state.errorFields.indexOf('sshServerUrl') !== -1} + fullWidth + inputProps={{ + name: 'sshServerUrl', + id: 'sshServerUrl', + shrink: true, + }} + InputLabelProps={{ + shrink: true, + style: styles.inputFieldLabel, + }} + FormHelperTextProps={{ + style: styles.inputFieldHelper, + }} + /> +
+
+
+ + + {data?.isCheckProcessed && + data?.isChecked && + (isHttps(this.state.url) || this.state.useTunnel) ? ( + + {' '} + Verified + + ) : null} + + {data?.isCheckProcessed && + data?.isChecked && + !isHttps(this.state.url) && + !this.state.useTunnel ? ( + + Verified but is + not secure + + ) : null} + + {data?.isCheckProcessed && !data?.isChecked ? ( + + Not available + + ) : null} +
+ +
+ +    + +
+
+
+ ) + } +} + +export default DbLabInstanceForm diff --git a/ui/packages/platform/src/components/DbLabInstances/DbLabInstances.tsx b/ui/packages/platform/src/components/DbLabInstances/DbLabInstances.tsx index 34724b50b..5587bf263 100644 --- a/ui/packages/platform/src/components/DbLabInstances/DbLabInstances.tsx +++ b/ui/packages/platform/src/components/DbLabInstances/DbLabInstances.tsx @@ -471,6 +471,7 @@ class DbLabInstances extends Component< ? data.data[index].url : ''} {!isHttps(data.data[index].url) && + data.data[index].url && !data.data[index].use_tunnel ? ( - ) : null} + ) : ( + 'N/A' + )} {data.data[index]?.state?.cloning?.numClones ?? diff --git a/ui/packages/platform/src/components/JoeInstanceForm/JoeInstanceForm.tsx b/ui/packages/platform/src/components/JoeInstanceForm/JoeInstanceForm.tsx index 326f1168b..e8bbb35d0 100644 --- a/ui/packages/platform/src/components/JoeInstanceForm/JoeInstanceForm.tsx +++ b/ui/packages/platform/src/components/JoeInstanceForm/JoeInstanceForm.tsx @@ -355,7 +355,9 @@ class JoeInstanceForm extends Component< }} margin="normal" helperText={ - !isHttps(this.state.url) && !this.state.useTunnel ? ( + this.state.url && + !isHttps(this.state.url) && + !this.state.useTunnel ? ( diff --git a/ui/packages/platform/src/components/JoeInstances/JoeInstances.tsx b/ui/packages/platform/src/components/JoeInstances/JoeInstances.tsx index e3a4a1a0d..10732dc70 100644 --- a/ui/packages/platform/src/components/JoeInstances/JoeInstances.tsx +++ b/ui/packages/platform/src/components/JoeInstances/JoeInstances.tsx @@ -404,7 +404,8 @@ class JoeInstances extends Component< {data.data[i].url ? data.data[i].url : ''} - {!isHttps(data.data[i].url) && + {data.data[i].url && + !isHttps(data.data[i].url) && !data.data[i].use_tunnel ? ( - ) : null} + ) : ( + 'N/A' + )} -- GitLab From b14f56bea648ce4b72f84cddbdeb0d7823a7db2e Mon Sep 17 00:00:00 2001 From: LashaKakabadze Date: Fri, 19 May 2023 13:56:45 +0400 Subject: [PATCH 2/3] roll back inactive instance, hide tabs for platform mode on instance page --- .../platform/src/pages/Instance/index.tsx | 1 + .../shared/pages/Instance/Clones/index.tsx | 4 +- .../shared/pages/Instance/Tabs/index.tsx | 8 +- ui/packages/shared/pages/Instance/context.ts | 1 + ui/packages/shared/pages/Instance/index.tsx | 414 ++++++++++-------- .../shared/pages/Instance/stores/Main.ts | 4 +- 6 files changed, 232 insertions(+), 200 deletions(-) diff --git a/ui/packages/platform/src/pages/Instance/index.tsx b/ui/packages/platform/src/pages/Instance/index.tsx index 380c934ec..5452a6e99 100644 --- a/ui/packages/platform/src/pages/Instance/index.tsx +++ b/ui/packages/platform/src/pages/Instance/index.tsx @@ -92,6 +92,7 @@ export const Instance = () => { return ( { const goToCloneAddPage = () => history.push(host.routes.createClone()) const showListSizeButton = - instance.state.cloning.clones.length > SHORT_LIST_SIZE && isMobile + instance.state.cloning.clones?.length > SHORT_LIST_SIZE && isMobile const isLoadingSnapshots = stores.main.snapshots.isLoading const hasSnapshots = Boolean(stores.main.snapshots.data?.length) diff --git a/ui/packages/shared/pages/Instance/Tabs/index.tsx b/ui/packages/shared/pages/Instance/Tabs/index.tsx index 03c9bdbe6..9d4c0f7fd 100644 --- a/ui/packages/shared/pages/Instance/Tabs/index.tsx +++ b/ui/packages/shared/pages/Instance/Tabs/index.tsx @@ -49,13 +49,13 @@ type Props = { value: number handleChange: (event: React.ChangeEvent<{}>, newValue: number) => void hasLogs: boolean - hideInstanceTabs?: boolean + isPlatform?: boolean } export const Tabs = (props: Props) => { const classes = useStyles() - const { value, handleChange, hasLogs, hideInstanceTabs } = props + const { value, handleChange, hasLogs } = props return ( { label="Logs" disabled={!hasLogs} classes={{ - root: classes.tabRoot, + root: props.isPlatform ? classes.tabHidden : classes.tabRoot, }} value={1} /> diff --git a/ui/packages/shared/pages/Instance/context.ts b/ui/packages/shared/pages/Instance/context.ts index 3b66b553f..18566e571 100644 --- a/ui/packages/shared/pages/Instance/context.ts +++ b/ui/packages/shared/pages/Instance/context.ts @@ -26,6 +26,7 @@ export type Host = { breadcrumbs: React.ReactNode } wsHost?: string + isPlatform?: boolean } // Host context. diff --git a/ui/packages/shared/pages/Instance/index.tsx b/ui/packages/shared/pages/Instance/index.tsx index 82f06a8ed..93cd54b54 100644 --- a/ui/packages/shared/pages/Instance/index.tsx +++ b/ui/packages/shared/pages/Instance/index.tsx @@ -5,196 +5,224 @@ *-------------------------------------------------------------------------- */ - import React, { useEffect } from 'react' - import { makeStyles } from '@material-ui/core' - import { observer } from 'mobx-react-lite' - - import { Button } from '@postgres.ai/shared/components/Button2' - import { StubSpinner } from '@postgres.ai/shared/components/StubSpinner' - import { SectionTitle } from '@postgres.ai/shared/components/SectionTitle' - import { ErrorStub } from '@postgres.ai/shared/components/ErrorStub' - - import { Tabs } from './Tabs' - import { Logs } from '../Logs' - import { Clones } from './Clones' - import { Info } from './Info' - import { Configuration } from '../Configuration' - import { ClonesModal } from './ClonesModal' - import { SnapshotsModal } from './SnapshotsModal' - import { Host, HostProvider, StoresProvider } from './context' - - import PropTypes from 'prop-types' - import Typography from '@material-ui/core/Typography' - import Box from '@mui/material/Box' - - import { useCreatedStores } from './useCreatedStores' - - import './styles.scss' - - type Props = Host - - const useStyles = makeStyles( - (theme) => ({ - title: { - marginTop: '8px', - }, - reloadButton: { - flex: '0 0 auto', - alignSelf: 'flex-start', - }, - errorStub: { - marginTop: '16px', - }, - content: { - display: 'flex', - marginTop: '16px', - position: 'relative', - flex: '1 1 100%', - height: '100%', - - [theme.breakpoints.down('sm')]: { - flexDirection: 'column', - }, - }, - }), - { index: 1 }, - ) - - export const Instance = observer((props: Props) => { - const classes = useStyles() - - const { instanceId, api } = props - - const stores = useCreatedStores(props) - const { instance, instanceError, instanceRetrieval, load } = stores.main - - useEffect(() => { - load(instanceId) - }, [instanceId]) - - const isConfigurationActive = instanceRetrieval?.mode !== 'physical' - - useEffect(() => { - if ( - instance && - instance?.state.retrieving?.status === 'pending' && - isConfigurationActive - ) { - setActiveTab(2) - } - if (instance && !instance?.state?.pools) { - if (!props.callbacks) return - - props.callbacks.showDeprecatedApiBanner() - return props.callbacks?.hideDeprecatedApiBanner - } - }, [instance]) - - const [activeTab, setActiveTab] = React.useState(0) - - const switchTab = (_: React.ChangeEvent<{}> | null, tabID: number) => { - const contentElement = document.getElementById('content-container') - setActiveTab(tabID) - contentElement?.scroll(0, 0) - } - - return ( - - - <> - {props.elements.breadcrumbs} - load(props.instanceId)} - isDisabled={!instance && !instanceError} - className={classes.reloadButton} - > - Reload info - - } - > - - - - {instanceError && ( - - )} - - - {!instanceError && ( -
- {!instance || - (!instance?.state.retrieving?.status && )} - - {instance ? ( - <> - - - - ) : ( - - )} -
- )} - - - - -
- - - {activeTab === 1 && } - - - - - {activeTab === 2 && ( - load(props.instanceId)} - /> - )} - -
-
- ) - }) - - function TabPanel(props: PropTypes.InferProps) { - const { children, value, index, ...other } = props - - return ( - - ) - } - - TabPanel.propTypes = { - children: PropTypes.node, - index: PropTypes.any.isRequired, - value: PropTypes.any.isRequired, - } \ No newline at end of file +import React, { useEffect } from 'react' +import { makeStyles } from '@material-ui/core' +import { observer } from 'mobx-react-lite' + +import { Button } from '@postgres.ai/shared/components/Button2' +import { StubSpinner } from '@postgres.ai/shared/components/StubSpinner' +import { SectionTitle } from '@postgres.ai/shared/components/SectionTitle' +import { ErrorStub } from '@postgres.ai/shared/components/ErrorStub' + +import { Tabs } from './Tabs' +import { Logs } from '../Logs' +import { Clones } from './Clones' +import { Info } from './Info' +import { Configuration } from '../Configuration' +import { ClonesModal } from './ClonesModal' +import { SnapshotsModal } from './SnapshotsModal' +import { InactiveInstance } from './InactiveInstance' +import { Host, HostProvider, StoresProvider } from './context' + +import Typography from '@material-ui/core/Typography' +import Box from '@mui/material/Box' + +import { useCreatedStores } from './useCreatedStores' + +import './styles.scss' + +type Props = Host + +const useStyles = makeStyles( + (theme) => ({ + title: { + marginTop: '8px', + }, + reloadButton: { + flex: '0 0 auto', + alignSelf: 'flex-start', + }, + errorStub: { + marginTop: '16px', + }, + content: { + display: 'flex', + marginTop: '16px', + position: 'relative', + flex: '1 1 100%', + height: '100%', + + [theme.breakpoints.down('sm')]: { + flexDirection: 'column', + }, + }, + }), + { index: 1 }, +) + +export const Instance = observer((props: Props) => { + const classes = useStyles() + + const { instanceId, api } = props + + const stores = useCreatedStores(props) + const { + instance, + instanceError, + instanceRetrieval, + isLoadingInstance, + load, + } = stores.main + + useEffect(() => { + load(instanceId) + }, [instanceId]) + + const isConfigurationActive = instanceRetrieval?.mode !== 'physical' + + useEffect(() => { + if ( + instance && + instance?.state.retrieving?.status === 'pending' && + isConfigurationActive && + !props.isPlatform + ) { + setActiveTab(2) + } + if (instance && !instance?.state?.pools) { + if (!props.callbacks) return + } + }, [instance]) + + const [activeTab, setActiveTab] = React.useState(0) + + const switchTab = (_: React.ChangeEvent<{}> | null, tabID: number) => { + const contentElement = document.getElementById('content-container') + setActiveTab(tabID) + contentElement?.scroll(0, 0) + } + + const isInstanceIntegrated = + !isLoadingInstance && instance && instance?.url && !instanceError + + return ( + + + {props.elements.breadcrumbs} + load(props.instanceId)} + isDisabled={!instance && !instanceError} + className={classes.reloadButton} + > + Reload info + + } + > + {isInstanceIntegrated && ( + + )} + + + {instanceError && ( + + )} + + {isInstanceIntegrated ? ( + <> + + {!instanceError && ( +
+ {!instance || + (!instance?.state.retrieving?.status && )} + + {instance ? ( + <> + + + + ) : ( + + )} +
+ )} + + + + +
+ + {!props.isPlatform && ( + <> + + {activeTab === 1 && } + + + + {activeTab === 2 && ( + load(props.instanceId)} + /> + )} + + + )} + + ) : !isLoadingInstance && !instanceError ? ( + + + + ) : ( + !instanceError && ( + +
+ +
+
+ ) + )} +
+
+ ) +}) + +function TabPanel(props: { + children?: React.ReactNode + index: number + value: number +}) { + const { children, value, index, ...other } = props + + return ( + + ) +} diff --git a/ui/packages/shared/pages/Instance/stores/Main.ts b/ui/packages/shared/pages/Instance/stores/Main.ts index a87bef493..6f3f21d2f 100644 --- a/ui/packages/shared/pages/Instance/stores/Main.ts +++ b/ui/packages/shared/pages/Instance/stores/Main.ts @@ -91,7 +91,9 @@ export class MainStore { this.isReloadingInstance = true this.loadInstance(instanceId) this.loadInstanceRetrieval(instanceId).then(() => { - this.getConfig() + if (this.instanceRetrieval) { + this.getConfig() + } }) this.snapshots.load(instanceId) } -- GitLab From 64af037d649bd09753af88d27b3eff62831c7fd4 Mon Sep 17 00:00:00 2001 From: LashaKakabadze Date: Fri, 19 May 2023 20:18:26 +0400 Subject: [PATCH 3/3] revert env variables, replace prod with debug api server --- .../platform/src/components/DbLabInstanceForm/utils/index.ts | 2 +- .../src/components/DbLabInstanceInstallForm/utils/index.ts | 2 +- ui/packages/platform/src/config/env.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/packages/platform/src/components/DbLabInstanceForm/utils/index.ts b/ui/packages/platform/src/components/DbLabInstanceForm/utils/index.ts index f47a2f842..68fa0f4b1 100644 --- a/ui/packages/platform/src/components/DbLabInstanceForm/utils/index.ts +++ b/ui/packages/platform/src/components/DbLabInstanceForm/utils/index.ts @@ -2,7 +2,7 @@ import { CloudImage } from 'api/cloud/getCloudImages' import { initialState } from '../reducer' const API_SERVER = process.env.REACT_APP_API_SERVER -const DEBUG_API_SERVER = 'https://postgres.ai/api/general' +const DEBUG_API_SERVER = 'https://v2.postgres.ai/api/general' export const availableTags = ['3.4.0-rc.5', '4.0.0-alpha.5'] diff --git a/ui/packages/platform/src/components/DbLabInstanceInstallForm/utils/index.ts b/ui/packages/platform/src/components/DbLabInstanceInstallForm/utils/index.ts index 42f42a98e..5282fda32 100644 --- a/ui/packages/platform/src/components/DbLabInstanceInstallForm/utils/index.ts +++ b/ui/packages/platform/src/components/DbLabInstanceInstallForm/utils/index.ts @@ -1,7 +1,7 @@ import { initialState } from '../reducer' const API_SERVER = process.env.REACT_APP_API_SERVER -const DEBUG_API_SERVER = 'https://postgres.ai/api/general' +const DEBUG_API_SERVER = 'https://v2.postgres.ai/api/general' export const getPlaybookCommand = ( state: typeof initialState, diff --git a/ui/packages/platform/src/config/env.ts b/ui/packages/platform/src/config/env.ts index 3ae7d53ec..3b802ffee 100644 --- a/ui/packages/platform/src/config/env.ts +++ b/ui/packages/platform/src/config/env.ts @@ -7,6 +7,6 @@ export const NODE_ENV = process.env.NODE_ENV export const SENTRY_DSN = process.env.REACT_APP_SENTRY_DSN -export const API_URL_PREFIX = 'https://postgres.ai/api/general' ?? '' +export const API_URL_PREFIX = process.env.REACT_APP_API_SERVER ?? '' export const WS_URL_PREFIX = process.env.REACT_APP_WS_URL_PREFIX ?? '' export const BUILD_TIMESTAMP = process.env.BUILD_TIMESTAMP -- GitLab