Skip to content

Commit

Permalink
feat: starting integration with tilt by detecting dashboard and servi…
Browse files Browse the repository at this point in the history
…ng it
  • Loading branch information
wufe committed Jan 17, 2024
1 parent 081d53d commit d686280
Show file tree
Hide file tree
Showing 31 changed files with 728 additions and 88 deletions.
13 changes: 13 additions & 0 deletions client/common/api/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ export interface IApiSessionStatus {
replacedBy: string;
}

export interface IAPISessionIntegrations {
tilt: {
dashboards: Array<{
id: string;
url: string;
}>;
}
}

export function killSessionAPI(uuid: string) {
return buildRequest<void>(() => Axios.delete(`/_polo_/api/session/${uuid}`));
}
Expand All @@ -39,6 +48,10 @@ export function retrieveSessionStatusAPI(uuid: string) {
return buildRequest<IApiSessionStatus>(() => Axios.get(`/_polo_/api/session/${uuid}/status`));
}

export function retrieveSessionIntegrationsStatusAPI(uuid: string) {
return buildRequest<IAPISessionIntegrations>(() => Axios.get(`/_polo_/api/session/${uuid}/status/integrations`));
}

export function retrieveLogsAndStatusAPI(uuid: string, lastUUID: string = "<none>") {
return buildRequest<IAPISessionLogsAndStatus>(() => Axios.get(`/_polo_/api/session/${uuid}/logs/${lastUUID}`));
}
Expand Down
38 changes: 36 additions & 2 deletions client/common/state/models/session-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import { APIPayload, APIRequestResult } from '../../api/common';
import {
getLogsWSURL,
IAPISession,
IAPISessionIntegrations,
IAPISessionLogsAndStatus, IApiSessionStatus,
killSessionAPI,
retrieveLogsAndStatusAPI,
retrieveSessionIntegrationsStatusAPI,
retrieveSessionStatusAPI,
trackSessionAPI,
untrackSessionAPI
Expand All @@ -16,6 +18,21 @@ export const SessionConfigurationModel = types.model({
isDefault: types.boolean,
});

//#region Integrations
export const TiltDashboardModel = types.model({
id: types.string,
url: types.string,
});

export const TiltSessionIntegrationModel = types.model({
dashboards: types.array(TiltDashboardModel),
});

export const SessionIntegrationsModel = types.model({
tilt: TiltSessionIntegrationModel,
});
//#endregion

export enum SessionLogType {
TRACE = 'trace',
DEBUG = 'debug',
Expand Down Expand Up @@ -77,6 +94,7 @@ export const SessionModel = types.model({
replacedBy : types.string,
permalink : types.string,
smartURL : types.string,
integrations : SessionIntegrationsModel,
}).views(self => ({
get beingReplacedBySession() {
return self.beingReplacedBy as ISession;
Expand Down Expand Up @@ -119,14 +137,30 @@ export const SessionModel = types.model({
}

return logsAndStatus;
})
});

const retrieveIntegrationsStatus = flow(function* retrieveIntegrations() {
const integrations: APIPayload<IAPISessionIntegrations> = yield retrieveSessionIntegrationsStatusAPI(self.uuid);

if (integrations.result === APIRequestResult.SUCCEEDED) {
self.integrations = {
...self.integrations,
tilt: TiltSessionIntegrationModel.create({
dashboards: integrations.payload.tilt.dashboards.map(dashboard => TiltDashboardModel.create({
id: dashboard.id,
url: dashboard.url,
})),
}),
};
}
});

const kill = flow(function* kill() {
const kill: APIPayload<void> = yield killSessionAPI(self.uuid);
return kill;
})

return { retrieveAge, retrieveStatus, track, untrack, kill, retrieveLogsAndStatus };
return { retrieveAge, retrieveStatus, track, untrack, kill, retrieveLogsAndStatus, retrieveIntegrationsStatus };
});

export interface ISession extends Instance<typeof SessionModel> {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { ISession } from '@polo/common/state/models';
import { observer } from 'mobx-react-lite';
import React from 'react';
import { TiltSessionIntegrationStatusDashboardLink } from './tilt/tilt-session-integration-status-dashboard-link';

type TProps = {
session: ISession;
integrationsStatus: ISession['integrations'];
};

export const SessionIntegrationsStatus = observer((props: TProps) => {
return <TiltSessionIntegrationStatusDashboardLink
session={props.session}
dashboards={props.integrationsStatus.tilt.dashboards} />;
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from 'react';
import { ISession } from "@polo/common/state/models";
import { observer } from "mobx-react-lite";

type TProps = {
session: ISession;
dashboards: ISession['integrations']['tilt']['dashboards'];
};

export const TiltSessionIntegrationStatusDashboardLink = observer((props: TProps) => {
return <div className={'flex'}>
{props.dashboards.map((dashboard, i) => {
return <a
key={dashboard.id}
href={`${window.configuration.integrationsPublicURL}/tilt/${props.session.uuid}/${dashboard.id}`}
target="_blank"
className="text-xs uppercase px-3 py-2 rounded-md bg-nord14 text-nord5 hover:text-nord0-lighter hover:bg-nord14-alpha50 active:bg-nord14-darker active:text-nord5 transition-colors duration-200 ease-in-out mx-1">
Tilt Dashboard {props.dashboards.length > 1 ? i + 1 : ''}
</a>
})}
</div>;
});
10 changes: 4 additions & 6 deletions client/manager/src/components/session/session-retrieval-hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,10 @@ export const useSessionTerminalRetrieval = (

let fetchFailed = false;
try {
const status = await session.retrieveStatus();
// Refreshes the status, which will be checked automatically
// from the component (or one of its ancestors) containing this hook
await session.retrieveStatus();
await session.retrieveIntegrationsStatus();
interval.current = setTimeout(() => sessionStatusRetrieval(), 1000);
} catch (e) {
console.error(e);
Expand Down Expand Up @@ -182,17 +185,12 @@ export const useSessionTerminalRetrieval = (
setTimeout(() => fitAddon.fit(), 0);
};

ws.onmessage = message => {
console.log(message.type, message.data)
};

terminal.onResize(function(event) {
const rows = event.rows;
const cols = event.cols;
const size = JSON.stringify({cols: cols, rows: rows + 1});
const send = new TextEncoder().encode("\x01" + size);
ws.send(send);
console.log('resizing', rows, cols)
});

const onWindowResize = () => {
Expand Down
23 changes: 15 additions & 8 deletions client/manager/src/components/session/session.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
import {SessionLogsContainer} from '@/components/session/session-logs-container';
import {SessionTerminalContainer} from '@/components/session/session-terminal-container';
import { SessionLogsContainer } from '@/components/session/session-logs-container';
import { SessionTerminalContainer } from '@/components/session/session-terminal-container';
import { IApp } from '@polo/common/state/models/app-model';
import {useNotification} from '@polo/common/state/models/notification-hook';
import { useNotification } from '@polo/common/state/models/notification-hook';
import { ISession } from '@polo/common/state/models/session-model';
import {buildFailedNotification} from '@polo/common/state/notifications/build-failed-notification';
import { buildFailedNotification } from '@polo/common/state/notifications/build-failed-notification';
import { observer } from 'mobx-react-lite';
import React, { useState } from 'react';
import {useHistory} from 'react-router-dom';
import React, { useEffect, useState } from 'react';
import { useHistory } from 'react-router-dom';
import { CommitMessage } from '../shared/commit-message';
import 'xterm/css/xterm.css';
import '@polo/manager/src/components/session/session.scss';
import { SessionIntegrationsStatus } from './integrations-status/session-integrations-status';

declare global {
interface Window {
configuration: {
advancedTerminalOutput: boolean;
integrationsPublicURL: string;
};
}
}
Expand Down Expand Up @@ -43,13 +45,18 @@ export const Session = observer((props: TProps) => {
};

return <div className="
mx-auto w-full max-w-6xl flex flex-col min-w-0 min-h-0 flex-1 pt-3 font-quicksand" style={{maxHeight:'calc(100vh - 120px)'}}>
mx-auto w-full max-w-6xl flex flex-col min-w-0 min-h-0 flex-1 pt-3 font-quicksand" style={{ maxHeight: 'calc(100vh - 120px)' }}>
<div className="main-gradient-faded absolute left-0 right-0 top-0 pointer-events-none" style={{ bottom: `${overlayBottom}%`, zIndex: 1 }}></div>
<h1 className="text-4xl px-2 lg:px-0 mb-3 font-quicksand font-light text-nord1 dark:text-nord5 z-10">
Session
</h1>
<div className="text-lg text-nord1 dark:text-nord5 mb-4 z-10 border-l pl-3 border-gray-500">
<div className="text-lg text-nord1 dark:text-nord5 mb-4 z-10 border-l pl-3 border-gray-500 flex justify-between min-w-full">
<span>{props.session.displayName}</span>
<div>
<SessionIntegrationsStatus
session={props.session}
integrationsStatus={props.session.integrations} />
</div>
</div>
<CommitMessage {...props.session} maxHeight />
{useAdvancedTerminal && <SessionTerminalContainer app={props.app} session={props.session} onSessionFail={onSessionFail} />}
Expand Down
3 changes: 3 additions & 0 deletions client/manager/tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,14 @@ module.exports = {
"nord0-alpha30": Color("#2E3440").alpha(.3).string(),
"nord0-alpha40": Color("#2E3440").alpha(.4).string(),
"nord0-alpha50": Color("#2E3440").alpha(.5).string(),
"nord0-lighter": Color("#2E3440").lighten(.5).string(),
"nord4-alpha10": Color("#D8DEE9").alpha(.1).string(),
"nord4-alpha20": Color("#D8DEE9").alpha(.2).string(),
"nord4-alpha30": Color("#D8DEE9").alpha(.3).string(),
"nord4-alpha40": Color("#D8DEE9").alpha(.4).string(),
"nord4-alpha50": Color("#D8DEE9").alpha(.5).string(),
"nord4-alpha": Color("#D8DEE9").alpha(.5).string(),
"nord4-darker": Color("#D8DEE9").darken(.3).string(),
"nord6-alpha10": Color("#ECEFF4").alpha(.1).string(),
"nord6-alpha20": Color("#ECEFF4").alpha(.2).string(),
"nord6-alpha30": Color("#ECEFF4").alpha(.3).string(),
Expand All @@ -44,6 +46,7 @@ module.exports = {
"nord6-alpha": Color("#ECEFF4").alpha(.5).string(),
"nord14-alpha50": Color("#A3BE8C").alpha(.5).string(),
"nord14-alpha": Color("#A3BE8C").alpha(.5).string(),
"nord14-darker": Color("#A3BE8C").darken(.3).string(),
"nord11-alpha50": Color("#BF616A").alpha(.5).string(),
"nord11-alpha": Color("#BF616A").alpha(.5).string(),
}),
Expand Down
5 changes: 3 additions & 2 deletions client/manager/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ module.exports = {
]
},
target: 'web',
optimization: {
optimization: {
minimizer: [
"...",
isProduction && new CssMinimizerPlugin(),
Expand Down Expand Up @@ -144,6 +144,7 @@ module.exports = {
},
compress: true,
port: 9000,
hot: true
hot: true,
allowedHosts: 'all'
}
};
2 changes: 2 additions & 0 deletions cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ func main() {

container.AddStaticService()
container.AddQueryService()
container.AddIntegrationsStatusRetriever()
container.AddRequestService()
container.AddAliasingService()

Expand All @@ -85,6 +86,7 @@ func main() {
container.AddHTTPProxy()
container.AddHTTPRouter()
container.AddHTTPRestHandler()
container.AddIntegrationsHTTPHandler()

// Startup

Expand Down
15 changes: 15 additions & 0 deletions internal/tests/di_fixture.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/wufe/polo/pkg/http/proxy"
"github.com/wufe/polo/pkg/http/rest"
"github.com/wufe/polo/pkg/http/routing"
"github.com/wufe/polo/pkg/integrations"
"github.com/wufe/polo/pkg/logging"
"github.com/wufe/polo/pkg/models"
"github.com/wufe/polo/pkg/services"
Expand Down Expand Up @@ -369,6 +370,14 @@ func (d *DI) AddQueryService() {
}
}

func (d *DI) AddIntegrationsStatusRetriever() {
if err := d.container.Provide(func(query *services.QueryService) integrations.SessionIntegrationsStatusRetriever {
return query
}); err != nil {
log.Panic(err)
}
}

func (d *DI) AddRequestService() {
if err := d.container.Provide(func(environment utils.Environment, sesStorage *storage.Session, appStorage *storage.Application, mediator *background.Mediator) *services.RequestService {
return services.NewRequestService(environment, sesStorage, appStorage, mediator)
Expand Down Expand Up @@ -437,6 +446,12 @@ func (d *DI) AddHTTPRestHandler() {
}
}

func (d *DI) AddIntegrationsHTTPHandler() {
if err := d.container.Provide(integrations.NewHandler); err != nil {
log.Panic(err)
}
}

// Startup

func (d *DI) AddStartup() {
Expand Down
2 changes: 2 additions & 0 deletions internal/tests/fixture.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ func Fixture(injectable *InjectableServices, applicationConfigurations ...*model

container.AddStaticService()
container.AddQueryService()
container.AddIntegrationsStatusRetriever()
container.AddRequestService()
container.AddAliasingService()

Expand All @@ -82,6 +83,7 @@ func Fixture(injectable *InjectableServices, applicationConfigurations ...*model
container.AddHTTPProxy()
container.AddHTTPRouter()
container.AddHTTPRestHandler()
container.AddIntegrationsHTTPHandler()

// Startup

Expand Down
27 changes: 27 additions & 0 deletions pkg/background/session-command-execution.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package background

import (
"bufio"
"context"
"fmt"
"io"
Expand All @@ -9,6 +10,7 @@ import (
"regexp"
"runtime"
"strings"
"sync"
"time"

"github.com/creack/pty"
Expand Down Expand Up @@ -76,6 +78,24 @@ func (ce *sessionCommandExecutionImpl) ExecCommand(ctx context.Context, command

buffer := make([]byte, 1024)

pipeReader, pipeWriter := io.Pipe()

var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()

scanner := bufio.NewScanner(pipeReader)
for scanner.Scan() {
line := scanner.Text()
parseSessionCommandOuput(session, command, line)
}

if err := scanner.Err(); err != nil {
ce.log.Warnf("error reading from the pipe reader: %s", err)
}
}()

for {
n, err := tty.Read(buffer)
if err == io.EOF {
Expand All @@ -86,10 +106,17 @@ func (ce *sessionCommandExecutionImpl) ExecCommand(ctx context.Context, command
break
}

if _, err := pipeWriter.Write(buffer[:n]); err != nil {
ce.log.Warnf("Error writing to pipe writer: %s", err)
}

if _, err := outputBuffer.Write(buffer[:n]); err != nil {
ce.log.Warnf("Error writing to PTY output buffer: %s", err)
}
}
pipeWriter.Close()

wg.Wait()
} else {
err = ce.commandRunner.ExecCmds(ctx, func(line *execution.StdLine) {
if line.Type == execution.StdTypeOut {
Expand Down
Loading

0 comments on commit d686280

Please sign in to comment.