Skip to content

Commit

Permalink
chore(gatsby-cli) Migrate remaining files in reporters/logger/ink to …
Browse files Browse the repository at this point in the history
…Typscript (#22782)

* Migrate remaining files in gatsby-cli/reporters/logger/ink to TS

* Rename "IProps" to something more contextual
Extend interface parameter individually instead of using utility

* Clean up after merging the redux master changes

Co-authored-by: Blaine Kasten <blainekasten@gmail.com>
  • Loading branch information
arthurjdam and blainekasten authored Apr 21, 2020
1 parent 67730fd commit 8ee74c1
Show file tree
Hide file tree
Showing 11 changed files with 109 additions and 112 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,34 @@ import React from "react"
import { Box, Static } from "ink"
import { isTTY } from "../../../util/is-tty"
import { trackBuildError } from "gatsby-telemetry"

import { Spinner } from "../ink/components/spinner"
import { ProgressBar } from "../ink/components/progress-bar"
import { Message } from "../ink/components/messages"
import { Error } from "./components/error"
import Develop from "../ink/components/develop"
import { Spinner } from "./components/spinner"
import { ProgressBar } from "./components/progress-bar"
import { Message, IMessageProps } from "./components/messages"
import { Error as ErrorComponent } from "./components/error"
import Develop from "./components/develop"
import { IGatsbyCLIState, IActivity } from "../../redux/types"
import { ActivityLogLevels } from "../../constants"
import { IStructuredError } from "../../../structured-errors/types"

const showProgress = isTTY()

class CLI extends React.Component {
state = {
interface ICLIProps {
logs: IGatsbyCLIState
showStatusBar: boolean
}

interface ICLIState {
hasError: boolean
error?: Error
}

class CLI extends React.Component<ICLIProps, ICLIState> {
readonly state: ICLIState = {
hasError: false,
}
memoizedReactElementsForMessages: React.ReactElement[] = []

memoizedReactElementsForMessages = []

componentDidCatch(error, info) {
componentDidCatch(error: Error, info: React.ErrorInfo): void {
trackBuildError(`INK`, {
error: {
stack: info.componentStack,
Expand All @@ -28,24 +39,24 @@ class CLI extends React.Component {
})
}

static getDerivedStateFromError(error) {
static getDerivedStateFromError(error: Error): ICLIState {
return { hasError: true, error }
}

render() {
render(): React.ReactElement {
const {
logs: { messages, activities },
showStatusBar,
} = this.props

const { hasError, error } = this.state

if (hasError) {
if (hasError && error) {
// You can render any custom fallback UI
return (
<Box flexDirection="row">
<Message
level="ACTIVITY_FAILED"
level={ActivityLogLevels.Failed}
text={`We've encountered an error: ${error.message}`}
/>
</Box>
Expand All @@ -68,16 +79,16 @@ class CLI extends React.Component {
const msg = messages[index]
this.memoizedReactElementsForMessages.push(
msg.level === `ERROR` ? (
<Error details={msg} key={index} />
<ErrorComponent details={msg as IStructuredError} key={index} />
) : (
<Message key={index} {...msg} />
<Message key={index} {...(msg as IMessageProps)} />
)
)
}
}

const spinners = []
const progressBars = []
const spinners: Array<IActivity> = []
const progressBars: Array<IActivity> = []
if (showProgress) {
Object.keys(activities).forEach(activityName => {
const activity = activities[activityName]
Expand Down Expand Up @@ -106,9 +117,9 @@ class CLI extends React.Component {
<ProgressBar
key={activity.id}
message={activity.text}
total={activity.total}
current={activity.current}
startTime={activity.startTime}
total={activity.total || 0}
current={activity.current || 0}
startTime={activity.startTime || [0, 0]}
/>
))}
</Box>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,29 @@ import { Box, Color, StdoutContext } from "ink"
import StoreStateContext from "../context"

// Track the width and height of the terminal. Responsive app design baby!
const useTerminalResize = () => {
const useTerminalResize = (): Array<number> => {
const { stdout } = useContext(StdoutContext)
const [sizes, setSizes] = useState([stdout.columns, stdout.rows])
useEffect(() => {
stdout.on(`resize`, () => {
const resizeListener = (): void => {
setSizes([stdout.columns, stdout.rows])
})
return () => {
stdout.off(`resize`)
}
stdout.on(`resize`, resizeListener)
return (): void => {
stdout.off(`resize`, resizeListener)
}
}, [stdout])

return sizes
}

const mapConstantToStatus = {
IN_PROGRESS: `In Progress`,
NOT_STARTED: `Not Started`,
INTERRUPTED: `Interrupted`,
FAILED: `Failed`,
SUCCESS: `Success`,
CANCELLED: `Cancelled`,
interface IDevelopProps {
pagesCount: number
appName: string
status: string
}

const Develop = ({ pagesCount, appName, status }) => {
const Develop: React.FC<IDevelopProps> = ({ pagesCount, appName, status }) => {
const [width] = useTerminalResize()

return (
Expand All @@ -36,22 +34,22 @@ const Develop = ({ pagesCount, appName, status }) => {
<Box height={1} flexDirection="row">
<Color>{pagesCount} pages</Color>
<Box flexGrow={1} />
<Color>{mapConstantToStatus[status]}</Color>
<Color>{status}</Color>
<Box flexGrow={1} />
<Color>{appName}</Color>
</Box>
</Box>
)
}

const ConnectedDevelop = () => {
const ConnectedDevelop: React.FC = () => {
const state = useContext(StoreStateContext)

return (
<Develop
pagesCount={state.pages ? state.pages.size : 0}
appName={state.program ? state.program.sitePackageJson.name || `` : ``}
status={state.logs ? state.logs.status : ``}
pagesCount={state.pages?.size || 0}
appName={state.program?.sitePackageJson.name || ``}
status={state.logs?.status || ``}
/>
)
}
Expand Down
24 changes: 9 additions & 15 deletions packages/gatsby-cli/src/reporter/loggers/ink/components/error.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import React, { FunctionComponent } from "react"
import path from "path"
import { Color, Box } from "ink"
import { get } from "lodash"
import { IStructuredError } from "../../../../structured-errors/types"

interface IFileProps {
filePath: string
location: string
location: IStructuredError["location"]
}

const File: FunctionComponent<IFileProps> = ({ filePath, location }) => {
const lineNumber = get(location, `start.line`)
const lineNumber = location?.start.line

let locString = ``
if (typeof lineNumber !== `undefined`) {
locString += `:${lineNumber}`
const columnNumber = get(location, `start.column`)
const columnNumber = location?.start.column
if (typeof columnNumber !== `undefined`) {
locString += `:${columnNumber}`
}
Expand All @@ -28,8 +29,9 @@ const File: FunctionComponent<IFileProps> = ({ filePath, location }) => {
}

interface IDocsLinkProps {
docsUrl: string
docsUrl: string | undefined
}

const DocsLink: FunctionComponent<IDocsLinkProps> = ({ docsUrl }) => {
// TODO: when there's no specific docsUrl, add helpful message describing how
// to submit an issue
Expand All @@ -41,16 +43,8 @@ const DocsLink: FunctionComponent<IDocsLinkProps> = ({ docsUrl }) => {
)
}

interface IErrorProps {
details: {
level: string
code?: string
type?: string
text: string
filePath?: string
location: string
docsUrl: string
}
export interface IErrorProps {
details: IStructuredError
}

export const Error: FunctionComponent<IErrorProps> = React.memo(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,14 @@ const getLabel = (
}
}

interface IProps {
export interface IMessageProps {
level: ActivityLogLevels | LogLevels
text: string
duration: number
statusText: string
duration?: number
statusText?: string
}
export const Message = React.memo<IProps>(

export const Message = React.memo<IMessageProps>(
({ level, text, duration, statusText }) => {
let message = text
if (duration) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const minWidth = 10

const getLength = (prop: string | number): number => String(prop).length

interface IProps {
export interface IProgressbarProps {
message: string
current: number
total: number
Expand All @@ -19,7 +19,7 @@ export function ProgressBar({
current,
total,
startTime,
}: IProps): JSX.Element {
}: IProgressbarProps): JSX.Element {
const percentage = total ? Math.round((current / total) * 100) : 0
const terminalWidth = process.stdout.columns || 80
const availableWidth =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import React from "react"
import { Box } from "ink"
import InkSpinner from "ink-spinner"

interface IProps {
interface ISpinnerProps {
text: string
statusText?: string
}
export function Spinner({ text, statusText }: IProps): JSX.Element {
export function Spinner({ text, statusText }: ISpinnerProps): JSX.Element {
let label = text
if (statusText) {
label += ` — ${statusText}`
Expand Down
24 changes: 0 additions & 24 deletions packages/gatsby-cli/src/reporter/loggers/ink/context.js

This file was deleted.

35 changes: 35 additions & 0 deletions packages/gatsby-cli/src/reporter/loggers/ink/context.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React, { useState, useEffect, createContext } from "react"
import { getStore, onLogAction } from "../../redux"
import { IGatsbyState } from "gatsby/src/redux/types"

// These weird castings we are doing in this file is because the way gatsby-cli works is that it starts with it's own store
// but then quickly swaps it out with the store from the installed gatsby. This would benefit from a refactor later on
// to not use it's own store temporarily.
// By the time this is actually running, it will become an `IGatsbyState`
const StoreStateContext = createContext<IGatsbyState>(
(getStore().getState() as any) as IGatsbyState
)

export const StoreStateProvider: React.FC = ({
children,
}): React.ReactElement => {
const [state, setState] = useState(
(getStore().getState() as any) as IGatsbyState
)

useEffect(
() =>
onLogAction(() => {
setState((getStore().getState() as any) as IGatsbyState)
}),
[]
)

return (
<StoreStateContext.Provider value={state}>
{children}
</StoreStateContext.Provider>
)
}

export default StoreStateContext
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import React, { useContext } from "react"
import { render } from "ink"
import StoreStateContext, { StoreStateProvider } from "./context"

import CLI from "./cli"

const ConnectedCLI = () => {
const ConnectedCLI: React.FC = (): React.ReactElement => {
const state = useContext(StoreStateContext)
const showStatusBar =
state.program &&
state.program._ &&
state.program._[0] === `develop` &&
state.program.status === `BOOTSTRAP_FINISHED`
state.program?._?.[0] === `develop` &&
state.program?.status === `BOOTSTRAP_FINISHED`

return <CLI showStatusBar={Boolean(showStatusBar)} logs={state.logs} />
}
Expand Down
2 changes: 2 additions & 0 deletions packages/gatsby/src/commands/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ export interface ICert {
}

export interface IProgram {
_: `develop` | `build` | `clean` | `feedback` | `repl` | `serve`
status?: string // I think this type should not exist here. It seems to be added in the reducer, but not applicable to the caller site from gatsby-cli
useYarn: boolean
open: boolean
openTracingConfigFile: string
Expand Down
Loading

0 comments on commit 8ee74c1

Please sign in to comment.