Skip to content

Commit

Permalink
(#85) VSCode Extension - Help when suibase not on path + misc UI changes
Browse files Browse the repository at this point in the history
  • Loading branch information
mario4tier committed May 24, 2024
1 parent db2b8cf commit f9b6df2
Show file tree
Hide file tree
Showing 9 changed files with 386 additions and 325 deletions.
12 changes: 6 additions & 6 deletions rust/demo-app/move/Move.lock
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ dependencies = [
]

[move.toolchain-version]
compiler-version = "1.25.1"
compiler-version = "1.26.0"
edition = "2024.beta"
flavor = "sui"

Expand All @@ -42,13 +42,13 @@ flavor = "sui"
test = 12

[env.localnet_proxy]
chain-id = "c47310d1"
original-published-id = "0x88783e9285603ec50560a4db581a728f4329c12e765fdefeebb3cc9a7db771f4"
latest-published-id = "0x88783e9285603ec50560a4db581a728f4329c12e765fdefeebb3cc9a7db771f4"
chain-id = "a93d8416"
original-published-id = "0x53402fa9fbe721fb56864ad3cf77d6508677d3d40dc5797b8b16883186afd02c"
latest-published-id = "0x53402fa9fbe721fb56864ad3cf77d6508677d3d40dc5797b8b16883186afd02c"
published-version = "1"

[env.testnet_proxy]
chain-id = "4c78adac"
original-published-id = "0x47a6d73defe78b2c2500fd25c01dd520aec45bb7fae178b92ffd39036f1d31b1"
latest-published-id = "0x47a6d73defe78b2c2500fd25c01dd520aec45bb7fae178b92ffd39036f1d31b1"
original-published-id = "0x915398a0991635914fbe730133da9015618976fe546db7c69cb94251c9ae6719"
latest-published-id = "0x915398a0991635914fbe730133da9015618976fe546db7c69cb94251c9ae6719"
published-version = "1"
7 changes: 5 additions & 2 deletions typescript/vscode-extension/src/BackendSync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
API_URL,
SETUP_ISSUE_GIT_NOT_INSTALLED,
SETUP_ISSUE_SUIBASE_NOT_INSTALLED,
SETUP_ISSUE_SUIBASE_NOT_ON_PATH,
WEBVIEW_BACKEND,
WORKDIRS_KEYS,
WORKDIR_IDX_TESTNET,
Expand Down Expand Up @@ -247,10 +248,12 @@ export class BackendSync {
const sb = SuibaseExec.getInstance();
if (sb === undefined) {
msg.setSetupIssue("Internal error. Shell commands failed.");
} else if ((await sb.isSuibaseInstalled()) === false) {
msg.setSetupIssue(SETUP_ISSUE_SUIBASE_NOT_INSTALLED);
} else if ((await sb.isGitInstalled()) === false) {
msg.setSetupIssue(SETUP_ISSUE_GIT_NOT_INSTALLED);
} else if ((await sb.isSuibaseInstalled()) === false) {
msg.setSetupIssue(SETUP_ISSUE_SUIBASE_NOT_INSTALLED);
} else if ((await sb.isSuibaseOnPath()) === false) {
msg.setSetupIssue(SETUP_ISSUE_SUIBASE_NOT_ON_PATH + ",homedir=" + SuibaseExec.getHomedir());
} else if ((await sb.isSuibaseBackendRunning()) === false) {
// Start the backend daemon if safe to do...
if ((await sb.isSuibaseBackendUpgrading()) === true) {
Expand Down
40 changes: 30 additions & 10 deletions typescript/vscode-extension/src/SuibaseExec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import * as vscode from "vscode";
import * as cp from "child_process";
//import WebSocket from "ws";
import * as OS from "os";

const execShell = (cmd: string) =>
new Promise<string>((resolve, reject) => {
Expand All @@ -37,12 +38,15 @@ const execShellBackground = (cmd: string) =>
export class SuibaseExec {
private static instance?: SuibaseExec;
private static context?: vscode.ExtensionContext;
private static homedir: string;
//private ws: WebSocket | undefined;

// Define a cache to store the response
//private cache: any = {};

private constructor() {
SuibaseExec.homedir = OS.homedir();

// Should be called only by SuibaseExec.activate()
/*
this.ws = new WebSocket("ws://localhost:44399");
Expand Down Expand Up @@ -106,6 +110,10 @@ export class SuibaseExec {
return SuibaseExec.instance;
}

public static getHomedir(): string {
return SuibaseExec.homedir;
}

public async isRustInstalled(): Promise<boolean> {
// Returns true if the rust compiler can be call.
// Returns false on any error.
Expand Down Expand Up @@ -134,30 +142,47 @@ export class SuibaseExec {
return false;
}

/*
public async fileExists(pathname: string): Promise<boolean> {
// Returns true if the file exists on the filesystem.
// Returns false on any error.
//
// This function must always resolve its promise.
pathname = pathname.replace("~", SuibaseExec.homedir);
try {
let result = await execShell(`ls ${pathname}`);
result = result.toLowerCase();
if (!result.includes(pathname) || result.includes("cannot access") || result.includes("no such")) {
if (
!result.includes(pathname) ||
result.includes("cannot access") ||
result.includes("no such") ||
result.includes("not found")
) {
console.error(`File ${pathname} not found`);
return false;
}
} catch (error) {
return false;
}
return true;
}*/
}

public async isSuibaseInstalled(): Promise<boolean> {
// Verify if Suibase itself is installed.
//
// Good enough to just check that the script to start the backend daemon exists.
try {
return await this.fileExists("~/suibase/scripts/common/run-daemon.sh");
} catch (error) {
return false;
}
}

public async isSuibaseOnPath(): Promise<boolean> {
// Verify if Suibase itself is accessible.
//
// Verifies that executing "localnet suibase-script-name" returns the exact string "localnet".
//
// This is the same verification trick used by "~/suibase/install"
// This is similar to the verification trick used by "~/suibase/install"
try {
const result = await execShell("localnet suibase-script-name");
if (!result || result.trim() !== "localnet") {
Expand Down Expand Up @@ -199,16 +224,11 @@ export class SuibaseExec {
//
// This function must always resolve its promise.
try {
let result = await execShell("ls /tmp/.suibase/suibase-daemon-upgrading");
result = result.toLowerCase();
if (result.includes("cannot") || result.includes("no such")) {
return false;
}
return await this.fileExists("/tmp/.suibase/suibase-daemon-upgrading")
} catch (error) {
return false;
}

return true;
}

public async version(): Promise<string> {
Expand Down
1 change: 1 addition & 0 deletions typescript/vscode-extension/src/common/Consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,5 @@ export const TREE_ID_INSERT_ADDR = "[TREE_ID_INSERT_ADDR]";

// setupIssue strings. Used in messages between extension and webviews
export const SETUP_ISSUE_SUIBASE_NOT_INSTALLED = "Suibase not installed";
export const SETUP_ISSUE_SUIBASE_NOT_ON_PATH = "Suibase scripts not on $PATH";
export const SETUP_ISSUE_GIT_NOT_INSTALLED = "Git not installed";
568 changes: 284 additions & 284 deletions typescript/vscode-extension/webview-ui/build/assets/index.js

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
import React from 'react';
import { Box, ClickAwayListener, useTheme} from '@mui/material';
import Fade from '@mui/material/Fade';
import ContentCopyOutlinedIcon from '@mui/icons-material/ContentCopyOutlined';

interface CopyToClipboardButtonProps {
text: string;
Expand Down Expand Up @@ -36,7 +37,7 @@ const CopyToClipboardButton = ({text,message}: CopyToClipboardButtonProps) => {

return (
<>
<div className="icon" onClick={handleClick}><i className="codicon codicon-clippy"></i></div>
<Box className="icon" onClick={handleClick}><ContentCopyOutlinedIcon sx={{ fontSize: '14px'}}/></Box>
<BasePopup
id="placement-popper"
open={open}
Expand All @@ -45,7 +46,7 @@ const CopyToClipboardButton = ({text,message}: CopyToClipboardButtonProps) => {
offset={4}
>
<ClickAwayListener onClickAway={handleClickAway}>
<Fade in={open} timeout={1000}>
<Fade in={open} timeout={500}>
<Box role="presentation" sx={{ padding: '2px',
color: theme.palette.secondary.contrastText,
backgroundColor: theme.palette.secondary.main,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ export const ExplorerController = () => {
<>
{common.current.setupIssue && <SetupIssue issue={common.current.setupIssue}/>}

{allDisabled && renderAllDisabledHelp()}
{!common.current.setupIssue && allDisabled && renderAllDisabledHelp()}

{renderControls && renderDropdown()}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ const CustomTreeItem = React.forwardRef(function CustomTreeItem(
const { workdir, id, itemId, disabled, children, ...other } = props;
let { label } = props;

let [isHoveredItem, setIsHoveredItem] = React.useState(false);

// set is_top_folder to true if first character of itemId is a numeric.
// See Consts.ts for the meaning of the first char ( TREE_ITEM_x ).
let is_top_folder = false;
Expand Down Expand Up @@ -117,36 +119,51 @@ const CustomTreeItem = React.forwardRef(function CustomTreeItem(
labelStyle.fontFamily = 'monospace';
}

const renderItemIcons = () => {
return (
<>
{to_clipboard && (
<Box width={20}>
<CopyToClipboardButton text={to_clipboard} message="Copied!" />
</Box>
)}
</>
);
}

const renderItem = () => {
return(
<Box display="flex" overflow="hidden"
justifyContent="space-between" width="100%"
onMouseEnter={()=> setIsHoveredItem(true)}
onMouseLeave={()=> setIsHoveredItem(false)}>

<Box flexGrow={1} overflow="hidden" >
<div style={{ overflow: 'hidden', textOverflow: 'ellipsis' }}>
<span style={labelStyle} {...getLabelProps()} >
{labelInnerStyling(label)}
</span>
</div>
{/* <TreeItem2Label sx={labelSx} {...getLabelProps()} />*/}
</Box>
{isHoveredItem && renderItemIcons()}
</Box>
);
}

return (
<TreeItem2Provider itemId={itemId}>
<TreeItem2Root {...getRootProps(other)}>
<CustomTreeItemContent {...getContentProps()}>
<TreeItem2IconContainer {...getIconContainerProps()}>
<TreeItem2Icon status={status} />
</TreeItem2IconContainer>

{is_empty_folder ? (
<Typography variant="caption" sx={labelStyle} {...getLabelProps()}>
{empty_folder_label}
</Typography>
) : (
<Box display="flex" overflow="hidden" justifyContent="space-between" width="100%">
<Box flexGrow={1} overflow="hidden" >
<div style={{ overflow: 'hidden', textOverflow: 'ellipsis' }}>
<span style={labelStyle} {...getLabelProps()} >
{labelInnerStyling(label)}
</span>
</div>
{/* <TreeItem2Label sx={labelSx} {...getLabelProps()} />*/}
</Box>
{to_clipboard && (
<Box width={20}>
<CopyToClipboardButton text={to_clipboard} message="Copied!" />
</Box>
)}
</Box>
)}

) : (renderItem())
}
</CustomTreeItemContent>
{children && <TreeItem2GroupTransition {...getGroupTransitionProps()} />}
</TreeItem2Root>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,20 @@
// a user friendly message with links.
import { Link, Typography } from "@mui/material";
import { SETUP_ISSUE_GIT_NOT_INSTALLED, SETUP_ISSUE_SUIBASE_NOT_INSTALLED } from "../../../src/common/Consts";
import { SETUP_ISSUE_SUIBASE_NOT_ON_PATH } from "../common/Consts";

// with a link to "Check https://suibase.io/how-to/install" on next line.
export default function SetupIssue(props: {issue: string}) {
const issue = props.issue;
let issue = props.issue;

// Extract from the issue string an appended ",homedir=<path>" if any.
let homedir = "";
const match = issue.match(/,homedir=(.*)/);
if (match) {
homedir = match[1];
issue = issue.replace(/,homedir=(.*)/, "");
}

if (issue == SETUP_ISSUE_SUIBASE_NOT_INSTALLED) {
return (
<Typography variant="body2">
Expand All @@ -21,7 +31,16 @@ export default function SetupIssue(props: {issue: string}) {
Check <Link href="https://docs.sui.io/guides/developer/getting-started/sui-install">https://docs.sui.io</Link>
</Typography>
);
} else if (issue == SETUP_ISSUE_SUIBASE_NOT_ON_PATH) {
return (
<Typography variant="body2">
{SETUP_ISSUE_SUIBASE_NOT_ON_PATH}<br/>
Initialize your shell to have {homedir}/.local/bin added to the $PATH.<br/>
Check <Link href="https://suibase.io/how-to/install">https://suibase.io/how-to/install</Link>
</Typography>
);
}

return (
<Typography variant="body2">{issue}</Typography>
);
Expand Down

0 comments on commit f9b6df2

Please sign in to comment.