Skip to content

Commit

Permalink
Gui tweaks (#39)
Browse files Browse the repository at this point in the history
* WIP

* WIP

* Update runInCloud.ts, testsBrowserComponent.tsx, and main.css

* Update package.json

* Update README.md
  • Loading branch information
RamiBerm authored Jan 30, 2022
1 parent 0608932 commit 09af940
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 75 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ You can find the UP9 Extension in the Visual Studio Code Marketplace. To install

## Quick Start

* Press `Command-Shift-P` to access VS Code command launcher and select **UP9: Open Code Browser** from the list. This will open a right-pane window offering you to sign in to your UP9 account:
* Press `Command-Shift-P` to access VS Code command launcher and select **UP9: Code Browser** from the list. This will open a right-pane window offering you to sign in to your UP9 account:

![The right-pane upon opening the code browser](images/image1.png)

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"commands": [
{
"command": "up9.openTestsBrowser",
"title": "UP9: Open Code Browser"
"title": "UP9: Code Browser"
},
{
"command": "up9.runTest",
Expand Down
2 changes: 1 addition & 1 deletion src/commands/runInCloud.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export class CloudRunner {
}

//TODO: reuse the same terminal (will require having only 1 simultaneous test run)
const terminalOutputter = this.createAndShowTerminal("Running test through UP9...\n\r", promise);
const terminalOutputter = this.createAndShowTerminal(`Running Code in UP9 - ${this._up9Auth.getEnv()} on workspace ${defaultWorkspace}\n\r(in order to change env/workspace, please change configuration in the UP9:Code browser)\n\r`, promise);

// terminal takes a second to properly initialize, calls to print before its ready will result in nothing being printed
await delay(1000);
Expand Down
147 changes: 88 additions & 59 deletions src/webview/src/components/testsBrowserComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,26 @@ import $ from "jquery";

const TestsBrowserComponent: React.FC<{}> = observer(() => {
const [workspaces, setWorkspaces] = useState(null);
const [workspaceFilterInput, setWorkspaceFilterInput] = useState("");
const [workspaceOAS, setWorkspaceOAS] = useState(null);

const [services, setServices] = useState(null);
const [selectedService, setSelectedService] = useState(null);

const [endpoints, setEndpoints] = useState(null);
const [endpointFilterInput, setEndpointFilterInput] = useState("");
const [selectedEndpoint, setSelectedEndpoint] = useState(null);
const [workspaceSpans, setWorkspaceSpans] = useState(null);

const [lastSelectedWorkspace, setLastSelectedWorkspace] = useState("");

const [isLoading, setIsLoading] = useState(true);

const serviceEndpoints = useMemo(() => {
if (!selectedService || !endpoints) {
return [];
}
return endpoints.filter(endpoint => endpoint.service === selectedService);
}, [selectedService, endpoints]);

useEffect(() => {
if (up9AuthStore.defaultWorkspace) {
setLastSelectedWorkspace(up9AuthStore.defaultWorkspace);
Expand All @@ -37,23 +45,9 @@ const TestsBrowserComponent: React.FC<{}> = observer(() => {
}

const getEndpointDisplayText = (endpoint) => {
return `${endpoint.method.toUpperCase()} ${endpoint.service}${endpoint.path}`;
return `${endpoint.method.toUpperCase()} ${endpoint.path}`;
}

const filteredEndpoints = useMemo(() => {
if (!endpoints || !endpointFilterInput) {
return endpoints;
}
return endpoints.filter(endpoint => getEndpointDisplayText(endpoint).toLocaleLowerCase().indexOf(endpointFilterInput.toLowerCase()) > -1);
}, [endpoints, endpointFilterInput]);

const filteredWorkspaces = useMemo(() => {
if (!workspaces || !workspaceFilterInput) {
return workspaces;
}
return workspaces.filter(workspace => workspace.toLocaleLowerCase().indexOf(workspaceFilterInput.toLowerCase()) > -1);
}, [workspaces, workspaceFilterInput]);

useEffect(() => {
if (workspaces && !up9AuthStore.defaultWorkspace) {
setDefaultWorkspace(workspaces?.[0]);
Expand All @@ -62,7 +56,6 @@ const TestsBrowserComponent: React.FC<{}> = observer(() => {

const refreshWorkspaces = async () => {
setIsLoading(true);
setWorkspaceFilterInput("");
try {
const workspaces = await sendApiMessage(ApiMessageType.WorkspacesList, null);
setWorkspaces(workspaces);
Expand All @@ -75,15 +68,17 @@ const TestsBrowserComponent: React.FC<{}> = observer(() => {

useEffect(() => {
(async () => {
setSelectedService("");
setSelectedEndpoint(null);
setEndpointFilterInput("");
setEndpoints(null);
setWorkspaceOAS(null);

if (up9AuthStore.defaultWorkspace) {
try {
const endpoints = await sendApiMessage(ApiMessageType.EndpointsList, {workspaceId: up9AuthStore.defaultWorkspace});
setEndpoints(endpoints);

setServices(Array.from(new Set(endpoints.map(endpoint => endpoint.service))));
} catch (error) {
console.error('error loading workspace endpoints', error);
}
Expand Down Expand Up @@ -112,25 +107,19 @@ const TestsBrowserComponent: React.FC<{}> = observer(() => {
}, [up9AuthStore.isAuthConfigured, up9AuthStore.up9Env]);

const onWorkspaceDropdownToggle = (isOpen: boolean) => {
setIsWorkspaceDropDownOpen(isOpen);
if (!isOpen && !up9AuthStore.defaultWorkspace && lastSelectedWorkspace) {
// prevent user from reaching state where nothing is selected
setDefaultWorkspace(lastSelectedWorkspace);
}
}

// TODO: refactor this
// ugly workaround for having the dropdowns apply focus to the filter form repeatedly
const [isWorkspaceDropDownOpen, setIsWorkspaceDropDownOpen] = useState(false);
const [isEndpointsDropdownOpen, setIsEndpointsDropdownOpen] = useState(false);

if (isLoading) {
return <LoadingOverlay />;
}

return <>
<div className="user-info">
<div style={{padding: "5px 0"}}>
<div style={{padding: "5px 0"}} className="user-icon">
{logoIcon}
</div>
<span className="env-text">
Expand All @@ -150,43 +139,83 @@ const TestsBrowserComponent: React.FC<{}> = observer(() => {
</div>
</div>
<hr style={{margin: "0"}}/>
<div className="select-test-form">
<Form.Group className="workspaces-form-group">
<Form.Label>Workspace</Form.Label>
<br/>
<Dropdown className="select-dropdown" onToggle={(isOpen, _) => onWorkspaceDropdownToggle(isOpen)}>
<Dropdown.Toggle>{up9AuthStore.defaultWorkspace ? up9AuthStore.defaultWorkspace : "Select a workspace"}</Dropdown.Toggle>
{isWorkspaceDropDownOpen && <Dropdown.Menu>
{isWorkspaceDropDownOpen && <FormControl className="dropdown-filter" autoFocus placeholder="Type to filter..." value={workspaceFilterInput} onChange={e => setWorkspaceFilterInput(e.target.value)} />}
<Dropdown.Divider/>
{filteredWorkspaces?.map((workspace) => {return <Dropdown.Item key={workspace} onClick={_ => {setWorkspaceFilterInput(""); setDefaultWorkspace(workspace ?? lastSelectedWorkspace)}}>{workspace}</Dropdown.Item>})}
</Dropdown.Menu>}
</Dropdown>
</Form.Group>

<Form.Group className="endpoints-form-group">
<Form.Label>Endpoint</Form.Label>
<br/>
<Dropdown className="select-dropdown" onToggle={(isOpen, _) => {
setIsEndpointsDropdownOpen(isOpen)
if (isOpen) {
$('.select-dropdown .dropdown-menu').hide().show(0); //this is a very strange workaround for a very strange html bug, without this the drop down sometimes shifts the entire page until anything changes in the dom
}
}}>
<Dropdown.Toggle disabled={!up9AuthStore.defaultWorkspace}>
{selectedEndpoint ? getEndpointDisplayText(selectedEndpoint) : "Select an endpoint"}
</Dropdown.Toggle>
{isEndpointsDropdownOpen && <Dropdown.Menu>
{isEndpointsDropdownOpen && <FormControl className="dropdown-filter" autoFocus placeholder="Type to filter..." value={endpointFilterInput} onChange={e => setEndpointFilterInput(e.target.value)} />}
<Dropdown.Divider/>
{filteredEndpoints?.map((endpoint) => {return <Dropdown.Item title={getEndpointDisplayText(endpoint)} key={endpoint.uuid} onClick={_ => {setEndpointFilterInput(""); setSelectedEndpoint(endpoint)}}>{getEndpointDisplayText(endpoint)}</Dropdown.Item>})}
</Dropdown.Menu>}
</Dropdown>
</Form.Group>
<div className="select-test-form">
<div style={{display: "flex"}}>
<TestBrowserParameterDropdown className="dropdown-container workspaces-form-group" label="Workspace" placeholder="Select workspace"
items={workspaces?.map((workspace) => ({key: workspace, value: workspace, label: workspace}))}
onDropdownToggle={onWorkspaceDropdownToggle} onSelect={setDefaultWorkspace} value={up9AuthStore.defaultWorkspace} />
</div>
<div className="endpoints-services-container">
<TestBrowserParameterDropdown className="dropdown-container services-form-group" label="Service" placeholder="Select service"
items={services?.map((service) => ({key: service, value: service, label: service}))}
disabled={!up9AuthStore.defaultWorkspace || services?.length < 1} onSelect={setSelectedService} value={selectedService} />

<TestBrowserParameterDropdown className="dropdown-container endpoints-form-group" label="Endpoint" placeholder="Select endpoint"
items={serviceEndpoints?.map((endpoint) => {return {key: endpoint.uuid, value: endpoint, label: getEndpointDisplayText(endpoint)}})}
disabled={!selectedService} onSelect={setSelectedEndpoint} value={selectedEndpoint} />
</div>

</div>
<hr/>
<TestCodeViewer workspace={up9AuthStore.defaultWorkspace} endpoint={selectedEndpoint} spans={workspaceSpans} workspaceOAS={workspaceOAS} />
</>;
});

interface TestBrowserParameterDropdownProps {
label: string;
className: string;
placeholder: string;
disabled?: boolean;
items: {label: string, value: any, key: any}[];
value: any;
onSelect: (value: any) => void;
onDropdownToggle?: (isOpen: boolean) => void;
}

const TestBrowserParameterDropdown: React.FC<TestBrowserParameterDropdownProps> = ({label, className, placeholder, disabled, items, value, onSelect, onDropdownToggle}) => {
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const [filterInputValue, setFilterInputValue] = useState("");

const selectedItem = useMemo(() => {
if (value) {
return items.find(item => item.value === value);
} else {
return null;
}
}, [value, items]);

const filteredItems = useMemo(() => {
if (!items || !filterInputValue) {
return items;
}
return items.filter(item => item.label.toLocaleLowerCase().indexOf(filterInputValue.toLowerCase()) > -1);
}, [items, filterInputValue]);

const onDropdownToggled = (isOpen: boolean) => {
if (onDropdownToggle) {
onDropdownToggle(isOpen);
}
setIsDropdownOpen(isOpen);
}

return <Form.Group className={className}>
<Form.Label>{label}</Form.Label>
<Dropdown className="select-dropdown" onToggle={(isOpen, _) => {
onDropdownToggled(isOpen)
if (isOpen) {
$('.select-dropdown .dropdown-menu').hide().show(0); //this is a very strange workaround for a very strange html bug, without this the drop down sometimes shifts the entire page until anything changes in the dom
}
}}>
<Dropdown.Toggle disabled={disabled}>
{selectedItem ? selectedItem.label : placeholder}
</Dropdown.Toggle>
{isDropdownOpen && <Dropdown.Menu>
{isDropdownOpen && <FormControl className="dropdown-filter" autoFocus placeholder="Type to filter..." value={filterInputValue} onChange={e => setFilterInputValue(e.target.value)} />}
<Dropdown.Divider/>
{filteredItems.map((item) => <Dropdown.Item title={item.label} key={item.key} onClick={_ => {setFilterInputValue(""); onSelect(item.value)}}>{item.label}</Dropdown.Item>)}
</Dropdown.Menu>}
</Dropdown>
</Form.Group>
};

export default TestsBrowserComponent;
58 changes: 45 additions & 13 deletions src/webview/src/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,12 @@ table {
}

.select-test-form {
height: 5%;
height: 105px;
min-height: 65px;

margin: 15px 20px 24px;
display: flex;
justify-content: space-around;
/* display: flex;
justify-content: space-around; */
gap: 10px;
}

Expand Down Expand Up @@ -144,7 +144,7 @@ table {
.anchor-button {
color: var(--vscode-textLink-foreground);
text-decoration: none;
font-size: 0.9em;
font-size: 0.5em;
}

.anchor-button:active, .anchor-button:hover, .anchor-button:focus {
Expand Down Expand Up @@ -208,9 +208,15 @@ hr {
opacity: 0.75;
}

.workspaces-form-group .form-label, .endpoints-form-group .form-label {
.workspaces-form-group .form-label, .endpoints-form-group .form-label, .services-form-group .form-label {
font-size: 0.9em;
opacity: 0.8
opacity: 0.8;
margin-bottom: 0;
margin-right: 0.9em;
}

.services-form-group .form-label {
margin-right: 38px;
}

.select-dropdown {
Expand All @@ -231,7 +237,7 @@ hr {
text-align: left;
padding-right: 8px;
outline: none !important;
border: none !important;
border: 1px solid var(--vscode-dropdown-border) !important;
}

.show>.btn-primary.dropdown-toggle {
Expand Down Expand Up @@ -259,17 +265,43 @@ hr {
color: var(--vscode-button-foreground);
}

.dropdown-container {
display: flex;
align-items: center;
}

.workspaces-form-group {
flex-grow: 1;
flex-shrink: 1;
flex-basis: 33%;
margin-bottom: 12px;
flex-grow: 2;
flex-shrink: 2;
}

.services-form-group {
margin-bottom: 12px;
flex-grow: 2;
flex-shrink: 0;
min-width: 0;
}

.endpoints-form-group {
flex-grow: 2;
flex-shrink: 2;
flex-basis: 66%;
max-width: 50%;
min-width: 0;
}

.endpoints-form-group .form-label {
margin-right: 25px;
}

.endpoints-form-group, .services-form-group, .workspaces-form-group {
flex-basis: 100%;
max-width: 100%;
margin-right: 0;
}

.endpoints-services-container {
display: flex;
flex-wrap: wrap;
}

.select-dropdown > button {
Expand Down Expand Up @@ -335,7 +367,7 @@ hr {
}

@media screen and (max-width: 400px) {
.auth-icon-container {
.auth-icon-container, .user-icon {
display: none !important;
}
}
Expand Down

0 comments on commit 09af940

Please sign in to comment.