Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 0 additions & 87 deletions .github/workflows/publish-development.yaml

This file was deleted.

3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "harperdb-studio",
"version": "4.5.5",
"version": "4.5.6",
"description": "A UI for HarperDB",
"deploymentUrl": "studio.harperdb.io",
"private": true,
Expand All @@ -10,7 +10,6 @@
"start": "HTTPS=true SSL_CRT_FILE=./.cert/cert.pem SSL_KEY_FILE=./.cert/key.pem react-scripts start",
"start:local": "REACT_APP_LOCALSTUDIO=true HTTPS=true SSL_CRT_FILE=./.cert/cert.pem SSL_KEY_FILE=./.cert/key.pem react-scripts start",
"docker": "HTTPS=false react-scripts start",
"build:dev": "PUBLIC_URL=https://d2uv4fa0aeja0t.cloudfront.net react-scripts build",
"build:stage": "GENERATE_SOURCEMAP=false PUBLIC_URL=https://dbjxbnqel2bw9.cloudfront.net react-scripts build",
"build:prod": "GENERATE_SOURCEMAP=false PUBLIC_URL=https://ds5zz9rfvzuta.cloudfront.net react-scripts build",
"build:local": "BUILD_PATH=./build-local GENERATE_SOURCEMAP=false REACT_APP_LOCALSTUDIO=true react-scripts build",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ function WebIDE({
active={activeEditorWindow === EDITOR_WINDOWS.CODE_EDITOR_WINDOW}
file={selectedFile}
onFileChange={async (fileContent) => {
if (!selectedFile) return;
updateFileInMemory(fileContent);
await onFileChange({ path: selectedFile?.path, content: fileContent });
setSelectedFile({ ...selectedFile, content: fileContent, cached: true });
Expand Down
51 changes: 11 additions & 40 deletions src/components/instance/status/SystemInfo.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import React, { useState, useEffect } from 'react';
import React, { useEffect, useState } from 'react';
import { useStoreState } from 'pullstate';
import { Card, CardBody, Row, Col, Button } from 'reactstrap';
import useInterval from 'use-interval';
import { ErrorBoundary } from 'react-error-boundary';

import appState from '../../../functions/state/appState';
import instanceState from '../../../functions/state/instanceState';
import config from '../../../config';

import updateSystemInfo from '../../../functions/api/instance/updateSystemInfo';
import ContentContainer from '../../shared/ContentContainer';
Expand All @@ -24,57 +22,30 @@ function SystemInfo() {
const storage = useStoreState(instanceState, (s) => s.storage);
const iopsAlarms = useStoreState(appState, (s) => s.alarms && s.alarms[compute_stack_id]?.alarmCounts['Disk I/O'], [compute_stack_id]);
const [autoRefresh, setAutoRefresh] = useState(false);
const [loading, setLoading] = useState(true);
const [lastUpdate, setLastUpdate] = useState(null);
const [loading, setLoading] = useState(!systemInfo?.totalMemory);

async function fetchSystemInfo(useCache = false) {
if (useCache) {
await updateSystemInfo({ auth, url, is_local, signal: controller.signal, refresh: !!systemInfo, previousSystemInfo: systemInfo, skip: ['disk', 'network'] });
} else {
await updateSystemInfo({ auth, url, is_local, signal: controller.signal, refresh: !!systemInfo, previousSystemInfo: systemInfo });
}
}
const fetchData = async () => {
setLoading(true);
controller = new AbortController();
await updateSystemInfo({ auth, url, is_local, signal: controller.signal, refresh: !!systemInfo, previousSystemInfo: systemInfo });
setLoading(false);
};

useEffect(() => {
let isMounted = true;

const fetchData = async () => {
setLoading(true);
controller = new AbortController();
await fetchSystemInfo(!!lastUpdate);
if (isMounted) setLoading(false);
};

if (auth) fetchData();
if (auth && !systemInfo?.totalMemory) fetchData();

return () => {
controller?.abort();
isMounted = false;
};
// eslint-disable-next-line
}, [auth, lastUpdate]);

useInterval(() => {
if (auth && autoRefresh) {
setLastUpdate(Date.now());
}
}, config.refresh_content_interval);
}, [auth]);

return (
<ErrorBoundary onError={(error, componentStack) => addError({ error: { message: error.message, componentStack } })} FallbackComponent={ErrorFallback}>
<Row className="floating-card-header">
<Col>host system</Col>
<Col className="text-end">
<Button
color="link"
title="Update Metrics"
className="me-2"
onClick={async () => {
setLoading(true);
await fetchSystemInfo(false);
setLoading(false);
}}
>
<Button color="link" title="Update Metrics" className="me-2" onClick={fetchData}>
<i className={`fa ${loading ? 'fa-spinner fa-spin' : 'fa-sync-alt'}`} />
</Button>
<Button color="link" title="Turn on autofresh" onClick={() => setAutoRefresh(!autoRefresh)}>
Expand Down
55 changes: 16 additions & 39 deletions src/components/instances/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import getCustomer from '../../functions/api/lms/getCustomer';
import getAlarms from '../../functions/api/lms/getAlarms';
import Unpaid from '../shared/Unpaid';
import UnlimitedEnterprise from '../shared/UnlimitedEnterprise';
import useInstanceAuth from '../../functions/state/instanceAuths';

function InstancesIndex() {
const navigate = useNavigate();
Expand All @@ -35,60 +34,38 @@ function InstancesIndex() {
const instances = useStoreState(appState, (s) => s.instances);
const isOrgUser = useStoreState(appState, (s) => s.auth?.orgs?.find((o) => o.customer_id?.toString() === customer_id && o.status !== 'invited'), [customer_id]);
const isOrgOwner = isOrgUser?.status === 'owner';
const [mounted, setMounted] = useState(false);
const [instanceAuths] = useInstanceAuth({});

const refreshInstances = useCallback(() => {
if (auth && customer_id && products && regions && subscriptions) {
getInstances({ auth, customer_id, products, regions, subscriptions, instanceCount: instances?.length });
}
}, [auth, customer_id, products, regions, subscriptions, instances?.length]);

useEffect(() => {
refreshInstances();
}, [auth, customer_id, products, regions, subscriptions]);

useEffect(() => {
if (action === 'login') {
alert.error('Please log in to that instance');
} else if (!isOrgUser) {
alert.error('You have been removed from this organization');
navigate('/');
}
}, [action, alert, instances, isOrgOwner]);
}, [action, alert, isOrgUser]);

useEffect(() => {
if (auth && customer_id) {
getCustomer({ auth, customer_id });
}
}, [customer_id, auth]);

useEffect(() => {
if (auth && customer_id) {
getAlarms({ auth, customer_id });
}
}, [customer_id, instances, auth]);

const refreshInstances = useCallback(() => {
if (auth && products && regions && subscriptions && customer_id && instanceAuths) {
getInstances({ auth, customer_id, products, regions, subscriptions, instanceCount: instances?.length });
}
}, [auth, customer_id, instances, products, regions, subscriptions, instanceAuths]);

useEffect(() => {
refreshInstances();
}, [auth, products, regions, subscriptions, customer_id, instanceAuths, refreshInstances]);
}, [customer_id, auth]);

useInterval(
() => instances?.length && instances.some((i) => ['CREATE_IN_PROGRESS', 'UPDATE_IN_PROGRESS', 'CONFIGURING_NETWORK'].includes(i.status)) && refreshInstances(),
() => instances?.some((i) => ['CREATE_IN_PROGRESS', 'UPDATE_IN_PROGRESS', 'CONFIGURING_NETWORK'].includes(i.status)) && refreshInstances(),
config.refresh_content_interval,
);

useEffect(() => {
if (mounted && instances && isOrgOwner) {
alert.success('You have been made an owner of this organization');
} else if (mounted && instances && !isOrgUser) {
alert.error('You have been removed from this organization');
navigate('/');
} else if (mounted && instances) {
alert.success('You are no longer an owner of this organization');
}
// eslint-disable-next-line
}, [isOrgOwner, isOrgUser?.status]);

useAsyncEffect(
() => setMounted(true),
() => setMounted(false),
[],
);

return (
<div id="instances">
<SubNav refreshInstances={refreshInstances} />
Expand Down
9 changes: 6 additions & 3 deletions src/components/instances/list/CardFront.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,12 @@ function CardFront({ compute_stack_id, instance_id, url, status, instance_name,
return setInstanceData({ ...instanceData, ...registrationResult });
}, [status, instanceAuth?.user, instanceAuth?.pass, lastUpdate]);

useInterval(() => {
if (instanceData.retry) setLastUpdate(Date.now());
}, config.refresh_content_interval / 5);
useInterval(
() => {
if (instanceData.retry) setLastUpdate(Date.now());
},
instanceData.status === 'SSL ERROR' ? config.refresh_content_interval / 3 : config.refresh_content_interval,
);

return (
<ErrorBoundary onError={(error, componentStack) => addError({ error: { message: error.message, componentStack } })} FallbackComponent={ErrorFallback}>
Expand Down
35 changes: 2 additions & 33 deletions src/functions/instances/handleInstanceRegistration.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
import registrationInfo from '../api/instance/registrationInfo';
import getFingerprint from '../api/instance/getFingerprint';
import restartInstance from '../api/instance/restartInstance';
import setLicense from '../api/instance/setLicense';

import createLicense from '../api/lms/createLicense';
import handleCloudInstanceUsernameChange from './handleCloudInstanceUsernameChange';

export default async ({ auth, customer_id, instanceAuth, url, is_local, is_ssl, cloud_provider, instance_id, compute_stack_id, compute, status }) => {
Expand Down Expand Up @@ -60,41 +55,15 @@ export default async ({ auth, customer_id, instanceAuth, url, is_local, is_ssl,
return {
status: 'UNABLE TO CONNECT',
error: true,
retry: true,
};
}

const registration_matches_stripe_plan = !compute || (registration.registered && registration.ram_allocation === compute.compute_ram);

if (registration_matches_stripe_plan) {
return {
status: 'OK',
error: false,
version: registration.version,
retry: false,
};
}

const fingerprint = await getFingerprint({ auth: instanceAuth, url });
const license = await createLicense({ auth, compute_stack_id, customer_id, fingerprint });
const apply = await setLicense({ auth: instanceAuth, key: license.key, company: license.company.toString(), url });

if (apply.error) {
return {
status: 'APPLYING LICENSE',
error: false,
version: registration.version,
retry: true,
};
}

restartInstance({ auth: instanceAuth, url });

return {
status: 'APPLYING LICENSE',
status: 'OK',
error: false,
version: registration.version,
retry: true,
retry: false,
};
// eslint-disable-next-line
} catch (e) {
Expand Down
Loading