Skip to content

Commit

Permalink
wip new init flow
Browse files Browse the repository at this point in the history
  • Loading branch information
timsuchanek committed Aug 19, 2019
1 parent f6ba182 commit f0e6b7c
Show file tree
Hide file tree
Showing 29 changed files with 290 additions and 34 deletions.
2 changes: 2 additions & 0 deletions cli/introspection/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,12 @@
"dependencies": {
"ajv": "^6.10.0",
"chalk": "^2.4.2",
"cli-truncate": "^2.0.0",
"dotenv": "^8.0.0",
"execa": "^1.0.0",
"figures": "^3.0.0",
"ink": "^2.2.0",
"ink-progress-bar": "^3.0.0",
"ink-spinner": "^3.0.1",
"ink-text-input": "^3.2.0",
"jsonwebtoken": "^8.5.1",
Expand Down
44 changes: 24 additions & 20 deletions cli/introspection/src/commands/Init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { findTemplate } from '../templates'
import { loadStarter } from '../loader'
import { mkdirpSync } from 'fs-extra'
import { InitPromptResult } from '../types'
import { renderInk } from '../prompt/inkTest'

export class Init implements Command {
static new(env: Env): Init {
Expand All @@ -31,26 +32,29 @@ export class Init implements Command {

const outputDirName = args._[0]
const outputDir = outputDirName ? join(process.cwd(), outputDirName) : process.cwd()

const existingFiles = readdirSync(outputDir)

if (existingFiles.length > 0) {
const relativeOutPath = './' + relative(process.cwd(), outputDir)
const s = existingFiles.length === 1 ? 's' : ''
const plural = existingFiles.length === 1 ? '' : 's'
const files =
existingFiles.length > 3
? existingFiles
.slice(0, 3)
.map(f => chalk.bold(f))
.join(', ') + `and ${existingFiles.length - 3} more files `
: existingFiles.map(f => chalk.underline(f)).join(', ')
throw new Error(`Can't start ${chalk.bold(
'prisma2 init',
)} as the file${plural} ${files} exist${s} in ${chalk.underline(relativeOutPath)}
Please either run ${chalk.greenBright('prisma2 init')} in an empty directory
or provide a directory to initialize in: ${chalk.greenBright('prisma2 init sub-dir')}`)
}
await renderInk()
return

// TODO: Move logic to the right place
// const existingFiles = readdirSync(outputDir)

// if (existingFiles.length > 0) {
// const relativeOutPath = './' + relative(process.cwd(), outputDir)
// const s = existingFiles.length === 1 ? 's' : ''
// const plural = existingFiles.length === 1 ? '' : 's'
// const files =
// existingFiles.length > 3
// ? existingFiles
// .slice(0, 3)
// .map(f => chalk.bold(f))
// .join(', ') + `and ${existingFiles.length - 3} more files `
// : existingFiles.map(f => chalk.underline(f)).join(', ')
// throw new Error(`Can't start ${chalk.bold(
// 'prisma2 init',
// )} as the file${plural} ${files} exist${s} in ${chalk.underline(relativeOutPath)}
// Please either run ${chalk.greenBright('prisma2 init')} in an empty directory
// or provide a directory to initialize in: ${chalk.greenBright('prisma2 init sub-dir')}`)
// }

if (outputDirName) {
try {
Expand Down
File renamed without changes.
60 changes: 60 additions & 0 deletions cli/introspection/src/prompt/components/BorderBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React from 'react'
import { Box } from 'ink'
import { drawBox } from './drawBox'

interface Layout {
bottom: number
height: number
left: number
right: number
top: number
width: number
}

export default class BorderBox extends React.Component<any> {
ref: any
state = {
border: '',
height: 0,
width: 0,
}
setRef = ref => {
this.ref = ref
const layout: Layout = this.ref.nodeRef.current.yogaNode.getComputedLayout()
const width = this.props.width || layout.width
const height = this.props.height || layout.height

const border = drawBox({
title: this.props.title,
width: width + 0,
height,
str: '',
drawExtension: this.props.extension,
})
this.setState({ border, height, width })
}
render() {
const { props } = this
const { marginTop, marginBottom, marginLeft, marginRight, paddingBottom, paddingTop, ...rest } = props
const extensionTop = this.props.extension ? -1 : 0
const outerProps = {
marginTop: (marginTop || 0) + extensionTop,
marginBottom,
marginLeft,
marginRight,
}
return (
<Box flexDirection="column" {...outerProps}>
<Box>{this.state.border}</Box>
<Box
ref={this.setRef}
marginTop={-this.state.height}
marginLeft={2}
paddingTop={paddingTop}
paddingBottom={(paddingBottom || 0) + 2}
{...rest}
/>
</Box>
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ import {
import { RadioButton } from './RadioButton'
import { SelectIndicator, SelectItem } from './SelectItem'
import { TextInput } from './TextInput'
import { CheckboxElement, InputElement, PromptElement, RadioElement, SpinnerState } from './types'
import { useStdin } from './useStdin'
import { CheckboxElement, InputElement, PromptElement, RadioElement, SpinnerState } from '../types'
import { useStdin } from '../useStdin'

export interface OnSubmitParams {
formValues?: Record<string, any>
Expand Down
25 changes: 25 additions & 0 deletions cli/introspection/src/prompt/components/Progress.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react'
import { Color, Box, Text } from 'ink'
import ProgressBar from 'ink-progress-bar'

export interface Props {
progress: number // progress from 0 to 1
}

const width = 40

export function Progress(props: Props) {
const { progress } = props
const percentage = Math.round(progress * 100)
return (
<Color green>
<Box marginLeft={1} marginRight={1}>
<Text bold>{percentage}%</Text>
</Box>
<ProgressBar percent={progress} columns={width} />
<Color dim>
<ProgressBar percent={1 - progress} columns={width} character="░" />
</Color>
</Color>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import * as React from 'react'
import { COLORS } from '../colors'
import { BACK_SYMBOL } from './helpers'
import { Spinner } from './Spinner'
import { SpinnerState } from './types'
import { useStdin } from './useStdin'
import { SpinnerState } from '../types'
import { useStdin } from '../useStdin'
import figures = require('figures')

interface Props {
Expand Down
59 changes: 59 additions & 0 deletions cli/introspection/src/prompt/components/drawBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import chalk from 'chalk'
import cliTruncate from 'cli-truncate'
import stringWidth from 'string-width'

export type BoxOptions = {
title: string
width: number
height: number
str: string
drawExtension?: boolean
}

const defaultChars = {
topLeft: '┌',
topRight: '┐',
bottomRight: '┘',
bottomLeft: '└',
vertical: '│',
horizontal: '─',
}

export function drawBox({ title, width, height, str, drawExtension }: BoxOptions) {
const chars = { ...defaultChars }

if (drawExtension) {
chars.topLeft = '├'
chars.topRight = '┤'
}

title = title || ''
const topLine =
chalk.grey(chars.topLeft + chars.horizontal) +
(title ? ' ' : '') +
chalk.reset(title) +
(title ? ' ' : '') +
chalk.grey(chars.horizontal.repeat(width - stringWidth(title) - (title ? 2 : 0) - 3) + chars.topRight) +
chalk.reset()

const bottomLine = chars.bottomLeft + chars.horizontal.repeat(width - 2) + chars.bottomRight

const lines = str.split('\n')

if (lines.length < height) {
lines.push(...new Array(height - lines.length).fill(''))
}

const mappedLines = lines
.slice(-height)
.map(l => {
const lineWidth = Math.min(stringWidth(l || ''), width)
const paddingRight = Math.max(width - lineWidth - 2, 0)
return `${chalk.grey(chars.vertical)}${chalk.reset(cliTruncate(l, width - 2))}${' '.repeat(
paddingRight,
)}${chalk.grey(chars.vertical)}`
})
.join('\n')

return chalk.grey(topLine + '\n' + mappedLines + '\n' + bottomLine)
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Key } from 'readline'
import { CheckboxElement, InputElement, PromptElement, RadioElement, SelectElement, SeparatorElement } from './types'
import { CheckboxElement, InputElement, PromptElement, RadioElement, SelectElement, SeparatorElement } from '../types'

export function isElementInput(obj: PromptElement): obj is InputElement {
return obj && obj.type === 'text-input'
Expand Down
38 changes: 38 additions & 0 deletions cli/introspection/src/prompt/inkTest.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { render, Color, Box, Text } from 'ink'
import React from 'react'
import { Progress } from './components/Progress'
import BorderBox from './components/BorderBox'
import chalk from 'chalk'
import Step0StarterVsBlank from './steps/Step0StarterVsBlank'

class Compy extends React.Component<any, { step: number; progress: number }> {
state = {
step: 0,
progress: 0,
}
componentDidMount() {
setInterval(() => {
this.setState(({ step }) => {
step += 0.05

return {
step,
progress: Math.abs(Math.sin(step)),
}
})
}, 16)
}
render() {
return (
<BorderBox flexDirection="column" title={chalk.bold('Hello World ' + Math.round(this.state.progress * 100))}>
<Progress progress={this.state.progress} />
</BorderBox>
)
}
}

export function renderInk() {
return new Promise(resolve => {
render(<Step0StarterVsBlank />)
})
}
2 changes: 1 addition & 1 deletion cli/introspection/src/prompt/prompts-elements.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DatabaseType } from 'prisma-datamodel'
import { PromptElement, RadioElement } from '../prompt-lib/types'
import { PromptElement, RadioElement } from './types'
import { DatabaseCredentials, SchemaWithMetadata } from '../types'

export const dbTypeToDbPort: Record<DatabaseType, string> = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react'
import { Prompt } from '../../prompt-lib/BoxPrompt'
import { Prompt } from '../components/BoxPrompt'
import { PromptState } from '../InteractivePrompt'
import { ActionType } from '../reducer'
import { formByStep, Step } from '../steps-definition'
Expand Down
2 changes: 1 addition & 1 deletion cli/introspection/src/prompt/steps/2-input-credentials.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as React from 'react'
import { credentialsToUri, uriToCredentials } from '../../convertCredentials'
import { getConnectedConnectorFromCredentials, getDatabaseSchemasWithMetadata } from '../../introspect/util'
import { onFormChangedParams, OnSubmitParams, Prompt } from '../../prompt-lib/BoxPrompt'
import { onFormChangedParams, OnSubmitParams, Prompt } from '../components/BoxPrompt'
import { DatabaseCredentials } from '../../types'
import { dbTypeTodbName, defaultCredentials, PromptState } from '../InteractivePrompt'
import { ActionType } from '../reducer'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Box, Color } from 'ink'
import * as React from 'react'
import { credentialsToUri } from '../../convertCredentials'
import { ConnectorData, minimalPrettyTime } from '../../introspect/util'
import { OnSubmitParams, Prompt } from '../../prompt-lib/BoxPrompt'
import { OnSubmitParams, Prompt } from '../components/BoxPrompt'
import { DatabaseCredentials } from '../../types'
import { defaultCredentials, PromptProps, PromptState } from '../InteractivePrompt'
import { ActionType } from '../reducer'
Expand Down
2 changes: 1 addition & 1 deletion cli/introspection/src/prompt/steps/4-select-tool.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react'
import { Prompt } from '../../prompt-lib/BoxPrompt'
import { Prompt } from '../components/BoxPrompt'
import { PromptState } from '../InteractivePrompt'
import { ActionType } from '../reducer'
import { formByStep, Step } from '../steps-definition'
Expand Down
2 changes: 1 addition & 1 deletion cli/introspection/src/prompt/steps/5-select-language.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react'
import { Prompt } from '../../prompt-lib/BoxPrompt'
import { Prompt } from '../components/BoxPrompt'
import { ActionType } from '../reducer'
import { formByStep, Step } from '../steps-definition'

Expand Down
4 changes: 2 additions & 2 deletions cli/introspection/src/prompt/steps/6-select-template.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react'
import { Prompt } from '../../prompt-lib/BoxPrompt'
import { Prompt } from '../components/BoxPrompt'
import { InitPromptResult } from '../../types'
import { PromptProps, PromptState } from '../InteractivePrompt'
import { ActionType } from '../reducer'
Expand Down Expand Up @@ -39,7 +39,7 @@ export function renderSelectTemplate(
lift: state.lift,
photon: state.photon,
template: selectedTemplate,
databaseType: state.databaseType
databaseType: state.databaseType,
},
} as InitPromptResult)
}}
Expand Down
48 changes: 48 additions & 0 deletions cli/introspection/src/prompt/steps/Step0StarterVsBlank.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React from 'react'
import { Box, Color, Text } from 'ink'
import BorderBox from '../components/BorderBox'
import chalk from 'chalk'
import figures from 'figures'

export default class Step0StarterVsBlank extends React.Component {
render() {
return (
<Box flexDirection="column">
<Box flexDirection="column" marginLeft={2}>
<Text bold>Select the language for a starter kit or start with a blank project.</Text>
<Color dim>Starter kits provide ready-made setups for various use cases.</Color>
</Box>
<BorderBox flexDirection="column" title={chalk.bold('Languages for starter kits')} marginTop={1}>
<Box>
<Color cyan>
<Box width={14} marginRight={2}>
{figures.pointer} <Text bold>JavaScript</Text>
</Box>
<Color dim>GraphQL, REST, gRPC, ...</Color>
</Color>
</Box>
<Box>
<Box width={14} marginLeft={2}>
TypeScript
</Box>
<Color dim>GraphQL, REST, gRPC, ...</Color>
</Box>
<Box marginLeft={2}>
<Color dim>Go (Coming soon)</Color>
</Box>
<Box marginLeft={2} marginTop={1}>
<Color dim>Note: Starter kits only work with empty databases</Color>
</Box>
</BorderBox>
<BorderBox flexDirection="column" title={chalk.bold('Get started from scratch')} marginBottom={1} marginTop={1}>
<Box>
<Box width={15} marginLeft={2}>
Blank project
</Box>
<Color dim>Supports introspecting your existing DB</Color>
</Box>
</BorderBox>
</Box>
)
}
}
File renamed without changes.

0 comments on commit f0e6b7c

Please sign in to comment.