Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[dashboard] improved workspaces #3457

Merged
merged 1 commit into from
Mar 17, 2021
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
3 changes: 2 additions & 1 deletion components/dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"private": true,
"dependencies": {
"@gitpod/gitpod-protocol": "0.1.5",
"moment": "^2.29.1",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moment.js is a legacy project, now in maintenance mode. In most cases, you should choose a different library.

nit: it would be great to find an alternative to format relative time. this is quite a balloon in the resulting bundle.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if it's used just to format relative time, maybe it's good to use https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat, and there is a polyfill available, too.

"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-router-dom": "^5.2.0"
Expand All @@ -20,8 +21,8 @@
"@types/node": "^12.0.0",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"@types/react-router-dom": "^5.1.7",
"@types/react-router": "^5.1.12",
"@types/react-router-dom": "^5.1.7",
"@typescript-eslint/eslint-plugin": "^4.15.2",
"@typescript-eslint/parser": "^4.15.2",
"autoprefixer": "^9.8.6",
Expand Down
69 changes: 69 additions & 0 deletions components/dashboard/src/components/ContextMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { useState } from 'react';

export interface ContextMenuProps {
children: React.ReactChild[] | React.ReactChild;
menuEntries: ContextMenuEntry[];
}

export interface ContextMenuEntry {
title: string;
active?: boolean;
/**
* whether a separator line should be rendered below this item
*/
separator?: boolean;
customFontStyle?: string;
onClick?: ()=>void;
href?: string;
}

function ContextMenu(props: ContextMenuProps) {
const [expanded, setExpanded] = useState(false);
const toggleExpanded = () => {
setExpanded(!expanded);
}

if (expanded) {
// HACK! I want to skip the bubbling phase of the current click
setTimeout(() => {
window.addEventListener('click', () => setExpanded(false), { once: true });
}, 0);
}

const enhancedEntries = props.menuEntries.map(e => {
return {
... e,
onClick: () => {
e.onClick && e.onClick();
toggleExpanded();
}
}
})
const font = "text-gray-400 hover:text-gray-800"
return (
<div className="relative cursor-pointer">
<div onClick={(e) => {
toggleExpanded();
e.preventDefault();
}}>
{props.children}
</div>
{expanded?
<div className={`z-50 w-40 bg-white absolute py-2 right-0 flex flex-col border border-gray-200 rounded-lg space-y-2`}>
{enhancedEntries.map(e => {
const entry = <div key={e.title} className={`px-4 flex py-2 text-gray-600 hover:bg-gray-200 text-sm leading-1 ${e.customFontStyle || font} ${e.separator? ' border-b border-gray-200':''}`} >
<div>{e.title}</div><div className="flex-1"></div>{e.active ? <div className="pl-1 font-semibold">&#x2713;</div>: null}
</div>
return <a href={e.href} onClick={e.onClick}>
{entry}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

quesrtion: Also, could we change the text and dropdown arrow icon color to gray-600 on hover?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you clarify, I think it is already gray-600 without hover.

Copy link
Contributor

@gtsiolis gtsiolis Mar 17, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remember seeing the status filter dropdown label and arrow using the same color on hover. Ideally both the label and the icon arrow would use gray-400 and switch to gray-600 on hover. Feel free to ignore this if this is not the case anymore. 🏓

</a>
})}
</div>
:
null
}
</div>
);
}

export default ContextMenu;
35 changes: 35 additions & 0 deletions components/dashboard/src/components/DropDown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { useState } from 'react';
import ContextMenu from './ContextMenu';

export interface DropDownProps {
entries: {
title: string,
onClick: ()=>void
}[];
}

function Arrow(props: {up: boolean}) {
return <span className="mx-2 border-gray-400" style={{ margin: 2, padding: 3, border: 'solid black', borderWidth: '0 2px 2px 0', display: 'inline-block', transform: `rotate(${props.up ? '-135deg' : '45deg'})`}}></span>
}

function DropDown(props: DropDownProps) {
const [current, setCurrent] = useState(props.entries[0].title);
const enhancedEntries = props.entries.map(e => {
return {
...e,
active: e.title === current,
onClick: () => {
e.onClick();
setCurrent(e.title);
}
}
})
const font = "text-gray-400 text-sm leading-1"
return (
<ContextMenu menuEntries={enhancedEntries}>
<span className={`py-2 cursor-pointer ${font}`}>{current}<Arrow up={false}/></span>
</ContextMenu>
);
}

export default DropDown;
16 changes: 6 additions & 10 deletions components/dashboard/src/components/Modal.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,20 @@
import { useState } from "react";

export default function Modal(props: {
children: React.ReactChild[] | React.ReactChild,
visible: boolean,
closeable?: boolean,
onClose?: () => void
onClose: () => void
}) {
const [visible, setVisible] = useState(props.visible);
const hide = () => setVisible(false);
if (!visible) {
if (!props.visible) {
return null;
}
setTimeout(() => window.addEventListener('click', props.onClose, {once: true}), 0);
return (
<div className="absolute top-0 left-0 bg-black bg-opacity-40 z-50 w-screen h-screen" >
<div className="fixed top-0 -left-2 bg-black bg-opacity-70 z-50 w-screen h-screen" >
<div className="bg-transparent h-1/3" />
<div className="bg-white rounded-md px-6 py-4 max-w-lg mx-auto">
<div className="bg-white border rounded-xl p-6 max-w-lg mx-auto">
{props.closeable !== false && (
<div className="float-right cursor-pointer" onClick={hide}>&#10006;</div>
<div className="float-right cursor-pointer" onClick={props.onClose}>&#10006;</div>
)}

{props.children}
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion components/dashboard/src/components/Separator.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export default function Separator() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this component really necessary?

return <div className="bg-gray-200 h-0.5 absolute left-0 w-screen"></div>;
return <div className="border-gray-200 border-b h-0.5 absolute left-0 w-screen"></div>;
}
28 changes: 0 additions & 28 deletions components/dashboard/src/components/Toggle.tsx

This file was deleted.

7 changes: 6 additions & 1 deletion components/dashboard/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@
}

input[type=text] {
@apply text-xs block w-56 font-medium text-gray-500 rounded-md bg-gray-100 border-gray-300 border-2 focus:border-gray-300 focus:bg-white focus:ring-0;
@apply text-xs block w-56 text-sm text-gray-600 rounded-md focus:border-gray-300 focus:bg-white focus:ring-0;
}

input[type=text]::placeholder {
@apply text-gray-400
}

}
2 changes: 1 addition & 1 deletion components/dashboard/src/settings/Account.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default function Account() {

const close = () => setModal(false);
return <div>
<Modal visible={modal}>
<Modal visible={modal} onClose={close}>
<h3>Do you really want to delete your account?</h3>
<p>This action will remove all the data associated with your account in Gitpod and cannot be reversed.</p>
<div className="flex justify-end pt-6">
Expand Down
2 changes: 1 addition & 1 deletion components/dashboard/src/start/CreateWorkspace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export class CreateWorkspace extends React.Component<CreateWorkspaceProps, Creat
}

else if (result?.existingWorkspaces) {
statusMessage = <Modal visible={true} closeable={false}>
statusMessage = <Modal visible={true} closeable={false} onClose={()=>{}}>
<h3>Running Workspaces</h3>
<div className="border-t border-b border-gray-200 mt-2 -mx-6 px-6 py-2">
<p className="mt-1 mb-2 text-base">You already have running workspaces with the same context. You can open an existing one or open a new workspace.</p>
Expand Down
39 changes: 23 additions & 16 deletions components/dashboard/src/tailwind.output.css
Original file line number Diff line number Diff line change
Expand Up @@ -858,33 +858,20 @@ button {
color: rgba(255, 255, 255, var(--tw-text-opacity));
}

input[type=text] {
--tw-bg-opacity: 1;
background-color: rgba(245, 245, 244, var(--tw-bg-opacity));
}

input[type=text]:focus {
--tw-bg-opacity: 1;
background-color: rgba(255, 255, 255, var(--tw-bg-opacity));
}

input[type=text] {
--tw-border-opacity: 1;
border-color: rgba(214, 211, 209, var(--tw-border-opacity));
}

input[type=text]:focus {
--tw-border-opacity: 1;
border-color: rgba(214, 211, 209, var(--tw-border-opacity));
}

input[type=text] {
border-radius: 0.375rem;
border-width: 2px;
display: block;
font-weight: 500;
font-size: 0.75rem;
line-height: 1rem;
font-size: 0.875rem;
line-height: 1.25rem;
}

input[type=text]:focus {
Expand All @@ -895,10 +882,30 @@ input[type=text]:focus {

input[type=text] {
--tw-text-opacity: 1;
color: rgba(120, 113, 108, var(--tw-text-opacity));
color: rgba(87, 83, 78, var(--tw-text-opacity));
width: 14rem;
}

input[type=text]::-webkit-input-placeholder {
--tw-text-opacity: 1;
color: rgba(168, 162, 158, var(--tw-text-opacity))
}

input[type=text]:-ms-input-placeholder {
--tw-text-opacity: 1;
color: rgba(168, 162, 158, var(--tw-text-opacity))
}

input[type=text]::-ms-input-placeholder {
--tw-text-opacity: 1;
color: rgba(168, 162, 158, var(--tw-text-opacity))
}

input[type=text]::placeholder {
--tw-text-opacity: 1;
color: rgba(168, 162, 158, var(--tw-text-opacity))
}

.space-y-0 > :not([hidden]) ~ :not([hidden]) {
--tw-space-y-reverse: 0 !important;
margin-top: calc(0px * calc(1 - var(--tw-space-y-reverse))) !important;
Expand Down
Loading