prototype of the deploys page using the inspect component

main
Antonio De Lucreziis 3 months ago
parent d997295848
commit 6ffa9ca777

@ -0,0 +1 @@
CONFIG_PATH=config.yaml

@ -0,0 +1,9 @@
{
"printWidth": 100,
"singleQuote": true,
"quoteProps": "consistent",
"tabWidth": 4,
"semi": false,
"arrowParens": "avoid",
"proseWrap": "always"
}

@ -23,11 +23,19 @@ deploys:
branch: main
type: dockerfile
options:
path: ./Dockerfile
ports:
- 80:8080
volumes:
- /var/www/html:/var/www/html
- name: project2
url: ssh://example.org/username/project2.git
commit: 04c540647a
type: docker-compose
options:
path: ./docker-compose.yml
path: ./docker-compose.yml # already the default
- name: project3
url: https://github.com/username/project3
type: shell
options:
path: ./deploy.sh # already the default
```

@ -2,9 +2,18 @@ deploys:
- name: project1
url: https://github.com/username/project1
branch: main
type: docker
options:
ports:
- 80:8080
volumes:
- /var/www/html:/var/www/html
- name: project2
url: https://github.com/username/project2
type: dockerfile
options:
port: 80:8080
ports:
- 9000:8080
volumes:
- /var/www/html:/var/www/html
- name: project2

@ -20,6 +20,7 @@
"async-mutex": "^0.4.1",
"dockerode": "^4.0.2",
"js-yaml": "^4.1.0",
"lodash": "^4.17.21",
"nodegit": "^0.27.0",
"preact": "^10.19.4",
"typescript": "^5.3.3"
@ -27,6 +28,7 @@
"devDependencies": {
"@types/dockerode": "^3.3.23",
"@types/js-yaml": "^4.0.9",
"@types/lodash": "^4.14.202",
"sass": "^1.70.0"
}
}

@ -35,6 +35,9 @@ dependencies:
js-yaml:
specifier: ^4.1.0
version: 4.1.0
lodash:
specifier: ^4.17.21
version: 4.17.21
nodegit:
specifier: ^0.27.0
version: 0.27.0
@ -52,6 +55,9 @@ devDependencies:
'@types/js-yaml':
specifier: ^4.0.9
version: 4.0.9
'@types/lodash':
specifier: ^4.14.202
version: 4.14.202
sass:
specifier: ^1.70.0
version: 1.70.0
@ -1000,6 +1006,10 @@ packages:
'@types/node': 20.11.17
dev: false
/@types/lodash@4.14.202:
resolution: {integrity: sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==}
dev: true
/@types/mdast@4.0.3:
resolution: {integrity: sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==}
dependencies:

@ -0,0 +1,9 @@
import { Value } from './Inspect.jsx'
export const Deploy = ({ deploy }) => {
return (
<div class="deploy">
<Value value={deploy} borderless />
</div>
)
}

@ -0,0 +1,41 @@
import _ from 'lodash'
import { clsx } from '../utils.js'
export const Value = ({ value, borderless }) => {
return Array.isArray(value) ? (
<ValueArray value={value} borderless={borderless} />
) : typeof value === 'object' ? (
<ValueObject value={value} borderless={borderless} />
) : (
value
)
}
export const ValueArray = ({ value, borderless }) => {
return (
<div class={clsx('compound-value array', borderless && 'borderless')}>
{value.map(item => (
<div class="item">
<Value value={item} borderless={borderless} />
</div>
))}
</div>
)
}
export const ValueObject = ({ value, borderless }) => {
return (
<div class={clsx('compound-value object', borderless && 'borderless')}>
{Object.entries(value).map(([k, v]) => (
<>
<div title={k} class="key">
{_.startCase(k)}
</div>
<div class="value">
<Value value={v} borderless={borderless} />
</div>
</>
))}
</div>
)
}

@ -10,27 +10,50 @@ export const NewDeployForm = () => {
<input id="deploy-name" name="deploy-name" type="text" placeholder="Project name..." />
<label for="deploy-url">Url</label>
<input id="deploy-url" name="deploy-url" type="text" placeholder="Valid git clone url..." />
<input
id="deploy-url"
name="deploy-url"
type="text"
placeholder="Valid git clone url..."
/>
<label for="deploy-ref-type">Ref</label>
<div class="compound">
<select id="deploy-ref-type" name="deploy-ref-type" value={refType} onChange={e => setRefType(e.target.value)}>
<select
id="deploy-ref-type"
name="deploy-ref-type"
value={refType}
onChange={e => setRefType(e.target.value)}
>
<option value="default">Default</option>
<option value="branch">Branch</option>
<option value="tag">Tag</option>
<option value="commit">Commit</option>
</select>
<input class="fill" id="deploy-ref-value" name="deploy-ref-value" disabled={refType === 'default'} type="text" placeholder="Ref value..." />
<input
class="fill"
id="deploy-ref-value"
name="deploy-ref-value"
disabled={refType === 'default'}
type="text"
placeholder="Ref value..."
/>
</div>
<label for="deploy-type">Type</label>
<select id="deploy-type" name="deploy-type" value={deployType} onChange={e => setDeployType(e.target.value)}>
<select
id="deploy-type"
name="deploy-type"
value={deployType}
onChange={e => setDeployType(e.target.value)}
>
<option value="initial" disabled>
Select a deploy type...
</option>
<option value="shell">Shell</option>
<option value="docker">Docker</option>
<option value="dockerfile">Dockerfile</option>
<option value="docker-compose">Docker Compose</option>
<option value="shell">Shell</option>
</select>
<DeployOptions type={deployType} />
@ -44,12 +67,14 @@ export const NewDeployForm = () => {
export const DeployOptions = ({ type }) => {
switch (type) {
case 'shell':
return <ShellDeploy />
case 'dockerfile':
case 'docker':
return <DockerDeploy />
case 'dockerfile':
return <DockerfileDeploy />
case 'docker-compose':
return <DockerComposeDeploy />
case 'shell':
return <ShellDeploy />
default:
return null
}
@ -58,20 +83,75 @@ export const DeployOptions = ({ type }) => {
const DockerDeploy = () => {
return (
<>
<label for="deploy-options-path">Path</label>
<input id="deploy-options-path" name="deploy-options-path" type="text" placeholder="Default is ./Dockerfile..." />
<label for="deploy-options-image">Image</label>
<input id="deploy-options-image" name="deploy-options-image" type="text" placeholder="organization/image:latest" />
<input
id="deploy-options-image"
name="deploy-options-image"
type="text"
placeholder="organization/image:latest"
/>
<label for="deploy-options-ports">Ports</label>
<textarea
id="deploy-options-ports"
name="deploy-options-ports"
rows={2}
placeholder="80:8080"
/>
<label for="deploy-options-env">Environment</label>
<textarea
id="deploy-options-env"
name="deploy-options-env"
rows={2}
placeholder="FOO=bar"
/>
<label for="deploy-options-volumes">Volumes</label>
<textarea
id="deploy-options-volumes"
name="deploy-options-volumes"
rows={2}
placeholder="/var/www/example:/data"
/>
</>
)
}
const DockerfileDeploy = () => {
return (
<>
<label for="deploy-options-path">Path</label>
<input
id="deploy-options-path"
name="deploy-options-path"
type="text"
placeholder="./Dockerfile"
/>
<label for="deploy-options-ports">Ports</label>
<textarea id="deploy-options-ports" name="deploy-options-ports" rows={2} placeholder="80:8080" />
<textarea
id="deploy-options-ports"
name="deploy-options-ports"
rows={2}
placeholder="80:8080..."
/>
<label for="deploy-options-env">Environment</label>
<textarea id="deploy-options-env" name="deploy-options-env" rows={2} placeholder="FOO=bar" />
<textarea
id="deploy-options-env"
name="deploy-options-env"
rows={2}
placeholder="FOO=bar"
/>
<label for="deploy-options-volumes">Volumes</label>
<textarea id="deploy-options-volumes" name="deploy-options-volumes" rows={2} placeholder="/var/www/example:/data" />
<textarea
id="deploy-options-volumes"
name="deploy-options-volumes"
rows={2}
placeholder="/var/www/example:/data"
/>
</>
)
}
@ -80,10 +160,20 @@ const ShellDeploy = () => {
return (
<>
<label for="deploy-options-path">Path</label>
<input id="deploy-options-path" name="deploy-options-path" type="text" placeholder="./deploy.sh" />
<input
id="deploy-options-path"
name="deploy-options-path"
type="text"
placeholder="./deploy.sh"
/>
<label for="deploy-options-env">Environment</label>
<textarea id="deploy-options-env" name="deploy-options-env" rows={2} placeholder="FOO=bar" />
<textarea
id="deploy-options-env"
name="deploy-options-env"
rows={2}
placeholder="FOO=bar"
/>
</>
)
}
@ -92,7 +182,12 @@ const DockerComposeDeploy = () => {
return (
<>
<label for="deploy-options-path">Path</label>
<input id="deploy-options-path" name="deploy-options-path" type="text" />
<input
id="deploy-options-path"
name="deploy-options-path"
type="text"
placeholder="./docker-compose.yml"
/>
</>
)
}

@ -3,46 +3,61 @@ import yaml from 'js-yaml'
import { readFile, writeFile } from 'fs/promises'
import { Mutex } from 'async-mutex'
type GitRef = { commit: string } | { branch: string } | { tag: string }
export type GitRef = { type: 'default' } | { type: 'branch' | 'tag' | 'commit'; value: string }
type BaseDeploy = {
name: string
export type BaseDeploy = { name: string }
export type BaseGitDeploy = BaseDeploy & {
url: string
} & GitRef
ref: GitRef
}
type DockerDeploy = BaseDeploy & {
export type DockerDeploy = BaseDeploy & {
type: 'docker'
options: {
path?: string
image: string
name?: string
volumes?: string[]
ports?: string[]
env?: Record<string, string>
}
}
type DockerComposeDeploy = BaseDeploy & {
export type DockerfileDeploy = BaseGitDeploy & {
type: 'dockerfile'
options: {
path?: string
name?: string
volumes?: string[]
ports?: string[]
env?: Record<string, string>
}
}
export type DockerComposeDeploy = BaseGitDeploy & {
type: 'docker-compose'
options: {
path?: string
}
}
type ShellDeploy = BaseDeploy & {
export type ShellDeploy = BaseGitDeploy & {
type: 'shell'
options: {
path?: string
env?: Record<string, string>
}
}
type Deploy = DockerDeploy | DockerComposeDeploy | ShellDeploy
export type Deploy = DockerDeploy | DockerfileDeploy | DockerComposeDeploy | ShellDeploy
type Config = {
export type Config = {
deploys: Deploy[]
}
export const refToString = (ref: GitRef) => {
return 'commit' in ref ? ref.commit : 'branch' in ref ? ref.branch : 'tag' in ref ? ref.tag : '<default>'
return ref.type === 'default' ? '<default>' : ref.value
}
const mutex = new Mutex()

@ -1,36 +1,15 @@
---
import { Deploy } from '../../client/Deploy'
import { loadConfig, refToString } from '../../config'
import Layout from '../../layouts/Layout.astro'
const { deploys } = await loadConfig()
---
<Layout title="Deplots | phCD">
<Layout title="Deploys | phCD">
<h1>Deploys</h1>
<a class="button" href="/deploys/new">New Deploy</a>
<ul>
{
deploys.map(deploy => (
<li>
<strong>Name: </strong>
{deploy.name} <br />
<strong>URL: </strong>
{deploy.url.startsWith('http') ? (
<a href={deploy.url} target="_blank">
{deploy.url}
</a>
) : (
deploy.url
)}
<br />
<strong>Ref: </strong>
{refToString(deploy)} <br />
<strong>Type: </strong>
{deploy.type} <br />
<strong>Path: </strong>
{deploy.options.path} <br />
</li>
))
}
</ul>
<div class="deploys">
{deploys.map(deploy => <Deploy deploy={deploy} />)}
</div>
</Layout>

@ -104,7 +104,7 @@ textarea {
width: auto;
&:not(textarea) {
height: 32px;
height: 2rem;
}
font-size: 18px;
@ -116,7 +116,7 @@ textarea {
border: 1px solid #ddd;
border-radius: 6px;
padding: 5px 0.25rem;
padding: 0 0.25rem;
display: flex;
align-items: center;
@ -132,6 +132,11 @@ textarea {
}
}
textarea {
min-height: 2rem;
padding: 7px 0.25rem;
}
form {
width: 100%;
@ -144,7 +149,7 @@ form {
border: 1px solid #ddd;
grid-template-columns: minmax(7rem, auto) 1fr;
gap: 0.75rem 1rem;
gap: 0.5rem;
align-items: start;
@ -180,9 +185,99 @@ form {
display: flex;
align-items: center;
height: 32px;
height: 2rem;
font-weight: 700;
}
}
.object {
display: grid;
grid-template-columns: auto 1fr;
border: 1px solid #ddd;
width: 100%;
& > .key {
font-weight: 700;
display: flex;
align-items: center;
min-height: 2rem;
padding: 0 1rem 0 0.25rem;
}
& > .value {
min-height: 2rem;
padding: 0.25rem;
display: flex;
align-items: center;
border-left: 1px solid #ddd;
}
& > .key,
& > .value {
border-top: 1px solid #ddd;
}
& > .key:nth-child(1) {
border-top: none;
}
& > .value:nth-child(2) {
border-top: none;
}
}
.array {
display: grid;
border: 1px solid #ddd;
width: 100%;
& > .item {
display: flex;
align-items: center;
min-height: 2rem;
padding: 0.25rem;
}
& > .item {
border-top: 1px solid #ddd;
}
& > .item:nth-child(1) {
border-top: none;
}
}
.compound-value {
border-radius: 4px;
&.borderless {
border: none;
}
}
.deploys {
width: 100%;
display: flex;
flex-direction: column;
gap: 1rem;
}
.deploy {
width: 100%;
background: #fff;
padding: 1rem;
border-radius: 1rem;
}
//

@ -0,0 +1,5 @@
export const clsx = (...args) =>
args
.filter(Boolean)
.flatMap(s => (typeof s === 'string' ? s.split(' ') : [s]))
.join(' ')

@ -2,6 +2,7 @@
"extends": "astro/tsconfigs/strict",
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "preact"
"jsxImportSource": "preact",
"exactOptionalPropertyTypes": true
}
}

Loading…
Cancel
Save