diff --git a/ui/packages/platform/src/components/AddDbLabInstanceFormWrapper/AddDblabInstanceForm.tsx b/ui/packages/platform/src/components/AddDbLabInstanceFormWrapper/AddDblabInstanceForm.tsx
index 6084b2dae8b9b7d7589b1ef38f1318b45bbe4971..4fc65a8d4c961c488a8c0f68e52bc6ebfebe0c92 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,
- }}
- />
-
-
- Generate
-
-
-
- )}
-
-
- {
- 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,
- }}
- />
-
-
-
-
- Verify URL
-
-
- {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}
-
-
-
-
- {this.props.edit ? 'Update' : 'Add'}
-
-
-
- Cancel
-
-
-
-
- )
- }
- }
-
- 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,
+ }}
+ />
+
+
+ Generate
+
+
+
+ )}
+
+
+ {
+ 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,
+ }}
+ />
+
+
+
+
+ Verify URL
+
+
+ {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}
+
+
+
+
+ {this.props.edit ? 'Update' : 'Add'}
+
+
+
+ Cancel
+
+
+
+
+ )
+ }
+}
+
+export default DbLabInstanceForm
diff --git a/ui/packages/platform/src/components/DbLabInstanceForm/utils/index.ts b/ui/packages/platform/src/components/DbLabInstanceForm/utils/index.ts
index f47a2f8427d6497255171a68c637306ab22ca213..68fa0f4b1950178e0e46d9019b159ac45d9fa7b1 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 42f42a98ef3c2ccb1200c6c78bf083ab3a6b83e4..5282fda325baa5dfaab5f1bea0021f1d3781f695 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/components/DbLabInstances/DbLabInstances.tsx b/ui/packages/platform/src/components/DbLabInstances/DbLabInstances.tsx
index 34724b50bf657c8841487855d4c2448d5edf002f..5587bf2634960dd764dfa8dba249f4c1b6bd2399 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 326f1168bac49b4b1c9906598c066dcf766fbdcc..e8bbb35d0177b0bef7592822602a71aaaeac4212 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 e3a4a1a0de6864721bc1a2958b8f35b3070da1c7..10732dc708941e48d485b143a30b6a88ca2a95c8 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'
+ )}
diff --git a/ui/packages/platform/src/config/env.ts b/ui/packages/platform/src/config/env.ts
index 3ae7d53ec00aa72dc7ba63e05f7608bbbe2dd31c..3b802ffeec93588c3baa743276c69ec244f2de2c 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
diff --git a/ui/packages/platform/src/pages/Instance/index.tsx b/ui/packages/platform/src/pages/Instance/index.tsx
index 380c934ecbea803f3afdbffa6cf785db9483c71d..5452a6e997d1965d29a18140253d856109aa909a 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 03c9bdbe6ff78f81ce2ceba3e44a37d24924afd7..9d4c0f7fd63d1d2fd1b2a3a508dd78e02c71f72a 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 3b66b553f2ede0fdee114749fb028873202d0c79..18566e571175780e0adcb4e2f7fa474b831e5fad 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 82f06a8ed04dde8fbd7fb8dd0770da8b989f751a..93cd54b541993baf3fd8f0cb88798a566b6f238e 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 (
-
-
- {children}
-
-
- )
- }
-
- 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 (
+
+
+ {children}
+
+
+ )
+}
diff --git a/ui/packages/shared/pages/Instance/stores/Main.ts b/ui/packages/shared/pages/Instance/stores/Main.ts
index a87bef493dc364ea1c5157165441b78e630f4b6f..6f3f21d2fb13042628293f34b7e709a34955d504 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)
}