Skip to content

Commit

Permalink
Add possibility to restart containers (#1808)
Browse files Browse the repository at this point in the history
* Add "Restart Container" button.

* UI Improvements for SSE

- Introduce separate state for container
- Disable button if the container is not started
- Disable Terminal button if you don't own the sandbox

* Updates

* Only reset files to container if we're sure it received it

* Return back to codesandbox.io

* Remove old comment
  • Loading branch information
lbogdan authored and SaraVieira committed Apr 30, 2019
1 parent 3dacc14 commit b315e5e
Show file tree
Hide file tree
Showing 15 changed files with 255 additions and 125 deletions.
9 changes: 0 additions & 9 deletions packages/app/scripts/start.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,15 +212,6 @@ function addMiddleware(devServer, index) {
changeOrigin: true,
})
);

// devServer.use(
// '/socket.io',
// proxy({
// target: 'https://sse.codesandbox.io',
// changeOrigin: true,
// secure: false,
// })
// );
}
if (process.env.VSCODE) {
devServer.use(
Expand Down
32 changes: 19 additions & 13 deletions packages/app/src/app/components/Preview/DevTools/Tabs/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const DevToolTabs = ({
const currentPane = panes[currentPaneIndex];
const actions =
typeof currentPane.actions === 'function'
? currentPane.actions(owned)
? currentPane.actions({ owned })
: currentPane.actions;

const TypedTabDropZone = (TabDropZone as unknown) as React.SFC<
Expand Down Expand Up @@ -89,21 +89,27 @@ const DevToolTabs = ({
</Tabs>

<Actions>
{actions.map(({ title, onClick, Icon }) => (
<Tooltip
style={{ pointerEvents: hidden ? 'none' : 'initial' }}
content={title}
key={title}
>
<Icon
{actions.map(({ title, onClick, Icon, disabled }) => {
return (
<Tooltip
style={{
opacity: hidden ? 0 : 1,
pointerEvents: hidden ? 'none' : 'initial',
}}
onClick={onClick}
content={title}
key={title}
/>
</Tooltip>
))}
delay={disabled ? [0, 0] : [500, 0]}
>
<Icon
style={{
opacity: hidden ? 0 : disabled ? 0.5 : 1,
pointerEvents: disabled ? 'none' : 'initial',
}}
onClick={onClick}
key={title}
/>
</Tooltip>
);
})}
</Actions>
</Container>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,16 +229,17 @@ export default {
id: 'codesandbox.terminal',
title: 'Terminal',
Content: withTheme(TerminalComponent),
actions: (owner: boolean) =>
actions: ({ owned }) =>
[
owner && {
title: 'Add Terminal',
{
title: owned ? 'Add Terminal' : 'Fork to add a terminal',
onClick: () => {
if (createShell) {
if (createShell && owned) {
createShell();
}
},
Icon: PlusIcon,
disabled: !owned,
},
].filter(Boolean),
};
3 changes: 2 additions & 1 deletion packages/app/src/app/components/Preview/DevTools/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,14 @@ export interface IViewAction {
title: string;
onClick: () => void;
Icon: React.ComponentClass<any, any>;
disabled?: boolean;
}

export interface IViewType {
id: string;
title: string;
Content: React.ComponentClass<any, any>;
actions: IViewAction[] | ((owner: boolean) => IViewAction[]);
actions: IViewAction[] | ((info: { owned: boolean }) => IViewAction[]);
}

export type StatusType = 'info' | 'warning' | 'error' | 'success' | 'clear';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,9 +217,14 @@ class Preview extends Component<Props, State> {
onToggleProjectView={() => signals.editor.projectViewToggled()}
showDevtools={store.preferences.showDevtools}
isResizing={store.editor.isResizing}
setServerStatus={(status: string) => {
setSSEManagerStatus={(status: string) => {
signals.server.statusChanged({ status });
}}
setSSEContainerStatus={(status: string) => {
signals.server.containerStatusChanged({ status });
}}
managerStatus={store.server.status}
containerStatus={store.server.containerStatus}
syncSandbox={signals.files.syncSandbox}
/>
) : (
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// @flow
import React from 'react';
import styled from 'styled-components';

import {
SSEContainerStatus,
SSEManagerStatus,
} from '@codesandbox/common/lib/types';

type Props = {
containerStatus: SSEContainerStatus;
managerStatus: SSEManagerStatus;
};

const StatusCircle = styled.div`
border-radius: 50%;
background-color: ${props => props.color};
width: 8px;
height: 8px;
margin-left: 0.75rem; /* Very precise to keep aligned with script icons */
margin-right: 0.75rem;
`;

const Container = styled.div`
display: flex;
align-items: center;
color: ${props =>
props.theme['editor.foreground'] || 'rgba(255, 255, 255, 0.8)'};
`;

const STATUS_MESSAGES = {
disconnected: 'Reconnecting to sandbox...',
connected: 'Connected to sandbox',
initializing: 'Initializing connection to sandbox...',
hibernated: 'Sandbox hibernated',
error: 'Unrecoverable sandbox error',
};

const STATUS_COLOR = {
disconnected: '#FD2439',
connected: '#4CFF00',
initializing: '#FFD399',
hibernated: '#FF662E',
error: '#FD2439',
};

function getContainerStatusMessageAndColor(
containerStatus: SSEContainerStatus
) {
switch (containerStatus) {
case 'initializing':
return { color: '#FFD399', message: 'Container is starting...' };
case 'container-started':
case 'stopped':
return { color: '#FFD399', message: 'Sandbox is starting...' };
case 'sandbox-started':
return { color: '#4CFF00', message: 'Connected to sandbox' };
case 'error':
return { color: '#FD2439', message: 'A sandbox error occurred' };
case 'hibernated':
return { color: '#FF662E', message: 'Sandbox hibernated' };
default:
return undefined;
}
}

function getManagerStatusMessageAndColor(managerStatus: SSEManagerStatus) {
switch (managerStatus) {
case 'connected':
case 'disconnected':
return undefined;
case 'initializing':
return {
message: 'Initializing connection to sandbox...',
color: '#FFD399',
};
default:
return undefined;
}
}

export default ({ containerStatus, managerStatus }: Props) => {
const { color, message } =
getManagerStatusMessageAndColor(managerStatus) ||
getContainerStatusMessageAndColor(containerStatus);
return (
<Container>
<StatusCircle color={color} />

{message}
</Container>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,8 @@ const SubTitle = styled.div`
font-size: 0.875rem;
`;

const Server = ({ store }) => {
function Server({ store }) {
const { parsed } = store.editor.parsedConfigurations.package;

const disconnected = store.server.status !== 'connected';

return (
Expand All @@ -38,7 +37,10 @@ const Server = ({ store }) => {
<Margin top={1}>
<SubTitle>Status</SubTitle>
<WorkspaceInputContainer>
<Status status={store.server.status} />
<Status
managerStatus={store.server.status}
containerStatus={store.server.containerStatus}
/>
</WorkspaceInputContainer>
</Margin>

Expand All @@ -58,17 +60,6 @@ const Server = ({ store }) => {
</Margin>
</Margin>

<Margin top={1}>
<SubTitle>Secret Keys</SubTitle>
<Description>
Secrets are available as environment variables. They are kept private
and will not be transferred between forks.
</Description>
<Margin top={0.5}>
<EnvironmentVariables />
</Margin>
</Margin>

<Margin top={1} bottom={0.5}>
<SubTitle style={{ marginBottom: '.5rem' }}>Control Container</SubTitle>
<WorkspaceInputContainer>
Expand All @@ -80,20 +71,61 @@ const Server = ({ store }) => {
}}
small
block
disabled={disconnected}
onClick={() =>
dispatch({ type: 'socket:message', channel: 'sandbox:restart' })
disabled={
disconnected || store.server.containerStatus !== 'sandbox-started'
}
onClick={() => {
dispatch({ type: 'socket:message', channel: 'sandbox:restart' });
}}
>
<PowerIcon
style={{ fontSize: '1.125em', marginRight: '.25rem ' }}
/>{' '}
Restart Sandbox
</Button>
</WorkspaceInputContainer>
<WorkspaceInputContainer>
<Button
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
small
block
disabled={
disconnected || store.server.containerStatus === 'initializing'
}
onClick={() => {
this.props.signals.server.containerStatusChanged({
status: 'initializing',
});
dispatch({
type: 'socket:message',
channel: 'sandbox:restart-container',
});
}}
>
<PowerIcon
style={{ fontSize: '1.125em', marginRight: '.25rem ' }}
/>{' '}
Restart Server
</Button>
</WorkspaceInputContainer>
</Margin>

<Margin top={1}>
<SubTitle>Secret Keys</SubTitle>
<Description>
Secrets are available as environment variables. They are kept private
and will not be transferred between forks.
</Description>
<Margin top={0.5}>
<EnvironmentVariables />
</Margin>
</Margin>
</div>
);
};
}

export default inject('store')(observer(Server));
export default inject('store', 'signals')(observer(Server));
2 changes: 2 additions & 0 deletions packages/app/src/app/store/modules/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ export default Module({
model,
state: {
status: 'initializing',
containerStatus: 'initializing',
},
signals: {
statusChanged: sequences.setStatus,
containerStatusChanged: sequences.setContainerStatus,
},
});
Loading

0 comments on commit b315e5e

Please sign in to comment.