mirror of
https://github.com/uqbar-dao/nectar.git
synced 2024-12-22 16:11:38 +03:00
Merge pull request #377 from kinode-dao/tm/ui-dev-servers
configure dev servers' proxies; fix blackscreen
This commit is contained in:
commit
553ad00d51
@ -95,7 +95,7 @@ fn make_widget() -> String {
|
||||
</div>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
fetch('/main:app_store:sys/apps/listed')
|
||||
fetch('/main:app_store:sys/apps/listed', { credentials: 'include' })
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const container = document.getElementById('latest-apps');
|
||||
|
File diff suppressed because one or more lines are too long
@ -14,7 +14,7 @@
|
||||
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport"
|
||||
content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1.00001, viewport-fit=cover" />
|
||||
<script type="module" crossorigin src="/main:app_store:sys/assets/index-Mr04YvPM.js"></script>
|
||||
<script type="module" crossorigin src="/main:app_store:sys/assets/index-I5kjLT9f.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/main:app_store:sys/assets/index-fGthT1qI.css">
|
||||
</head>
|
||||
|
||||
|
@ -5,6 +5,7 @@ import Modal from "./Modal";
|
||||
import { getAppName } from "../utils/app";
|
||||
import Loader from "./Loader";
|
||||
import classNames from "classnames";
|
||||
import { FaU } from "react-icons/fa6";
|
||||
|
||||
interface UpdateButtonProps extends React.HTMLAttributes<HTMLButtonElement> {
|
||||
app: AppInfo;
|
||||
@ -55,10 +56,12 @@ export default function UpdateButton({ app, isIcon = false, ...props }: UpdateBu
|
||||
<button
|
||||
{...props}
|
||||
type="button"
|
||||
className={classNames("text-sm self-start", props.className)}
|
||||
className={classNames("text-sm self-start", props.className, {
|
||||
'icon clear': isIcon
|
||||
})}
|
||||
onClick={onClick}
|
||||
>
|
||||
Update
|
||||
{isIcon ? <FaU /> : 'Update'}
|
||||
</button>
|
||||
<Modal show={showModal} hide={() => setShowModal(false)}>
|
||||
{loading ? (
|
||||
|
File diff suppressed because one or more lines are too long
@ -9,7 +9,7 @@
|
||||
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport"
|
||||
content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1.00001, viewport-fit=cover" />
|
||||
<script type="module" crossorigin src="/assets/index-DqBTDSfz.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-BkgGa32-.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-BS5LP50I.css">
|
||||
</head>
|
||||
|
||||
|
2
kinode/packages/homepage/ui/dist/index.html
vendored
2
kinode/packages/homepage/ui/dist/index.html
vendored
@ -9,7 +9,7 @@
|
||||
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport"
|
||||
content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1.00001, viewport-fit=cover" />
|
||||
<script type="module" crossorigin src="/assets/index-DqBTDSfz.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-BkgGa32-.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-BS5LP50I.css">
|
||||
</head>
|
||||
|
||||
|
@ -15,7 +15,7 @@ const AllApps: React.FC<{ expanded: boolean }> = ({ expanded }) => {
|
||||
})}>
|
||||
{apps.length === 0
|
||||
? <div>Loading apps...</div>
|
||||
: apps.map(app => <AppDisplay app={app} />)}
|
||||
: apps.map(app => <AppDisplay key={app.package_name} app={app} />)}
|
||||
</div>
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@ import { isMobileCheck } from "../utils/dimensions"
|
||||
import AppIconPlaceholder from "./AppIconPlaceholder"
|
||||
|
||||
interface AppDisplayProps {
|
||||
app: HomepageApp
|
||||
app?: HomepageApp
|
||||
}
|
||||
|
||||
const AppDisplay: React.FC<AppDisplayProps> = ({ app }) => {
|
||||
@ -17,15 +17,15 @@ const AppDisplay: React.FC<AppDisplayProps> = ({ app }) => {
|
||||
|
||||
return <a
|
||||
className={classNames("flex-col-center gap-2 relative hover:opacity-90 transition-opacity", {
|
||||
'cursor-pointer': app.path,
|
||||
'cursor-not-allowed': !app.path,
|
||||
'cursor-pointer': app?.path,
|
||||
'cursor-not-allowed': !app?.path,
|
||||
})}
|
||||
id={app.package_name}
|
||||
href={app.path}
|
||||
id={app?.package_name}
|
||||
href={app?.path}
|
||||
onMouseEnter={() => setIsHovered(true)}
|
||||
onMouseLeave={() => setIsHovered(false)}
|
||||
>
|
||||
{app.base64_icon
|
||||
{app?.base64_icon
|
||||
? <img
|
||||
src={app.base64_icon}
|
||||
className={classNames('rounded', {
|
||||
@ -34,12 +34,12 @@ const AppDisplay: React.FC<AppDisplayProps> = ({ app }) => {
|
||||
})}
|
||||
/>
|
||||
: <AppIconPlaceholder
|
||||
text={app.state?.our_version || '0'}
|
||||
text={app?.state?.our_version || '0'}
|
||||
size={'small'}
|
||||
className="h-16 w-16"
|
||||
/>}
|
||||
<h6>{app.label}</h6>
|
||||
{app.path && isHovered && <button
|
||||
<h6>{app?.label}</h6>
|
||||
{app?.path && isHovered && <button
|
||||
className="absolute p-2 -top-2 -right-2 clear text-sm"
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
|
@ -5,6 +5,7 @@ import { useEffect, useState } from "react"
|
||||
import { isMobileCheck } from "../utils/dimensions"
|
||||
import classNames from "classnames"
|
||||
import { DragDropContext, Draggable, DropResult, Droppable } from 'react-beautiful-dnd'
|
||||
import { getFetchUrl } from "../utils/fetch"
|
||||
|
||||
const AppsDock: React.FC = () => {
|
||||
const { apps } = useHomepageStore()
|
||||
@ -66,11 +67,12 @@ const AppsDock: React.FC = () => {
|
||||
|
||||
console.log({ favoriteApps })
|
||||
|
||||
fetch('/order', {
|
||||
fetch(getFetchUrl('/order'), {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(packageNames)
|
||||
})
|
||||
.then(data => {
|
||||
|
@ -19,6 +19,7 @@ const Widgets = () => {
|
||||
package_name={package_name}
|
||||
widget={widget!}
|
||||
forceLarge={_appsWithWidgets.length === 1}
|
||||
key={package_name}
|
||||
/>)}
|
||||
</div>
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import classNames from 'classnames'
|
||||
import WidgetsSettingsModal from '../components/WidgetsSettingsModal'
|
||||
|
||||
import valetIcon from '../../public/valet-icon.png'
|
||||
import { getFetchUrl } from '../utils/fetch'
|
||||
|
||||
interface AppStoreApp {
|
||||
package: string,
|
||||
@ -28,9 +29,9 @@ function Homepage() {
|
||||
|
||||
const getAppPathsAndIcons = () => {
|
||||
Promise.all([
|
||||
fetch('/apps').then(res => res.json() as any as HomepageApp[]),
|
||||
fetch('/main:app_store:sys/apps').then(res => res.json()),
|
||||
fetch('/version').then(res => res.text())
|
||||
fetch(getFetchUrl('/apps'), { credentials: 'include' }).then(res => res.json() as any as HomepageApp[]).catch(() => []),
|
||||
fetch(getFetchUrl('/main:app_store:sys/apps'), { credentials: 'include' }).then(res => res.json()).catch(() => []),
|
||||
fetch(getFetchUrl('/version'), { credentials: 'include' }).then(res => res.text()).catch(() => '')
|
||||
]).then(([appsData, appStoreData, version]) => {
|
||||
console.log({ appsData, appStoreData, version })
|
||||
|
||||
@ -77,7 +78,7 @@ function Homepage() {
|
||||
}, [our]);
|
||||
|
||||
useEffect(() => {
|
||||
fetch('/our')
|
||||
fetch(getFetchUrl('/our'), { credentials: 'include' })
|
||||
.then(res => res.text())
|
||||
.then(data => {
|
||||
if (data.match(/^[a-zA-Z0-9\-\.]+\.[a-zA-Z]+$/)) {
|
||||
|
12
kinode/packages/homepage/ui/src/utils/fetch.ts
Normal file
12
kinode/packages/homepage/ui/src/utils/fetch.ts
Normal file
@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Prepends or strips '/api/' based on the environment.
|
||||
* @param {string} path The original path.
|
||||
* @return {string} The modified path.
|
||||
*/
|
||||
export function getFetchUrl(path: string) {
|
||||
const isDevelopment = import.meta.env.DEV;
|
||||
if (isDevelopment) {
|
||||
return `/api${path}`;
|
||||
}
|
||||
return path.replace(/^\/api/, '');
|
||||
}
|
12
kinode/packages/homepage/ui/src/vite-env.d.ts
vendored
12
kinode/packages/homepage/ui/src/vite-env.d.ts
vendored
@ -1 +1,13 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
interface ImportMetaEnv {
|
||||
readonly VITE_APP_TITLE: string;
|
||||
readonly REACT_APP_MAINNET_RPC_URL: string;
|
||||
readonly REACT_APP_SEPOLIA_RPC_URL: string;
|
||||
readonly VITE_NODE_URL: string;
|
||||
// Add other environment variables as needed
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv;
|
||||
}
|
@ -8,4 +8,13 @@ export default defineConfig({
|
||||
react()
|
||||
],
|
||||
// ...
|
||||
server: {
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://localhost:8080',
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/api/, '')
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
File diff suppressed because one or more lines are too long
@ -11,7 +11,7 @@
|
||||
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport"
|
||||
content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1.00001, viewport-fit=cover" />
|
||||
<script type="module" crossorigin src="/assets/index-iKMNbHhl.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index--NeI-a3U.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-B00cPdAQ.css">
|
||||
</head>
|
||||
|
||||
|
@ -36,6 +36,7 @@ import KinodeHome from "./pages/KinodeHome"
|
||||
import ResetNode from "./pages/ResetNode";
|
||||
import ImportKeyfile from "./pages/ImportKeyfile";
|
||||
import { UnencryptedIdentity } from "./lib/types";
|
||||
import { getFetchUrl } from "./utils/fetch";
|
||||
|
||||
const {
|
||||
useProvider,
|
||||
@ -117,7 +118,7 @@ function App() {
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
const infoResponse = await fetch('/info', { method: 'GET' })
|
||||
const infoResponse = await fetch(getFetchUrl('/info'), { method: 'GET', credentials: 'include' })
|
||||
|
||||
if (infoResponse.status > 399) {
|
||||
console.log('no info, unbooted')
|
||||
@ -136,7 +137,7 @@ function App() {
|
||||
}
|
||||
|
||||
try {
|
||||
const currentChainResponse = await fetch('/current-chain', { method: 'GET' })
|
||||
const currentChainResponse = await fetch(getFetchUrl('/current-chain'), { method: 'GET', credentials: 'include' })
|
||||
|
||||
if (currentChainResponse.status < 400) {
|
||||
const nodeChainId = await currentChainResponse.json()
|
||||
|
@ -9,6 +9,7 @@ import { ipToNumber } from "../utils/ipToNumber";
|
||||
import DirectCheckbox from "../components/DirectCheckbox";
|
||||
import { KinodeTitle } from "../components/KinodeTitle";
|
||||
import { Tooltip } from "../components/Tooltip";
|
||||
import { getFetchUrl } from "../utils/fetch";
|
||||
|
||||
const { useAccounts, useProvider } = hooks;
|
||||
|
||||
@ -51,7 +52,7 @@ function ClaimOsInvite({
|
||||
if (invite !== "") {
|
||||
const url = process.env.REACT_APP_INVITE_GET + invite;
|
||||
|
||||
const response = await fetch(url, { method: "GET" });
|
||||
const response = await fetch(getFetchUrl(url), { method: "GET", credentials: 'include' });
|
||||
|
||||
if (response!.status === 200) {
|
||||
setInviteValidity("");
|
||||
@ -80,7 +81,7 @@ function ClaimOsInvite({
|
||||
routers
|
||||
}
|
||||
}
|
||||
} = (await fetch("/generate-networking-info", { method: "POST" }).then(
|
||||
} = (await fetch(getFetchUrl("/generate-networking-info"), { method: "POST", credentials: 'include' }).then(
|
||||
(res) => res.json()
|
||||
)) as NetworkingInfo;
|
||||
|
||||
@ -106,9 +107,10 @@ function ClaimOsInvite({
|
||||
console.log("BUILDING", networking_key, ipAddress, ws_port, tcp_port, routers);
|
||||
|
||||
try {
|
||||
response = await fetch(process.env.REACT_APP_BUILD_USER_OP_POST!, {
|
||||
response = await fetch(getFetchUrl(process.env.REACT_APP_BUILD_USER_OP_POST!), {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify({
|
||||
name: name + ".os",
|
||||
address: accounts![0],
|
||||
@ -143,9 +145,10 @@ function ClaimOsInvite({
|
||||
data.userOperation.signature = signature;
|
||||
|
||||
try {
|
||||
response = await fetch(process.env.REACT_APP_BROADCAST_USER_OP_POST!, {
|
||||
response = await fetch(getFetchUrl(process.env.REACT_APP_BROADCAST_USER_OP_POST!), {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify({
|
||||
userOp: data.userOperation,
|
||||
code: invite,
|
||||
|
@ -9,6 +9,7 @@ import { utils } from "ethers";
|
||||
import KinodeHeader from "../components/KnsHeader";
|
||||
import { PageProps } from "../lib/types";
|
||||
import Loader from "../components/Loader";
|
||||
import { getFetchUrl } from "../utils/fetch";
|
||||
|
||||
interface ImportKeyfileProps extends PageProps { }
|
||||
|
||||
@ -36,8 +37,9 @@ function ImportKeyfile({
|
||||
|
||||
// const handlePassword = useCallback(async () => {
|
||||
// try {
|
||||
// const response = await fetch("/vet-keyfile", {
|
||||
// const response = await fetch(getFetchUrl("/vet-keyfile"), {
|
||||
// method: "POST",
|
||||
// credentials: 'include',
|
||||
// headers: { "Content-Type": "application/json" },
|
||||
// body: JSON.stringify({
|
||||
// keyfile: localKey,
|
||||
@ -127,8 +129,9 @@ function ImportKeyfile({
|
||||
if (keyErrs.length === 0 && localKey !== "") {
|
||||
let hashed_password = utils.sha256(utils.toUtf8Bytes(pw));
|
||||
|
||||
const response = await fetch("/vet-keyfile", {
|
||||
const response = await fetch(getFetchUrl("/vet-keyfile"), {
|
||||
method: "POST",
|
||||
credentials: 'include',
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
keyfile: localKey,
|
||||
@ -140,8 +143,9 @@ function ImportKeyfile({
|
||||
throw new Error("Incorrect password");
|
||||
}
|
||||
|
||||
const result = await fetch("/import-keyfile", {
|
||||
const result = await fetch(getFetchUrl("/import-keyfile"), {
|
||||
method: "POST",
|
||||
credentials: 'include',
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
keyfile: localKey,
|
||||
@ -154,7 +158,7 @@ function ImportKeyfile({
|
||||
}
|
||||
|
||||
const interval = setInterval(async () => {
|
||||
const res = await fetch("/");
|
||||
const res = await fetch(getFetchUrl("/"), { credentials: 'include' });
|
||||
if (
|
||||
res.status < 300 &&
|
||||
Number(res.headers.get("content-length")) !== appSizeOnLoad
|
||||
|
@ -13,6 +13,7 @@ import { KinodeTitle } from "../components/KinodeTitle";
|
||||
import { isMobileCheck } from "../utils/dimensions";
|
||||
import classNames from "classnames";
|
||||
import { generateNetworkingKeys, getNetworkName } from "../utils/chain";
|
||||
import { getFetchUrl } from "../utils/fetch";
|
||||
|
||||
const { useProvider } = hooks;
|
||||
|
||||
@ -51,7 +52,7 @@ function Login({
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
const infoData = (await fetch("/info", { method: "GET" }).then((res) =>
|
||||
const infoData = (await fetch(getFetchUrl("/info"), { method: "GET", credentials: 'include' }).then((res) =>
|
||||
res.json()
|
||||
)) as UnencryptedIdentity;
|
||||
setRouters(infoData.allowed_routers);
|
||||
@ -81,8 +82,9 @@ function Login({
|
||||
let hashed_password = utils.sha256(utils.toUtf8Bytes(pw));
|
||||
|
||||
// Replace this with network key generation
|
||||
const response = await fetch("/vet-keyfile", {
|
||||
const response = await fetch(getFetchUrl("/vet-keyfile"), {
|
||||
method: "POST",
|
||||
credentials: 'include',
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ password_hash: hashed_password, keyfile: "" }),
|
||||
});
|
||||
@ -119,9 +121,10 @@ function Login({
|
||||
|
||||
// Login or confirm new keys
|
||||
const result = await fetch(
|
||||
reset ? "confirm-change-network-keys" : "login",
|
||||
getFetchUrl(reset ? "confirm-change-network-keys" : "login"),
|
||||
{
|
||||
method: "POST",
|
||||
credentials: 'include',
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: reset
|
||||
? JSON.stringify({ password_hash: hashed_password, direct })
|
||||
@ -139,7 +142,7 @@ function Login({
|
||||
}
|
||||
|
||||
const interval = setInterval(async () => {
|
||||
const res = await fetch("/");
|
||||
const res = await fetch(getFetchUrl("/"), { credentials: 'include' });
|
||||
if (
|
||||
res.status < 300 &&
|
||||
Number(res.headers.get("content-length")) !== appSizeOnLoad
|
||||
|
@ -5,6 +5,7 @@ import { utils, providers } from "ethers";
|
||||
import { downloadKeyfile } from "../utils/download-keyfile";
|
||||
import { Tooltip } from "../components/Tooltip";
|
||||
import { KinodeTitle } from "../components/KinodeTitle";
|
||||
import { getFetchUrl } from "../utils/fetch";
|
||||
|
||||
type SetPasswordProps = {
|
||||
direct: boolean;
|
||||
@ -70,7 +71,7 @@ function SetPassword({
|
||||
let signature = await signer?.signMessage(utils.toUtf8Bytes(sig_data));
|
||||
|
||||
try {
|
||||
const result = await fetch("/boot", {
|
||||
const result = await fetch(getFetchUrl("/boot"), {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
credentials: "include",
|
||||
@ -90,7 +91,7 @@ function SetPassword({
|
||||
downloadKeyfile(knsName, base64String);
|
||||
|
||||
const interval = setInterval(async () => {
|
||||
const res = await fetch("/");
|
||||
const res = await fetch(getFetchUrl("/"), { credentials: 'include' });
|
||||
|
||||
if (
|
||||
res.status < 300 &&
|
||||
|
12
kinode/src/register-ui/src/utils/fetch.ts
Normal file
12
kinode/src/register-ui/src/utils/fetch.ts
Normal file
@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Prepends or strips '/api/' based on the environment.
|
||||
* @param {string} path The original path.
|
||||
* @return {string} The modified path.
|
||||
*/
|
||||
export function getFetchUrl(path: string) {
|
||||
const isDevelopment = import.meta.env.DEV;
|
||||
if (isDevelopment) {
|
||||
return `/api${path}`;
|
||||
}
|
||||
return path.replace(/^\/api/, '');
|
||||
}
|
@ -44,29 +44,10 @@ export default defineConfig({
|
||||
// ...
|
||||
server: {
|
||||
proxy: {
|
||||
'/generate-networking-info': {
|
||||
target: 'http://localhost:8080/generate-networking-info',
|
||||
changeOrigin: true,
|
||||
},
|
||||
'/vet-keyfile': {
|
||||
target: 'http://localhost:8080/vet-keyfile',
|
||||
changeOrigin: true,
|
||||
},
|
||||
'/import-keyfile': {
|
||||
target: 'http://localhost:8080/import-keyfile',
|
||||
changeOrigin: true,
|
||||
},
|
||||
'/info': {
|
||||
target: 'http://localhost:8080/info',
|
||||
changeOrigin: true,
|
||||
},
|
||||
'/current-chain': {
|
||||
target: 'http://localhost:8080/current-chain',
|
||||
changeOrigin: true,
|
||||
},
|
||||
'/boot': {
|
||||
target: 'http://localhost:8080/boot',
|
||||
'/api': {
|
||||
target: 'http://localhost:8080',
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/api/, '')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user