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

Improve in app help #294

Merged
merged 6 commits into from
Nov 23, 2023
Merged
Show file tree
Hide file tree
Changes from 3 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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

### Added
- Link to REST API docs in settings menu

### Changed
- (internal): pipeline HTTP run url is now `/pipelines/{pipeline_id}/run`

## [0.4.1] - 2023-10-11

### Fixed
Expand Down
2 changes: 2 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.17.0",
"react-syntax-highlighter": "^15.5.0",
"react-use-websocket": "^4.3.1"
},
"devDependencies": {
"@types/json-schema": "^7.0.11",
"@types/node": "^20.8.6",
"@types/react": "^18.2.29",
"@types/react-dom": "^18.2.12",
"@types/react-syntax-highlighter": "^15.5.9",
"@vitejs/plugin-react": "^4.0.4",
"autoprefixer": "^10.4.13",
"postcss": "^8.4.21",
Expand Down
38 changes: 31 additions & 7 deletions frontend/src/components/SettingsMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import { useAuthState } from '@/contexts/AuthContext'
import { Card, Tab, TabGroup, TabList } from '@tremor/react'
import { Popover, PopoverContent, PopoverTrigger } from './Popover'
import { Card, Icon, List, Tab, TabGroup, TabList, Text } from '@tremor/react'
import {
Cog6ToothIcon,
MoonIcon,
SunIcon,
ComputerDesktopIcon,
CodeBracketSquareIcon,
ArrowTopRightOnSquareIcon,
} from '@heroicons/react/24/outline'
import UserInfo from './UserInfo'
import { useState } from 'react'

import { useAuthState } from '@/contexts/AuthContext'
import { getApiUrl } from '@/repository'
import { Popover, PopoverContent, PopoverTrigger } from './Popover'
import UserInfo from './UserInfo'

interface Props {}

const THEME_MODE_LIGHT = 0
Expand Down Expand Up @@ -88,10 +92,30 @@
</div>
</PopoverTrigger>
<PopoverContent>
<Card className="shadow-xl z-20">
<ThemeSwitch />
<Card className="p-0 pt-4 shadow-xl z-20">
<List>
<a
Fixed Show fixed Hide fixed
className="flex items-center px-6 py-2 hover:bg-tremor-brand-faint hover:dark:bg-dark-tremor-brand-faint transition-colors no-underline"
href={getApiUrl().replace(/\/api$/, '/docs')}
target="_blank"
>
<Icon
icon={CodeBracketSquareIcon}
color="slate"
className="mr-3"
/>
<Text className="flex-grow no-underline border-0">
REST API docs
</Text>
<Icon icon={ArrowTopRightOnSquareIcon} color="slate" />
</a>
</List>

<div className="p-6">
<ThemeSwitch />

{isAuthenticationEnabled && <UserInfo />}
{isAuthenticationEnabled && <UserInfo />}
</div>
</Card>
</PopoverContent>
</Popover>
Expand Down
109 changes: 109 additions & 0 deletions frontend/src/components/help/PipelineHttpRun.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import {
Button,
Tab,
TabGroup,
TabList,
TabPanel,
TabPanels,
} from '@tremor/react'
import { QuestionMarkCircleIcon } from '@heroicons/react/24/outline'
import { useState } from 'react'
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
import {
okaidia,
oneLight,
} from 'react-syntax-highlighter/dist/esm/styles/prism'

import CopyButton from '@/components/CopyButton'
import Dialog from '@/components/Dialog'
import { getPipelineRunUrl } from '@/repository'

interface Props {
pipelineId: string
triggerId?: string
}

const PipelineHttpRun: React.FC<Props> = ({ pipelineId, triggerId }) => {
const [open, setOpen] = useState(false)
const isDark = document.documentElement.classList.contains('dark')

const SNIPPETS = [
{
language: 'python',
name: 'Python',
code: `import httpx

httpx.post('${getPipelineRunUrl(pipelineId)}', json={
"pipeline_id": "${pipelineId}",
"trigger_id": "${triggerId}",
"params": {
"name": "value",
}
})`,
},
{
language: 'js',
name: 'JavaScript',
code: `fetch('${getPipelineRunUrl(pipelineId)}', {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
pipeline_id: '${pipelineId}',
trigger_id: '${triggerId}',
params: {},
}),
})`,
},
]

return (
<>
<Button
color="indigo"
variant="secondary"
size="xs"
icon={QuestionMarkCircleIcon}
onClick={() => setOpen(true)}
></Button>

<Dialog
isOpen={open}
title="Run via HTTP request"
subtitle="You can run pipelines and triggers via HTTP requests"
onClose={() => setOpen(false)}
>
<TabGroup>
<TabList className="mt-8">
{SNIPPETS.map((snippet) => (
<Tab key={snippet.name}>{snippet.name}</Tab>
))}
</TabList>
<TabPanels>
{SNIPPETS.map((snippet) => (
<TabPanel key={snippet.name}>
<div className="mt-6 relative group">
<SyntaxHighlighter
language={snippet.language}
style={isDark ? okaidia : oneLight}
customStyle={{ borderRadius: 8 }}
>
{snippet.code}
</SyntaxHighlighter>

<CopyButton
content={snippet.code}
className="absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity bg-slate-200/80 dark:bg-slate-800/80 rounded p-2"
/>
</div>
</TabPanel>
))}
</TabPanels>
</TabGroup>
</Dialog>
</>
)
}

export default PipelineHttpRun
51 changes: 10 additions & 41 deletions frontend/src/pages/pipelines/[pipelineId]/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,20 @@ import {
List,
Bold,
Grid,
TextInput,
} from '@tremor/react'
import { useParams } from 'react-router-dom'
import React from 'react'
import {
ArrowTopRightOnSquareIcon,
QuestionMarkCircleIcon,
} from '@heroicons/react/24/outline'
import { ArrowTopRightOnSquareIcon } from '@heroicons/react/24/outline'

import CopyButton from '@/components/CopyButton'
import Breadcrumbs from '@/components/Breadcrumbs'
import RunsDurationChart from '@/components/RunsDurationChart'
import RunsList from '@/components/RunsList'
import RunsStatusChart from '@/components/RunsStatusChart'
import { getPipeline, getPipelineRunUrl, listRuns } from '@/repository'
import { getPipeline, listRuns } from '@/repository'
import ManualRunDialog from '@/components/ManualRunDialog'
import TriggersList from '@/components/TriggersList'
import PageLayout from '@/components/PageLayout'
import PipelineHttpRun from '@/components/help/PipelineHttpRun'

const PipelineView: React.FC = () => {
const urlParams = useParams()
Expand All @@ -36,15 +32,9 @@ const PipelineView: React.FC = () => {
const pipelineQuery = useQuery(getPipeline(pipelineId))
const runsQuery = useQuery(listRuns(pipelineId))

const CopyUrlButton = () => (
<CopyButton content={getPipelineRunUrl(pipelineId)} className="ml-2.5" />
)

if (pipelineQuery.isLoading)
return <div>Loading...</div>
if (pipelineQuery.isLoading) return <div>Loading...</div>

if (pipelineQuery.isError)
return <div>An error has occurred</div>
if (pipelineQuery.isError) return <div>An error has occurred</div>

const pipeline = pipelineQuery.data

Expand Down Expand Up @@ -117,32 +107,14 @@ const PipelineView: React.FC = () => {

<div style={{ flexGrow: 1 }} />

<Flex className="gap-8">
<Flex className="justify-start w-auto flex-shrink-0">
<Text>Run URL</Text>

<Icon
size="sm"
color="slate"
icon={QuestionMarkCircleIcon}
tooltip="URL to run the pipeline programmatically via an HTTP POST request"
/>
</Flex>
<Flex className="justify-between gap-8">
<Text>Run URL</Text>

<TextInput
title={getPipelineRunUrl(pipelineId)}
value={getPipelineRunUrl(pipelineId)}
readOnly
icon={CopyUrlButton}
className="flex-grow"
/>
<PipelineHttpRun pipelineId={pipelineId} />
</Flex>
</Card>

<RunsStatusChart
subject="Pipeline"
query={runsQuery}
/>
<RunsStatusChart subject="Pipeline" query={runsQuery} />

<RunsDurationChart query={runsQuery} />
</Grid>
Expand All @@ -159,10 +131,7 @@ const PipelineView: React.FC = () => {
</Col>

<Col>
<RunsList
query={runsQuery}
pipelineId={pipelineId}
/>
<RunsList query={runsQuery} pipelineId={pipelineId} />
</Col>
</Grid>
</PageLayout>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,23 @@ import {
ListItem,
Button,
Flex,
Icon,
Grid,
TextInput,
} from '@tremor/react'
import { PlayIcon, QuestionMarkCircleIcon } from '@heroicons/react/24/outline'
import { PlayIcon } from '@heroicons/react/24/outline'
import { useNavigate, useParams } from 'react-router-dom'
import React from 'react'

import TriggerParamsDialog from '@/components/TriggerParamsDialog'
import CopyButton from '@/components/CopyButton'
import Breadcrumbs from '@/components/Breadcrumbs'
import ManualRunDialog from '@/components/ManualRunDialog'
import PageLayout from '@/components/PageLayout'
import RunsDurationChart from '@/components/RunsDurationChart'
import RunsList from '@/components/RunsList'
import RunsStatusChart from '@/components/RunsStatusChart'
import { MANUAL_TRIGGER } from '@/constants'
import {
getPipeline,
listRuns,
getTriggerRunUrl,
runPipeline,
} from '@/repository'
import { getPipeline, listRuns, runPipeline } from '@/repository'
import { Trigger } from '@/types'
import PipelineHttpRun from '@/components/help/PipelineHttpRun'

const TriggerView: React.FC = () => {
const navigate = useNavigate()
Expand All @@ -55,18 +48,9 @@ const TriggerView: React.FC = () => {
},
})

const CopyUrlButton = () => (
<CopyButton
content={getTriggerRunUrl(pipelineId, triggerId)}
className="ml-2.5"
/>
)

if (pipelineQuery.isLoading)
return <div>Loading...</div>
if (pipelineQuery.isLoading) return <div>Loading...</div>

if (pipelineQuery.isError)
return <div>An error has occurred</div>
if (pipelineQuery.isError) return <div>An error has occurred</div>

const pipeline = pipelineQuery.data

Expand Down Expand Up @@ -144,32 +128,14 @@ const TriggerView: React.FC = () => {
)}
</ListItem>

<Flex className="gap-8">
<Flex className="justify-start w-auto flex-shrink-0">
<Text>Run URL</Text>
<Flex className="">
<Text>Run URL</Text>

<Icon
size="sm"
color="slate"
icon={QuestionMarkCircleIcon}
tooltip="URL to run the pipeline programmatically via an HTTP POST request"
/>
</Flex>

<TextInput
title={getTriggerRunUrl(pipelineId, triggerId)}
value={getTriggerRunUrl(pipelineId, triggerId)}
readOnly
icon={CopyUrlButton}
className="flex-grow"
/>
<PipelineHttpRun pipelineId={pipelineId} triggerId={triggerId} />
</Flex>
</Card>

<RunsStatusChart
subject="Trigger"
query={runsQuery}
/>
<RunsStatusChart subject="Trigger" query={runsQuery} />

<RunsDurationChart query={runsQuery} />
</Grid>
Expand Down
Loading
Loading