Skip to content

Commit

Permalink
feat(cli-terminal): Create cli-terminal
Browse files Browse the repository at this point in the history
  • Loading branch information
abhinandan13jan authored and root committed Mar 26, 2020
1 parent a5bc8fc commit 5e91d37
Show file tree
Hide file tree
Showing 16 changed files with 274 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as React from 'react';
import CloudShellTerminal from '../terminal/CloudshellTerminal';

// [TODO](sahil143) Temp Code, will be removed once we have actual terminal in place
const CloudShellBody: React.FC = () => (
Expand All @@ -8,7 +9,7 @@ const CloudShellBody: React.FC = () => (
height: '100%',
}}
>
<b>Oops! Nothing to see here</b>
<CloudShellTerminal />
</div>
);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import * as React from 'react';
import * as _ from 'lodash';
import { LoadingBox } from '@console/internal/components/utils';

const CloudshellResource: React.FC = (props) => {
const cloudShell = _.get(props, ['resources', 'cloudShell', 'data']);
const phase = _.get(cloudShell, ['status', 'phase']);
const ideUrl = _.get(cloudShell, ['status', 'ideUrl']);
if (phase === 'Running' && ideUrl)
return <iframe title="cloudshell" style={{ width: '100%', height: '100%' }} src={ideUrl} />;
return <LoadingBox />;
};

export default CloudshellResource;
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import * as React from 'react';
import { referenceForModel, k8sCreate, k8sList } from '@console/internal/module/k8s';
import { LoadingBox, Firehose, FirehoseResource } from '@console/internal/components/utils';

import { WorkspaceModel } from '../../models';
import CloudshellResource from './CloudshellResource';
import { newCloudShellWorkSpace } from '../../utils/cloudshell-resource';

type CloudShellTerminalProps = {};

const CloudShellTerminal: React.FC<CloudShellTerminalProps> = () => {
/* Change dedicated name and namespace as per update */
const namespace = 'che-workspace-controller';
const name = 'cloudshell-userID';
const [cloudShell, setCloudShell] = React.useState(null);

const createCloudShell = () => {
k8sCreate(WorkspaceModel, newCloudShellWorkSpace(name, namespace))
.then((newShell) => {
setCloudShell(newShell);
})
.catch((error) => {
// eslint-disable-next-line no-console
console.warn('Cloudshell creation Error', error);
});
};

React.useEffect(() => {
k8sList(WorkspaceModel, { ns: namespace })
.then((existingShells) => {
if (!existingShells || existingShells.length === 0) {
createCloudShell();
} else {
setCloudShell(existingShells[0]);
}
})
.catch((error) => {
// eslint-disable-next-line no-console
console.warn('Cloud Shell resuming error', error);
});
}, []);

if (cloudShell && cloudShell.metadata) {
const resources: FirehoseResource[] = [
{
kind: referenceForModel(WorkspaceModel),
name: cloudShell.metadata.name,
namespace,
prop: `cloudShell`,
isList: false,
},
];

return (
<Firehose resources={resources}>
<CloudshellResource />
</Firehose>
);
}
return <LoadingBox />;
};

export default CloudShellTerminal;
31 changes: 31 additions & 0 deletions frontend/packages/console-app/src/components/terminal/Terminal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import * as React from 'react';
import { connect } from 'react-redux';
import { RootState } from '@console/internal/redux';
import * as UIActions from '@console/internal/actions/ui';
import CloudShellDrawer from '../cloud-shell/CloudShellDrawer';
import CloudShellBody from '../cloud-shell/CloudShellBody';

type TerminalContentProps = {
isTerminalExpanded: boolean;
toggleTerminal: any;
};

const TerminalContent: React.FC<TerminalContentProps> = ({
isTerminalExpanded,
toggleTerminal,
}) => (
<CloudShellDrawer open={isTerminalExpanded} onClose={() => toggleTerminal()}>
<CloudShellBody />
</CloudShellDrawer>
);

const terminalStateToProps = ({ UI }: RootState) => ({
isTerminalExpanded: !!UI.getIn(['terminal', 'isExpanded']),
});

const connecttoTerminalIcon = connect((state: RootState) => terminalStateToProps(state), {
toggleTerminal: UIActions.terminalDrawerToggleExpanded,
});
const ConnectedTerminal = connecttoTerminalIcon(TerminalContent);

export default ConnectedTerminal;
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as React from 'react';
import { TerminalIcon } from '@patternfly/react-icons';
import { Button, ToolbarItem } from '@patternfly/react-core';
import { connectToFlags } from '@console/internal/reducers/features';
import { FLAG_DEVWORKSPACE } from '../../consts';

type TerminalTooliconProps = {
flags: Record<string, any>;
terminalToggle: any;
};
const TerminalToolicon: React.FC<TerminalTooliconProps> = ({ flags, terminalToggle }) => {
if (!flags[FLAG_DEVWORKSPACE]) return null;
return (
<ToolbarItem>
<Button variant="plain" aria-label="Terminal" onClick={terminalToggle}>
<TerminalIcon className="co-masthead-icon" />
</Button>
</ToolbarItem>
);
};

const ConnectedTerminalToolicon = connectToFlags(FLAG_DEVWORKSPACE)(TerminalToolicon);

export default ConnectedTerminalToolicon;
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { action, ActionType } from 'typesafe-actions';

export enum Actions {
TerminalDrawerToggleExpanded = 'terminalDrawerExpanded',
}

export const terminalDrawerToggleExpanded = () => action(Actions.TerminalDrawerToggleExpanded);

const actions = {
terminalDrawerToggleExpanded,
};

export type TerminalAction = ActionType<typeof actions>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Map } from 'immutable';
import { TerminalAction, Actions } from './action';

export type State = Map<string, any>;

export default (state: State, action: TerminalAction) => {
if (!state) {
return Map({
terminal: () => {},
});
}
if (action.type === Actions.TerminalDrawerToggleExpanded)
return state.setIn(['terminal', 'isExpanded'], !state.getIn(['terminal', 'isExpanded']));

return state;
};
1 change: 1 addition & 0 deletions frontend/packages/console-app/src/consts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const FLAG_DEVWORKSPACE = 'DEVWORKSPACE';
27 changes: 27 additions & 0 deletions frontend/packages/console-app/src/models/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { K8sKind } from '@console/internal/module/k8s';

export const WorkspaceModel: K8sKind = {
kind: 'Workspace',
label: 'Workspace',
labelPlural: 'workspaces',
apiGroup: 'workspace.che.eclipse.org',
apiVersion: 'v1alpha1',
abbr: 'WS',
namespaced: true,
crd: true,
plural: 'workspaces',
propagationPolicy: 'Foreground',
};

export const DevWorkspaceModel: K8sKind = {
kind: 'DevWorkspace',
label: 'Devworkspace',
labelPlural: 'workspaces',
apiGroup: 'apiextensions.k8s.io',
apiVersion: 'v1alpha1',
abbr: 'DW',
namespaced: true,
crd: true,
plural: 'devworkspaces',
propagationPolicy: 'Foreground',
};
20 changes: 20 additions & 0 deletions frontend/packages/console-app/src/plugin.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import * as React from 'react';
import * as _ from 'lodash';
import { CogsIcon } from '@patternfly/react-icons';
import { FLAGS } from '@console/shared/src/constants';
import { FLAG_DEVWORKSPACE } from './consts';
import {
Plugin,
Perspective,
ModelFeatureFlag,
ModelDefinition,
DashboardsOverviewResourceActivity,
DashboardsOverviewHealthURLSubsystem,
DashboardsOverviewHealthPrometheusSubsystem,
Expand Down Expand Up @@ -40,16 +44,32 @@ import {
getClusterUpdateTimestamp,
isClusterUpdateActivity,
} from './components/dashboards-page/activity';
import * as models from './models';

type ConsumedExtensions =
| Perspective
| ModelDefinition
| ModelFeatureFlag
| DashboardsOverviewResourceActivity
| DashboardsOverviewHealthURLSubsystem<any>
| DashboardsOverviewHealthPrometheusSubsystem
| DashboardsOverviewInventoryItem
| DashboardsOverviewHealthOperator<ClusterOperator>;

const plugin: Plugin<ConsumedExtensions> = [
{
type: 'ModelDefinition',
properties: {
models: _.values(models),
},
},
{
type: 'FeatureFlag/Model',
properties: {
model: models.DevWorkspaceModel,
flag: FLAG_DEVWORKSPACE,
},
},
{
type: 'Perspective',
properties: {
Expand Down
37 changes: 37 additions & 0 deletions frontend/packages/console-app/src/utils/cloudshell-resource.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
export const newCloudShellWorkSpace = (name: string, namespace: string) => ({
apiVersion: 'workspace.che.eclipse.org/v1alpha1',
kind: 'Workspace',
metadata: {
name,
namespace,
},
spec: {
started: true,
devfile: {
apiVersion: '0.0.1',
metadata: {
name: 'cloud-shell',
},
components: [
{
alias: 'cloud-shell',
type: 'cheEditor',
id: 'eclipse/cloud-shell/nightly',
},
{
type: 'dockerimage',
memoryLimit: '256Mi',
alias: 'dev',
image: 'quay.io/eclipse/che-sidecar-openshift-connector:0.1.2-2601509',
args: ['tail', '-f', '/dev/null'],
env: [
{
value: '\\[\\e[34m\\]>\\[\\e[m\\]\\[\\e[33m\\]>\\[\\e[m\\]',
name: 'PS1',
},
],
},
],
},
},
});
6 changes: 6 additions & 0 deletions frontend/packages/console-app/src/utils/reducers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { combineReducers } from 'redux';
import terminalReducer from '../components/terminal/redux/reducer';

export default combineReducers({
terminal: terminalReducer,
});
3 changes: 3 additions & 0 deletions frontend/public/actions/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export enum ActionType {
ToggleMonitoringGraphs = 'monitoringToggleGraphs',
NotificationDrawerToggleExpanded = 'notificationDrawerExpanded',
NotificationDrawerToggleRead = 'notificationDrawerRead',
TerminalDrawerToggleExpanded = 'terminalDrawerExpanded',
QueryBrowserAddQuery = 'queryBrowserAddQuery',
QueryBrowserDeleteAllQueries = 'queryBrowserDeleteAllQueries',
QueryBrowserDeleteQuery = 'queryBrowserDeleteQuery',
Expand Down Expand Up @@ -308,6 +309,7 @@ export const monitoringToggleGraphs = () => action(ActionType.ToggleMonitoringGr
export const notificationDrawerToggleExpanded = () =>
action(ActionType.NotificationDrawerToggleExpanded);
export const notificationDrawerToggleRead = () => action(ActionType.NotificationDrawerToggleRead);
export const terminalDrawerToggleExpanded = () => action(ActionType.TerminalDrawerToggleExpanded);
export const queryBrowserAddQuery = () => action(ActionType.QueryBrowserAddQuery);
export const queryBrowserDeleteAllQueries = () => action(ActionType.QueryBrowserDeleteAllQueries);
export const queryBrowserDismissNamespaceAlert = () =>
Expand Down Expand Up @@ -391,6 +393,7 @@ const uiActions = {
setNodeMetrics,
notificationDrawerToggleExpanded,
notificationDrawerToggleRead,
terminalDrawerToggleExpanded,
};

export type UIAction = Action<typeof uiActions>;
3 changes: 3 additions & 0 deletions frontend/public/components/app.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import * as _ from 'lodash-es';
import * as React from 'react';
import { render } from 'react-dom';
import { Helmet } from 'react-helmet';

import { Provider } from 'react-redux';
import { Route, Router } from 'react-router-dom';
// AbortController is not supported in some older browser versions
import 'abort-controller/polyfill';
import Terminal from '@console/app/src/components/terminal/Terminal';

import store from '../redux';
import { detectFeatures } from '../actions/features';
Expand Down Expand Up @@ -159,6 +161,7 @@ class App extends React.PureComponent {
</ConnectedNotificationDrawer>
</Firehose>
</Page>
<Terminal />
<ConsoleNotifier location="BannerBottom" />
</>
);
Expand Down
12 changes: 11 additions & 1 deletion frontend/public/components/masthead-toolbar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
import classNames from 'classnames';
import { FLAGS, YellowExclamationTriangleIcon } from '@console/shared';
import { formatNamespacedRouteForResource } from '@console/shared/src/utils';
import TerminalToolicon from '@console/app/src/components/terminal/TerminalToolicon';
import * as UIActions from '../actions/ui';
import { connectToFlags, flagPending, featureReducerName } from '../reducers/features';
import { authSvc } from '../module/auth';
Expand Down Expand Up @@ -523,7 +524,14 @@ class MastheadToolbarContents_ extends React.Component {
showAboutModal,
statuspageData,
} = this.state;
const { consoleLinks, cv, drawerToggle, notificationsRead, canAccessNS } = this.props;
const {
consoleLinks,
cv,
drawerToggle,
notificationsRead,
canAccessNS,
terminalToggle,
} = this.props;
const launchActions = this._launchActions();
const alertAccess = canAccessNS && !!window.SERVER_FLAGS.prometheusBaseURL;
return (
Expand Down Expand Up @@ -572,6 +580,7 @@ class MastheadToolbarContents_ extends React.Component {
<PlusCircleIcon className="co-masthead-icon" />
</Button>
</ToolbarItem>
<TerminalToolicon terminalToggle={terminalToggle} />
<ToolbarItem>
<ApplicationLauncher
aria-label="Help menu"
Expand Down Expand Up @@ -629,6 +638,7 @@ const mastheadToolbarStateToProps = (state) => ({

const MastheadToolbarContents = connect(mastheadToolbarStateToProps, {
drawerToggle: UIActions.notificationDrawerToggleExpanded,
terminalToggle: UIActions.terminalDrawerToggleExpanded,
})(
connectToFlags(
FLAGS.AUTH_ENABLED,
Expand Down
3 changes: 3 additions & 0 deletions frontend/public/reducers/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,9 @@ export default (state: UIState, action: UIAction): UIState => {
case ActionType.NotificationDrawerToggleRead:
return state.setIn(['notifications', 'isRead'], !state.getIn(['notifications', 'isRead']));

case ActionType.TerminalDrawerToggleExpanded:
return state.setIn(['terminal', 'isExpanded'], !state.getIn(['terminal', 'isExpanded']));

case ActionType.QueryBrowserAddQuery:
return state.setIn(
['queryBrowser', 'queries'],
Expand Down

0 comments on commit 5e91d37

Please sign in to comment.