@backstage/core-components 0.8.6 → 0.8.8-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -0
- package/dist/esm/{RealLogViewer-36241415.esm.js → RealLogViewer-e0ae55bd.esm.js} +2 -2
- package/dist/esm/{RealLogViewer-36241415.esm.js.map → RealLogViewer-e0ae55bd.esm.js.map} +1 -1
- package/dist/index.d.ts +13 -4
- package/dist/index.esm.js +90 -23
- package/dist/index.esm.js.map +1 -1
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# @backstage/core-components
|
|
2
2
|
|
|
3
|
+
## 0.8.8-next.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 8d785a0b1b: chore: bump `ansi-regex` from `5.0.1` to `6.0.1`
|
|
8
|
+
- f2dfbd3fb0: Adjust ErrorPage to accept optional supportUrl property to override app support config. Update type of additionalInfo property to be ReactNode to accept both string and component.
|
|
9
|
+
- d62bdb7a8e: The `ErrorPage` now falls back to using the default support configuration if the `ConfigApi` is not available.
|
|
10
|
+
|
|
11
|
+
## 0.8.7
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- f7257dff6f: The `<Link />` component now accepts a `noTrack` prop, which prevents the `click` event from being captured by the Analytics API. This can be used if tracking is explicitly not warranted, or in order to use custom link tracking in specific situations.
|
|
16
|
+
- 4c773ed25c: Change subtitle of Header style to use palette.bursts.fontColor
|
|
17
|
+
- f465b63b7f: Fix an issue where changes related to the `MobileSidebar` prevented scrolling pages. Additionally improve the menu of the `MobileSidebar` to not overlay the `BottomNavigation`.
|
|
18
|
+
- 064e750a50: Adding hover message to the Gauge and an info icon to the GaugeCard.
|
|
19
|
+
- a681cb9c2f: Make linkTarget configurable for MarkdownContent component
|
|
20
|
+
|
|
21
|
+
## 0.8.7-next.1
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- f7257dff6f: The `<Link />` component now accepts a `noTrack` prop, which prevents the `click` event from being captured by the Analytics API. This can be used if tracking is explicitly not warranted, or in order to use custom link tracking in specific situations.
|
|
26
|
+
|
|
27
|
+
## 0.8.7-next.0
|
|
28
|
+
|
|
29
|
+
### Patch Changes
|
|
30
|
+
|
|
31
|
+
- 4c773ed25c: Change subtitle of Header style to use palette.bursts.fontColor
|
|
32
|
+
- f465b63b7f: Fix an issue where changes related to the `MobileSidebar` prevented scrolling pages. Additionally improve the menu of the `MobileSidebar` to not overlay the `BottomNavigation`.
|
|
33
|
+
- a681cb9c2f: Make linkTarget configurable for MarkdownContent component
|
|
34
|
+
|
|
3
35
|
## 0.8.6
|
|
4
36
|
|
|
5
37
|
### Patch Changes
|
|
@@ -45,7 +45,7 @@ const codeModifiers = Object.fromEntries(Object.entries({
|
|
|
45
45
|
46: (m) => ({ ...m, background: "cyan" }),
|
|
46
46
|
47: (m) => ({ ...m, background: "white" }),
|
|
47
47
|
49: ({ background: _, ...m }) => m
|
|
48
|
-
}).map(([code, modifier]) => [
|
|
48
|
+
}).map(([code, modifier]) => [`\x1B[${code}m`, modifier]));
|
|
49
49
|
class AnsiLine {
|
|
50
50
|
constructor(lineNumber = 1, chunks = []) {
|
|
51
51
|
this.lineNumber = lineNumber;
|
|
@@ -552,4 +552,4 @@ function RealLogViewer(props) {
|
|
|
552
552
|
}
|
|
553
553
|
|
|
554
554
|
export { RealLogViewer };
|
|
555
|
-
//# sourceMappingURL=RealLogViewer-
|
|
555
|
+
//# sourceMappingURL=RealLogViewer-e0ae55bd.esm.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RealLogViewer-36241415.esm.js","sources":["../../src/components/LogViewer/AnsiProcessor.ts","../../src/components/LogViewer/styles.ts","../../src/components/LogViewer/LogLine.tsx","../../src/components/LogViewer/LogViewerControls.tsx","../../src/components/LogViewer/useLogViewerSearch.tsx","../../src/components/LogViewer/useLogViewerSelection.tsx","../../src/components/LogViewer/RealLogViewer.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport ansiRegexMaker from 'ansi-regex';\n\nconst ansiRegex = ansiRegexMaker();\nconst newlineRegex = /\\n\\r?/g;\n\n// A mapping of how each escape code changes the modifiers\nconst codeModifiers = Object.fromEntries(\n Object.entries({\n 1: m => ({ ...m, bold: true }),\n 3: m => ({ ...m, italic: true }),\n 4: m => ({ ...m, underline: true }),\n 22: ({ bold: _, ...m }) => m,\n 23: ({ italic: _, ...m }) => m,\n 24: ({ underline: _, ...m }) => m,\n 30: m => ({ ...m, foreground: 'black' }),\n 31: m => ({ ...m, foreground: 'red' }),\n 32: m => ({ ...m, foreground: 'green' }),\n 33: m => ({ ...m, foreground: 'yellow' }),\n 34: m => ({ ...m, foreground: 'blue' }),\n 35: m => ({ ...m, foreground: 'magenta' }),\n 36: m => ({ ...m, foreground: 'cyan' }),\n 37: m => ({ ...m, foreground: 'white' }),\n 39: ({ foreground: _, ...m }) => m,\n 90: m => ({ ...m, foreground: 'grey' }),\n 40: m => ({ ...m, background: 'black' }),\n 41: m => ({ ...m, background: 'red' }),\n 42: m => ({ ...m, background: 'green' }),\n 43: m => ({ ...m, background: 'yellow' }),\n 44: m => ({ ...m, background: 'blue' }),\n 45: m => ({ ...m, background: 'magenta' }),\n 46: m => ({ ...m, background: 'cyan' }),\n 47: m => ({ ...m, background: 'white' }),\n 49: ({ background: _, ...m }) => m,\n } as Record<string, (m: ChunkModifiers) => ChunkModifiers>).map(\n ([code, modifier]) => [`\\x1b[${code}m`, modifier],\n ),\n);\n\nexport type AnsiColor =\n | 'black'\n | 'red'\n | 'green'\n | 'yellow'\n | 'blue'\n | 'magenta'\n | 'cyan'\n | 'white'\n | 'grey';\n\nexport interface ChunkModifiers {\n foreground?: AnsiColor;\n background?: AnsiColor;\n bold?: boolean;\n italic?: boolean;\n underline?: boolean;\n}\n\nexport interface AnsiChunk {\n text: string;\n modifiers: ChunkModifiers;\n}\n\nexport class AnsiLine {\n text: string;\n\n constructor(\n readonly lineNumber: number = 1,\n readonly chunks: AnsiChunk[] = [],\n ) {\n this.text = chunks\n .map(c => c.text)\n .join('')\n .toLocaleLowerCase('en-US');\n }\n\n lastChunk(): AnsiChunk | undefined {\n return this.chunks[this.chunks.length - 1];\n }\n\n replaceLastChunk(newChunks?: AnsiChunk[]) {\n if (newChunks) {\n this.chunks.splice(this.chunks.length - 1, 1, ...newChunks);\n this.text = this.chunks\n .map(c => c.text)\n .join('')\n .toLocaleLowerCase('en-US');\n }\n }\n}\n\nexport class AnsiProcessor {\n private text: string = '';\n private lines: AnsiLine[] = [];\n\n /**\n * Processes a chunk of text while keeping internal state that optimizes\n * subsequent processing that appends to the text.\n */\n process(text: string): AnsiLine[] {\n if (this.text === text) {\n return this.lines;\n }\n\n if (text.startsWith(this.text)) {\n const lastLineIndex = this.lines.length > 0 ? this.lines.length - 1 : 0;\n const lastLine = this.lines[lastLineIndex] ?? new AnsiLine();\n const lastChunk = lastLine.lastChunk();\n\n const newLines = this.processLines(\n (lastChunk?.text ?? '') + text.slice(this.text.length),\n lastChunk?.modifiers,\n lastLine?.lineNumber,\n );\n lastLine.replaceLastChunk(newLines[0]?.chunks);\n\n this.lines[lastLineIndex] = lastLine;\n this.lines.push(...newLines.slice(1));\n } else {\n this.lines = this.processLines(text);\n }\n this.text = text;\n\n return this.lines;\n }\n\n // Split a chunk of text up into lines and process each line individually\n private processLines = (\n text: string,\n modifiers: ChunkModifiers = {},\n startingLineNumber: number = 1,\n ): AnsiLine[] => {\n const lines: AnsiLine[] = [];\n\n let currentModifiers = modifiers;\n let currentLineNumber = startingLineNumber;\n\n let prevIndex = 0;\n newlineRegex.lastIndex = 0;\n for (;;) {\n const match = newlineRegex.exec(text);\n if (!match) {\n const chunks = this.processText(\n text.slice(prevIndex),\n currentModifiers,\n );\n lines.push(new AnsiLine(currentLineNumber, chunks));\n return lines;\n }\n\n const line = text.slice(prevIndex, match.index);\n prevIndex = match.index + match[0].length;\n\n const chunks = this.processText(line, currentModifiers);\n lines.push(new AnsiLine(currentLineNumber, chunks));\n\n // Modifiers that are active in the last chunk are carried over to the next line\n currentModifiers =\n chunks[chunks.length - 1].modifiers ?? currentModifiers;\n currentLineNumber += 1;\n }\n };\n\n // Processing of a one individual text chunk\n private processText = (\n fullText: string,\n modifiers: ChunkModifiers,\n ): AnsiChunk[] => {\n const chunks: AnsiChunk[] = [];\n\n let currentModifiers = modifiers;\n\n let prevIndex = 0;\n ansiRegex.lastIndex = 0;\n for (;;) {\n const match = ansiRegex.exec(fullText);\n if (!match) {\n chunks.push({\n text: fullText.slice(prevIndex),\n modifiers: currentModifiers,\n });\n return chunks;\n }\n\n const text = fullText.slice(prevIndex, match.index);\n chunks.push({ text, modifiers: currentModifiers });\n\n // For every escape code that we encounter we keep track of where the\n // next chunk of text starts, and what modifiers it has\n prevIndex = match.index + match[0].length;\n currentModifiers = this.processCode(match[0], currentModifiers);\n }\n };\n\n private processCode = (\n code: string,\n modifiers: ChunkModifiers,\n ): ChunkModifiers => {\n return codeModifiers[code]?.(modifiers) ?? modifiers;\n };\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { alpha, makeStyles } from '@material-ui/core/styles';\nimport * as colors from '@material-ui/core/colors';\n\nexport const HEADER_SIZE = 40;\n\n/** @public Class keys for overriding LogViewer styles */\nexport type LogViewerClassKey =\n | 'root'\n | 'header'\n | 'log'\n | 'line'\n | 'lineSelected'\n | 'lineCopyButton'\n | 'lineNumber'\n | 'textHighlight'\n | 'textSelectedHighlight'\n | 'modifierBold'\n | 'modifierItalic'\n | 'modifierUnderline'\n | 'modifierForegroundBlack'\n | 'modifierForegroundRed'\n | 'modifierForegroundGreen'\n | 'modifierForegroundYellow'\n | 'modifierForegroundBlue'\n | 'modifierForegroundMagenta'\n | 'modifierForegroundCyan'\n | 'modifierForegroundWhite'\n | 'modifierForegroundGrey'\n | 'modifierBackgroundBlack'\n | 'modifierBackgroundRed'\n | 'modifierBackgroundGreen'\n | 'modifierBackgroundYellow'\n | 'modifierBackgroundBlue'\n | 'modifierBackgroundMagenta'\n | 'modifierBackgroundCyan'\n | 'modifierBackgroundWhite'\n | 'modifierBackgroundGrey';\n\nexport const useStyles = makeStyles(\n theme => ({\n root: {\n background: theme.palette.background.paper,\n },\n header: {\n height: HEADER_SIZE,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'flex-end',\n },\n log: {\n fontFamily: '\"Monaco\", monospace',\n fontSize: theme.typography.pxToRem(12),\n },\n line: {\n position: 'relative',\n whiteSpace: 'pre',\n\n '&:hover': {\n background: theme.palette.action.hover,\n },\n },\n lineSelected: {\n background: theme.palette.action.selected,\n\n '&:hover': {\n background: theme.palette.action.selected,\n },\n },\n lineCopyButton: {\n position: 'absolute',\n paddingTop: 0,\n paddingBottom: 0,\n },\n lineNumber: {\n display: 'inline-block',\n textAlign: 'end',\n width: 60,\n marginRight: theme.spacing(1),\n cursor: 'pointer',\n },\n textHighlight: {\n background: alpha(theme.palette.info.main, 0.15),\n },\n textSelectedHighlight: {\n background: alpha(theme.palette.info.main, 0.4),\n },\n modifierBold: {\n fontWeight: theme.typography.fontWeightBold,\n },\n modifierItalic: {\n fontStyle: 'italic',\n },\n modifierUnderline: {\n textDecoration: 'underline',\n },\n modifierForegroundBlack: {\n color: colors.common.black,\n },\n modifierForegroundRed: {\n color: colors.red[500],\n },\n modifierForegroundGreen: {\n color: colors.green[500],\n },\n modifierForegroundYellow: {\n color: colors.yellow[500],\n },\n modifierForegroundBlue: {\n color: colors.blue[500],\n },\n modifierForegroundMagenta: {\n color: colors.purple[500],\n },\n modifierForegroundCyan: {\n color: colors.cyan[500],\n },\n modifierForegroundWhite: {\n color: colors.common.white,\n },\n modifierForegroundGrey: {\n color: colors.grey[500],\n },\n modifierBackgroundBlack: {\n background: colors.common.black,\n },\n modifierBackgroundRed: {\n background: colors.red[500],\n },\n modifierBackgroundGreen: {\n background: colors.green[500],\n },\n modifierBackgroundYellow: {\n background: colors.yellow[500],\n },\n modifierBackgroundBlue: {\n background: colors.blue[500],\n },\n modifierBackgroundMagenta: {\n background: colors.purple[500],\n },\n modifierBackgroundCyan: {\n background: colors.cyan[500],\n },\n modifierBackgroundWhite: {\n background: colors.common.white,\n },\n modifierBackgroundGrey: {\n background: colors.grey[500],\n },\n }),\n { name: 'BackstageLogViewer' },\n);\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useMemo } from 'react';\nimport { AnsiChunk, AnsiLine, ChunkModifiers } from './AnsiProcessor';\nimport startCase from 'lodash/startCase';\nimport classnames from 'classnames';\nimport { useStyles } from './styles';\n\nexport function getModifierClasses(\n classes: ReturnType<typeof useStyles>,\n modifiers: ChunkModifiers,\n) {\n const classNames = new Array<string>();\n if (modifiers.bold) {\n classNames.push(classes.modifierBold);\n }\n if (modifiers.italic) {\n classNames.push(classes.modifierItalic);\n }\n if (modifiers.underline) {\n classNames.push(classes.modifierUnderline);\n }\n if (modifiers.foreground) {\n const key = `modifierForeground${startCase(\n modifiers.foreground,\n )}` as keyof typeof classes;\n classNames.push(classes[key]);\n }\n if (modifiers.background) {\n const key = `modifierBackground${startCase(\n modifiers.background,\n )}` as keyof typeof classes;\n classNames.push(classes[key]);\n }\n return classNames.length > 0 ? classNames.join(' ') : undefined;\n}\n\nexport function findSearchResults(text: string, searchText: string) {\n if (!searchText || !text.includes(searchText)) {\n return undefined;\n }\n const searchResults = new Array<{ start: number; end: number }>();\n let offset = 0;\n for (;;) {\n const start = text.indexOf(searchText, offset);\n if (start === -1) {\n break;\n }\n const end = start + searchText.length;\n searchResults.push({ start, end });\n offset = end;\n }\n return searchResults;\n}\n\nexport interface HighlightAnsiChunk extends AnsiChunk {\n highlight?: number;\n}\n\nexport function calculateHighlightedChunks(\n line: AnsiLine,\n searchText: string,\n): HighlightAnsiChunk[] {\n const results = findSearchResults(line.text, searchText);\n if (!results) {\n return line.chunks;\n }\n\n const chunks = new Array<HighlightAnsiChunk>();\n\n let lineOffset = 0;\n let resultIndex = 0;\n let result = results[resultIndex];\n for (const chunk of line.chunks) {\n const { text, modifiers } = chunk;\n if (!result || lineOffset + text.length < result.start) {\n chunks.push(chunk);\n lineOffset += text.length;\n continue;\n }\n\n let localOffset = 0;\n while (result) {\n const localStart = Math.max(result.start - lineOffset, 0);\n if (localStart > text.length) {\n break; // The next result is not in this chunk\n }\n\n const localEnd = Math.min(result.end - lineOffset, text.length);\n\n const hasTextBeforeResult = localStart > localOffset;\n if (hasTextBeforeResult) {\n chunks.push({ text: text.slice(localOffset, localStart), modifiers });\n }\n const hasResultText = localEnd > localStart;\n if (hasResultText) {\n chunks.push({\n modifiers,\n highlight: resultIndex,\n text: text.slice(localStart, localEnd),\n });\n }\n\n localOffset = localEnd;\n\n const foundCompleteResult = result.end - lineOffset === localEnd;\n if (foundCompleteResult) {\n resultIndex += 1;\n result = results[resultIndex];\n } else {\n break; // The rest of the result is in the following chunks\n }\n }\n\n const hasTextAfterResult = localOffset < text.length;\n if (hasTextAfterResult) {\n chunks.push({ text: text.slice(localOffset), modifiers });\n }\n\n lineOffset += text.length;\n }\n\n return chunks;\n}\n\nexport interface LogLineProps {\n line: AnsiLine;\n classes: ReturnType<typeof useStyles>;\n searchText: string;\n highlightResultIndex?: number;\n}\n\nexport function LogLine({\n line,\n classes,\n searchText,\n highlightResultIndex,\n}: LogLineProps) {\n const chunks = useMemo(\n () => calculateHighlightedChunks(line, searchText),\n [line, searchText],\n );\n\n const elements = useMemo(\n () =>\n chunks.map(({ text, modifiers, highlight }, index) => (\n <span\n key={index}\n className={classnames(\n getModifierClasses(classes, modifiers),\n highlight !== undefined &&\n (highlight === highlightResultIndex\n ? classes.textSelectedHighlight\n : classes.textHighlight),\n )}\n >\n {text}\n </span>\n )),\n [chunks, highlightResultIndex, classes],\n );\n\n return <>{elements}</>;\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport IconButton from '@material-ui/core/IconButton';\nimport TextField from '@material-ui/core/TextField';\nimport Typography from '@material-ui/core/Typography';\nimport ChevronLeftIcon from '@material-ui/icons/ChevronLeft';\nimport ChevronRightIcon from '@material-ui/icons/ChevronRight';\nimport FilterListIcon from '@material-ui/icons/FilterList';\nimport { LogViewerSearch } from './useLogViewerSearch';\n\nexport interface LogViewerControlsProps extends LogViewerSearch {}\n\nexport function LogViewerControls(props: LogViewerControlsProps) {\n const { resultCount, resultIndexStep, toggleShouldFilter } = props;\n const resultIndex = props.resultIndex ?? 0;\n\n const handleKeyPress = (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (event.key === 'Enter') {\n if (event.metaKey || event.ctrlKey || event.altKey) {\n toggleShouldFilter();\n } else {\n resultIndexStep(event.shiftKey);\n }\n }\n };\n\n return (\n <>\n {resultCount !== undefined && (\n <>\n <IconButton size=\"small\" onClick={() => resultIndexStep(true)}>\n <ChevronLeftIcon />\n </IconButton>\n <Typography>\n {Math.min(resultIndex + 1, resultCount)}/{resultCount}\n </Typography>\n <IconButton size=\"small\" onClick={() => resultIndexStep()}>\n <ChevronRightIcon />\n </IconButton>\n </>\n )}\n <TextField\n size=\"small\"\n variant=\"standard\"\n placeholder=\"Search\"\n value={props.searchInput}\n onKeyPress={handleKeyPress}\n onChange={e => props.setSearchInput(e.target.value)}\n />\n <IconButton size=\"small\" onClick={toggleShouldFilter}>\n {props.shouldFilter ? (\n <FilterListIcon color=\"primary\" />\n ) : (\n <FilterListIcon color=\"disabled\" />\n )}\n </IconButton>\n </>\n );\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useMemo, useState } from 'react';\nimport useToggle from 'react-use/lib/useToggle';\nimport { AnsiLine } from './AnsiProcessor';\n\nexport function applySearchFilter(lines: AnsiLine[], searchText: string) {\n if (!searchText) {\n return { lines };\n }\n\n const matchingLines = [];\n const searchResults = [];\n for (const line of lines) {\n if (line.text.includes(searchText)) {\n matchingLines.push(line);\n\n let offset = 0;\n let lineResultIndex = 0;\n for (;;) {\n const start = line.text.indexOf(searchText, offset);\n if (start === -1) {\n break;\n }\n searchResults.push({\n lineNumber: line.lineNumber,\n lineIndex: lineResultIndex++,\n });\n offset = start + searchText.length;\n }\n }\n }\n\n return {\n lines: matchingLines,\n results: searchResults,\n };\n}\n\nexport interface LogViewerSearch {\n lines: AnsiLine[];\n\n searchText: string;\n searchInput: string;\n setSearchInput: (searchInput: string) => void;\n\n shouldFilter: boolean;\n toggleShouldFilter: () => void;\n\n resultCount: number | undefined;\n resultIndex: number | undefined;\n resultIndexStep: (decrement?: boolean) => void;\n\n resultLine: number | undefined;\n resultLineIndex: number | undefined;\n}\n\nexport function useLogViewerSearch(lines: AnsiLine[]): LogViewerSearch {\n const [searchInput, setSearchInput] = useState('');\n const searchText = searchInput.toLocaleLowerCase('en-US');\n\n const [resultIndex, setResultIndex] = useState<number>(0);\n\n const [shouldFilter, toggleShouldFilter] = useToggle(false);\n\n const filter = useMemo(\n () => applySearchFilter(lines, searchText),\n [lines, searchText],\n );\n\n const searchResult = filter.results\n ? filter.results[Math.min(resultIndex, filter.results.length - 1)]\n : undefined;\n const resultCount = filter.results?.length;\n\n const resultIndexStep = (decrement?: boolean) => {\n if (decrement) {\n if (resultCount !== undefined) {\n const next = Math.min(resultIndex - 1, resultCount - 2);\n setResultIndex(next < 0 ? resultCount - 1 : next);\n }\n } else {\n if (resultCount !== undefined) {\n const next = resultIndex + 1;\n setResultIndex(next >= resultCount ? 0 : next);\n }\n }\n };\n\n return {\n lines: shouldFilter ? filter.lines : lines,\n searchText,\n searchInput,\n setSearchInput,\n shouldFilter,\n toggleShouldFilter,\n resultCount,\n resultIndex,\n resultIndexStep,\n resultLine: searchResult?.lineNumber,\n resultLineIndex: searchResult?.lineIndex,\n };\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { errorApiRef, useApi } from '@backstage/core-plugin-api';\nimport { useEffect, useState } from 'react';\nimport useCopyToClipboard from 'react-use/lib/useCopyToClipboard';\nimport { AnsiLine } from './AnsiProcessor';\n\nexport function useLogViewerSelection(lines: AnsiLine[]) {\n const errorApi = useApi(errorApiRef);\n const [sel, setSelection] = useState<{ start: number; end: number }>();\n const start = sel ? Math.min(sel.start, sel.end) : undefined;\n const end = sel ? Math.max(sel.start, sel.end) : undefined;\n\n const [{ error }, copyToClipboard] = useCopyToClipboard();\n\n useEffect(() => {\n if (error) {\n errorApi.post(error);\n }\n }, [error, errorApi]);\n\n return {\n shouldShowButton(line: number) {\n return start === line || end === line;\n },\n isSelected(line: number) {\n if (!sel) {\n return false;\n }\n return start! <= line && line <= end!;\n },\n setSelection(line: number, add: boolean) {\n if (add) {\n setSelection(s =>\n s ? { start: s.start, end: line } : { start: line, end: line },\n );\n } else {\n setSelection(s =>\n s?.start === line && s?.end === line\n ? undefined\n : { start: line, end: line },\n );\n }\n },\n copySelection() {\n if (sel) {\n const copyText = lines\n .slice(Math.min(sel.start, sel.end) - 1, Math.max(sel.start, sel.end))\n .map(l => l.chunks.map(c => c.text).join(''))\n .join('\\n');\n copyToClipboard(copyText);\n setSelection(undefined);\n }\n },\n };\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useEffect, useMemo, useRef } from 'react';\nimport IconButton from '@material-ui/core/IconButton';\nimport CopyIcon from '@material-ui/icons/FileCopy';\nimport AutoSizer from 'react-virtualized-auto-sizer';\nimport { FixedSizeList } from 'react-window';\nimport { AnsiProcessor } from './AnsiProcessor';\nimport { HEADER_SIZE, useStyles } from './styles';\nimport classnames from 'classnames';\nimport { LogLine } from './LogLine';\nimport { LogViewerControls } from './LogViewerControls';\nimport { useLogViewerSearch } from './useLogViewerSearch';\nimport { useLogViewerSelection } from './useLogViewerSelection';\n\nexport interface RealLogViewerProps {\n text: string;\n classes?: { root?: string };\n}\n\nexport function RealLogViewer(props: RealLogViewerProps) {\n const classes = useStyles({ classes: props.classes });\n const listRef = useRef<FixedSizeList | null>(null);\n\n // The processor keeps state that optimizes appending to the text\n const processor = useMemo(() => new AnsiProcessor(), []);\n const lines = processor.process(props.text);\n\n const search = useLogViewerSearch(lines);\n const selection = useLogViewerSelection(lines);\n\n useEffect(() => {\n if (search.resultLine !== undefined && listRef.current) {\n listRef.current.scrollToItem(search.resultLine - 1, 'center');\n }\n }, [search.resultLine]);\n\n const handleSelectLine = (\n line: number,\n event: { shiftKey: boolean; preventDefault: () => void },\n ) => {\n event.preventDefault();\n selection.setSelection(line, event.shiftKey);\n };\n\n return (\n <AutoSizer>\n {({ height, width }) => (\n <div style={{ width, height }} className={classes.root}>\n <div className={classes.header}>\n <LogViewerControls {...search} />\n </div>\n <FixedSizeList\n ref={listRef}\n className={classes.log}\n height={height - HEADER_SIZE}\n width={width}\n itemData={search.lines}\n itemSize={20}\n itemCount={search.lines.length}\n >\n {({ index, style, data }) => {\n const line = data[index];\n const { lineNumber } = line;\n return (\n <div\n style={{ ...style }}\n className={classnames(classes.line, {\n [classes.lineSelected]: selection.isSelected(lineNumber),\n })}\n >\n {selection.shouldShowButton(lineNumber) && (\n <IconButton\n data-testid=\"copy-button\"\n size=\"small\"\n className={classes.lineCopyButton}\n onClick={() => selection.copySelection()}\n >\n <CopyIcon fontSize=\"inherit\" />\n </IconButton>\n )}\n <a\n role=\"row\"\n target=\"_self\"\n href={`#line-${lineNumber}`}\n className={classes.lineNumber}\n onClick={event => handleSelectLine(lineNumber, event)}\n onKeyPress={event => handleSelectLine(lineNumber, event)}\n >\n {lineNumber}\n </a>\n <LogLine\n line={line}\n classes={classes}\n searchText={search.searchText}\n highlightResultIndex={\n search.resultLine === lineNumber\n ? search.resultLineIndex\n : undefined\n }\n />\n </div>\n );\n }}\n </FixedSizeList>\n </div>\n )}\n </AutoSizer>\n );\n}\n"],"names":["classnames","ChevronRightIcon","FilterListIcon"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"RealLogViewer-e0ae55bd.esm.js","sources":["../../src/components/LogViewer/AnsiProcessor.ts","../../src/components/LogViewer/styles.ts","../../src/components/LogViewer/LogLine.tsx","../../src/components/LogViewer/LogViewerControls.tsx","../../src/components/LogViewer/useLogViewerSearch.tsx","../../src/components/LogViewer/useLogViewerSelection.tsx","../../src/components/LogViewer/RealLogViewer.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport ansiRegexMaker from 'ansi-regex';\n\nconst ansiRegex = ansiRegexMaker();\nconst newlineRegex = /\\n\\r?/g;\n\n// A mapping of how each escape code changes the modifiers\nconst codeModifiers = Object.fromEntries(\n Object.entries({\n 1: m => ({ ...m, bold: true }),\n 3: m => ({ ...m, italic: true }),\n 4: m => ({ ...m, underline: true }),\n 22: ({ bold: _, ...m }) => m,\n 23: ({ italic: _, ...m }) => m,\n 24: ({ underline: _, ...m }) => m,\n 30: m => ({ ...m, foreground: 'black' }),\n 31: m => ({ ...m, foreground: 'red' }),\n 32: m => ({ ...m, foreground: 'green' }),\n 33: m => ({ ...m, foreground: 'yellow' }),\n 34: m => ({ ...m, foreground: 'blue' }),\n 35: m => ({ ...m, foreground: 'magenta' }),\n 36: m => ({ ...m, foreground: 'cyan' }),\n 37: m => ({ ...m, foreground: 'white' }),\n 39: ({ foreground: _, ...m }) => m,\n 90: m => ({ ...m, foreground: 'grey' }),\n 40: m => ({ ...m, background: 'black' }),\n 41: m => ({ ...m, background: 'red' }),\n 42: m => ({ ...m, background: 'green' }),\n 43: m => ({ ...m, background: 'yellow' }),\n 44: m => ({ ...m, background: 'blue' }),\n 45: m => ({ ...m, background: 'magenta' }),\n 46: m => ({ ...m, background: 'cyan' }),\n 47: m => ({ ...m, background: 'white' }),\n 49: ({ background: _, ...m }) => m,\n } as Record<string, (m: ChunkModifiers) => ChunkModifiers>).map(\n ([code, modifier]) => [`\\x1b[${code}m`, modifier],\n ),\n);\n\nexport type AnsiColor =\n | 'black'\n | 'red'\n | 'green'\n | 'yellow'\n | 'blue'\n | 'magenta'\n | 'cyan'\n | 'white'\n | 'grey';\n\nexport interface ChunkModifiers {\n foreground?: AnsiColor;\n background?: AnsiColor;\n bold?: boolean;\n italic?: boolean;\n underline?: boolean;\n}\n\nexport interface AnsiChunk {\n text: string;\n modifiers: ChunkModifiers;\n}\n\nexport class AnsiLine {\n text: string;\n\n constructor(\n readonly lineNumber: number = 1,\n readonly chunks: AnsiChunk[] = [],\n ) {\n this.text = chunks\n .map(c => c.text)\n .join('')\n .toLocaleLowerCase('en-US');\n }\n\n lastChunk(): AnsiChunk | undefined {\n return this.chunks[this.chunks.length - 1];\n }\n\n replaceLastChunk(newChunks?: AnsiChunk[]) {\n if (newChunks) {\n this.chunks.splice(this.chunks.length - 1, 1, ...newChunks);\n this.text = this.chunks\n .map(c => c.text)\n .join('')\n .toLocaleLowerCase('en-US');\n }\n }\n}\n\nexport class AnsiProcessor {\n private text: string = '';\n private lines: AnsiLine[] = [];\n\n /**\n * Processes a chunk of text while keeping internal state that optimizes\n * subsequent processing that appends to the text.\n */\n process(text: string): AnsiLine[] {\n if (this.text === text) {\n return this.lines;\n }\n\n if (text.startsWith(this.text)) {\n const lastLineIndex = this.lines.length > 0 ? this.lines.length - 1 : 0;\n const lastLine = this.lines[lastLineIndex] ?? new AnsiLine();\n const lastChunk = lastLine.lastChunk();\n\n const newLines = this.processLines(\n (lastChunk?.text ?? '') + text.slice(this.text.length),\n lastChunk?.modifiers,\n lastLine?.lineNumber,\n );\n lastLine.replaceLastChunk(newLines[0]?.chunks);\n\n this.lines[lastLineIndex] = lastLine;\n this.lines.push(...newLines.slice(1));\n } else {\n this.lines = this.processLines(text);\n }\n this.text = text;\n\n return this.lines;\n }\n\n // Split a chunk of text up into lines and process each line individually\n private processLines = (\n text: string,\n modifiers: ChunkModifiers = {},\n startingLineNumber: number = 1,\n ): AnsiLine[] => {\n const lines: AnsiLine[] = [];\n\n let currentModifiers = modifiers;\n let currentLineNumber = startingLineNumber;\n\n let prevIndex = 0;\n newlineRegex.lastIndex = 0;\n for (;;) {\n const match = newlineRegex.exec(text);\n if (!match) {\n const chunks = this.processText(\n text.slice(prevIndex),\n currentModifiers,\n );\n lines.push(new AnsiLine(currentLineNumber, chunks));\n return lines;\n }\n\n const line = text.slice(prevIndex, match.index);\n prevIndex = match.index + match[0].length;\n\n const chunks = this.processText(line, currentModifiers);\n lines.push(new AnsiLine(currentLineNumber, chunks));\n\n // Modifiers that are active in the last chunk are carried over to the next line\n currentModifiers =\n chunks[chunks.length - 1].modifiers ?? currentModifiers;\n currentLineNumber += 1;\n }\n };\n\n // Processing of a one individual text chunk\n private processText = (\n fullText: string,\n modifiers: ChunkModifiers,\n ): AnsiChunk[] => {\n const chunks: AnsiChunk[] = [];\n\n let currentModifiers = modifiers;\n\n let prevIndex = 0;\n ansiRegex.lastIndex = 0;\n for (;;) {\n const match = ansiRegex.exec(fullText);\n if (!match) {\n chunks.push({\n text: fullText.slice(prevIndex),\n modifiers: currentModifiers,\n });\n return chunks;\n }\n\n const text = fullText.slice(prevIndex, match.index);\n chunks.push({ text, modifiers: currentModifiers });\n\n // For every escape code that we encounter we keep track of where the\n // next chunk of text starts, and what modifiers it has\n prevIndex = match.index + match[0].length;\n currentModifiers = this.processCode(match[0], currentModifiers);\n }\n };\n\n private processCode = (\n code: string,\n modifiers: ChunkModifiers,\n ): ChunkModifiers => {\n return codeModifiers[code]?.(modifiers) ?? modifiers;\n };\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { alpha, makeStyles } from '@material-ui/core/styles';\nimport * as colors from '@material-ui/core/colors';\n\nexport const HEADER_SIZE = 40;\n\n/** @public Class keys for overriding LogViewer styles */\nexport type LogViewerClassKey =\n | 'root'\n | 'header'\n | 'log'\n | 'line'\n | 'lineSelected'\n | 'lineCopyButton'\n | 'lineNumber'\n | 'textHighlight'\n | 'textSelectedHighlight'\n | 'modifierBold'\n | 'modifierItalic'\n | 'modifierUnderline'\n | 'modifierForegroundBlack'\n | 'modifierForegroundRed'\n | 'modifierForegroundGreen'\n | 'modifierForegroundYellow'\n | 'modifierForegroundBlue'\n | 'modifierForegroundMagenta'\n | 'modifierForegroundCyan'\n | 'modifierForegroundWhite'\n | 'modifierForegroundGrey'\n | 'modifierBackgroundBlack'\n | 'modifierBackgroundRed'\n | 'modifierBackgroundGreen'\n | 'modifierBackgroundYellow'\n | 'modifierBackgroundBlue'\n | 'modifierBackgroundMagenta'\n | 'modifierBackgroundCyan'\n | 'modifierBackgroundWhite'\n | 'modifierBackgroundGrey';\n\nexport const useStyles = makeStyles(\n theme => ({\n root: {\n background: theme.palette.background.paper,\n },\n header: {\n height: HEADER_SIZE,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'flex-end',\n },\n log: {\n fontFamily: '\"Monaco\", monospace',\n fontSize: theme.typography.pxToRem(12),\n },\n line: {\n position: 'relative',\n whiteSpace: 'pre',\n\n '&:hover': {\n background: theme.palette.action.hover,\n },\n },\n lineSelected: {\n background: theme.palette.action.selected,\n\n '&:hover': {\n background: theme.palette.action.selected,\n },\n },\n lineCopyButton: {\n position: 'absolute',\n paddingTop: 0,\n paddingBottom: 0,\n },\n lineNumber: {\n display: 'inline-block',\n textAlign: 'end',\n width: 60,\n marginRight: theme.spacing(1),\n cursor: 'pointer',\n },\n textHighlight: {\n background: alpha(theme.palette.info.main, 0.15),\n },\n textSelectedHighlight: {\n background: alpha(theme.palette.info.main, 0.4),\n },\n modifierBold: {\n fontWeight: theme.typography.fontWeightBold,\n },\n modifierItalic: {\n fontStyle: 'italic',\n },\n modifierUnderline: {\n textDecoration: 'underline',\n },\n modifierForegroundBlack: {\n color: colors.common.black,\n },\n modifierForegroundRed: {\n color: colors.red[500],\n },\n modifierForegroundGreen: {\n color: colors.green[500],\n },\n modifierForegroundYellow: {\n color: colors.yellow[500],\n },\n modifierForegroundBlue: {\n color: colors.blue[500],\n },\n modifierForegroundMagenta: {\n color: colors.purple[500],\n },\n modifierForegroundCyan: {\n color: colors.cyan[500],\n },\n modifierForegroundWhite: {\n color: colors.common.white,\n },\n modifierForegroundGrey: {\n color: colors.grey[500],\n },\n modifierBackgroundBlack: {\n background: colors.common.black,\n },\n modifierBackgroundRed: {\n background: colors.red[500],\n },\n modifierBackgroundGreen: {\n background: colors.green[500],\n },\n modifierBackgroundYellow: {\n background: colors.yellow[500],\n },\n modifierBackgroundBlue: {\n background: colors.blue[500],\n },\n modifierBackgroundMagenta: {\n background: colors.purple[500],\n },\n modifierBackgroundCyan: {\n background: colors.cyan[500],\n },\n modifierBackgroundWhite: {\n background: colors.common.white,\n },\n modifierBackgroundGrey: {\n background: colors.grey[500],\n },\n }),\n { name: 'BackstageLogViewer' },\n);\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useMemo } from 'react';\nimport { AnsiChunk, AnsiLine, ChunkModifiers } from './AnsiProcessor';\nimport startCase from 'lodash/startCase';\nimport classnames from 'classnames';\nimport { useStyles } from './styles';\n\nexport function getModifierClasses(\n classes: ReturnType<typeof useStyles>,\n modifiers: ChunkModifiers,\n) {\n const classNames = new Array<string>();\n if (modifiers.bold) {\n classNames.push(classes.modifierBold);\n }\n if (modifiers.italic) {\n classNames.push(classes.modifierItalic);\n }\n if (modifiers.underline) {\n classNames.push(classes.modifierUnderline);\n }\n if (modifiers.foreground) {\n const key = `modifierForeground${startCase(\n modifiers.foreground,\n )}` as keyof typeof classes;\n classNames.push(classes[key]);\n }\n if (modifiers.background) {\n const key = `modifierBackground${startCase(\n modifiers.background,\n )}` as keyof typeof classes;\n classNames.push(classes[key]);\n }\n return classNames.length > 0 ? classNames.join(' ') : undefined;\n}\n\nexport function findSearchResults(text: string, searchText: string) {\n if (!searchText || !text.includes(searchText)) {\n return undefined;\n }\n const searchResults = new Array<{ start: number; end: number }>();\n let offset = 0;\n for (;;) {\n const start = text.indexOf(searchText, offset);\n if (start === -1) {\n break;\n }\n const end = start + searchText.length;\n searchResults.push({ start, end });\n offset = end;\n }\n return searchResults;\n}\n\nexport interface HighlightAnsiChunk extends AnsiChunk {\n highlight?: number;\n}\n\nexport function calculateHighlightedChunks(\n line: AnsiLine,\n searchText: string,\n): HighlightAnsiChunk[] {\n const results = findSearchResults(line.text, searchText);\n if (!results) {\n return line.chunks;\n }\n\n const chunks = new Array<HighlightAnsiChunk>();\n\n let lineOffset = 0;\n let resultIndex = 0;\n let result = results[resultIndex];\n for (const chunk of line.chunks) {\n const { text, modifiers } = chunk;\n if (!result || lineOffset + text.length < result.start) {\n chunks.push(chunk);\n lineOffset += text.length;\n continue;\n }\n\n let localOffset = 0;\n while (result) {\n const localStart = Math.max(result.start - lineOffset, 0);\n if (localStart > text.length) {\n break; // The next result is not in this chunk\n }\n\n const localEnd = Math.min(result.end - lineOffset, text.length);\n\n const hasTextBeforeResult = localStart > localOffset;\n if (hasTextBeforeResult) {\n chunks.push({ text: text.slice(localOffset, localStart), modifiers });\n }\n const hasResultText = localEnd > localStart;\n if (hasResultText) {\n chunks.push({\n modifiers,\n highlight: resultIndex,\n text: text.slice(localStart, localEnd),\n });\n }\n\n localOffset = localEnd;\n\n const foundCompleteResult = result.end - lineOffset === localEnd;\n if (foundCompleteResult) {\n resultIndex += 1;\n result = results[resultIndex];\n } else {\n break; // The rest of the result is in the following chunks\n }\n }\n\n const hasTextAfterResult = localOffset < text.length;\n if (hasTextAfterResult) {\n chunks.push({ text: text.slice(localOffset), modifiers });\n }\n\n lineOffset += text.length;\n }\n\n return chunks;\n}\n\nexport interface LogLineProps {\n line: AnsiLine;\n classes: ReturnType<typeof useStyles>;\n searchText: string;\n highlightResultIndex?: number;\n}\n\nexport function LogLine({\n line,\n classes,\n searchText,\n highlightResultIndex,\n}: LogLineProps) {\n const chunks = useMemo(\n () => calculateHighlightedChunks(line, searchText),\n [line, searchText],\n );\n\n const elements = useMemo(\n () =>\n chunks.map(({ text, modifiers, highlight }, index) => (\n <span\n key={index}\n className={classnames(\n getModifierClasses(classes, modifiers),\n highlight !== undefined &&\n (highlight === highlightResultIndex\n ? classes.textSelectedHighlight\n : classes.textHighlight),\n )}\n >\n {text}\n </span>\n )),\n [chunks, highlightResultIndex, classes],\n );\n\n return <>{elements}</>;\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport IconButton from '@material-ui/core/IconButton';\nimport TextField from '@material-ui/core/TextField';\nimport Typography from '@material-ui/core/Typography';\nimport ChevronLeftIcon from '@material-ui/icons/ChevronLeft';\nimport ChevronRightIcon from '@material-ui/icons/ChevronRight';\nimport FilterListIcon from '@material-ui/icons/FilterList';\nimport { LogViewerSearch } from './useLogViewerSearch';\n\nexport interface LogViewerControlsProps extends LogViewerSearch {}\n\nexport function LogViewerControls(props: LogViewerControlsProps) {\n const { resultCount, resultIndexStep, toggleShouldFilter } = props;\n const resultIndex = props.resultIndex ?? 0;\n\n const handleKeyPress = (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (event.key === 'Enter') {\n if (event.metaKey || event.ctrlKey || event.altKey) {\n toggleShouldFilter();\n } else {\n resultIndexStep(event.shiftKey);\n }\n }\n };\n\n return (\n <>\n {resultCount !== undefined && (\n <>\n <IconButton size=\"small\" onClick={() => resultIndexStep(true)}>\n <ChevronLeftIcon />\n </IconButton>\n <Typography>\n {Math.min(resultIndex + 1, resultCount)}/{resultCount}\n </Typography>\n <IconButton size=\"small\" onClick={() => resultIndexStep()}>\n <ChevronRightIcon />\n </IconButton>\n </>\n )}\n <TextField\n size=\"small\"\n variant=\"standard\"\n placeholder=\"Search\"\n value={props.searchInput}\n onKeyPress={handleKeyPress}\n onChange={e => props.setSearchInput(e.target.value)}\n />\n <IconButton size=\"small\" onClick={toggleShouldFilter}>\n {props.shouldFilter ? (\n <FilterListIcon color=\"primary\" />\n ) : (\n <FilterListIcon color=\"disabled\" />\n )}\n </IconButton>\n </>\n );\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useMemo, useState } from 'react';\nimport useToggle from 'react-use/lib/useToggle';\nimport { AnsiLine } from './AnsiProcessor';\n\nexport function applySearchFilter(lines: AnsiLine[], searchText: string) {\n if (!searchText) {\n return { lines };\n }\n\n const matchingLines = [];\n const searchResults = [];\n for (const line of lines) {\n if (line.text.includes(searchText)) {\n matchingLines.push(line);\n\n let offset = 0;\n let lineResultIndex = 0;\n for (;;) {\n const start = line.text.indexOf(searchText, offset);\n if (start === -1) {\n break;\n }\n searchResults.push({\n lineNumber: line.lineNumber,\n lineIndex: lineResultIndex++,\n });\n offset = start + searchText.length;\n }\n }\n }\n\n return {\n lines: matchingLines,\n results: searchResults,\n };\n}\n\nexport interface LogViewerSearch {\n lines: AnsiLine[];\n\n searchText: string;\n searchInput: string;\n setSearchInput: (searchInput: string) => void;\n\n shouldFilter: boolean;\n toggleShouldFilter: () => void;\n\n resultCount: number | undefined;\n resultIndex: number | undefined;\n resultIndexStep: (decrement?: boolean) => void;\n\n resultLine: number | undefined;\n resultLineIndex: number | undefined;\n}\n\nexport function useLogViewerSearch(lines: AnsiLine[]): LogViewerSearch {\n const [searchInput, setSearchInput] = useState('');\n const searchText = searchInput.toLocaleLowerCase('en-US');\n\n const [resultIndex, setResultIndex] = useState<number>(0);\n\n const [shouldFilter, toggleShouldFilter] = useToggle(false);\n\n const filter = useMemo(\n () => applySearchFilter(lines, searchText),\n [lines, searchText],\n );\n\n const searchResult = filter.results\n ? filter.results[Math.min(resultIndex, filter.results.length - 1)]\n : undefined;\n const resultCount = filter.results?.length;\n\n const resultIndexStep = (decrement?: boolean) => {\n if (decrement) {\n if (resultCount !== undefined) {\n const next = Math.min(resultIndex - 1, resultCount - 2);\n setResultIndex(next < 0 ? resultCount - 1 : next);\n }\n } else {\n if (resultCount !== undefined) {\n const next = resultIndex + 1;\n setResultIndex(next >= resultCount ? 0 : next);\n }\n }\n };\n\n return {\n lines: shouldFilter ? filter.lines : lines,\n searchText,\n searchInput,\n setSearchInput,\n shouldFilter,\n toggleShouldFilter,\n resultCount,\n resultIndex,\n resultIndexStep,\n resultLine: searchResult?.lineNumber,\n resultLineIndex: searchResult?.lineIndex,\n };\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { errorApiRef, useApi } from '@backstage/core-plugin-api';\nimport { useEffect, useState } from 'react';\nimport useCopyToClipboard from 'react-use/lib/useCopyToClipboard';\nimport { AnsiLine } from './AnsiProcessor';\n\nexport function useLogViewerSelection(lines: AnsiLine[]) {\n const errorApi = useApi(errorApiRef);\n const [sel, setSelection] = useState<{ start: number; end: number }>();\n const start = sel ? Math.min(sel.start, sel.end) : undefined;\n const end = sel ? Math.max(sel.start, sel.end) : undefined;\n\n const [{ error }, copyToClipboard] = useCopyToClipboard();\n\n useEffect(() => {\n if (error) {\n errorApi.post(error);\n }\n }, [error, errorApi]);\n\n return {\n shouldShowButton(line: number) {\n return start === line || end === line;\n },\n isSelected(line: number) {\n if (!sel) {\n return false;\n }\n return start! <= line && line <= end!;\n },\n setSelection(line: number, add: boolean) {\n if (add) {\n setSelection(s =>\n s ? { start: s.start, end: line } : { start: line, end: line },\n );\n } else {\n setSelection(s =>\n s?.start === line && s?.end === line\n ? undefined\n : { start: line, end: line },\n );\n }\n },\n copySelection() {\n if (sel) {\n const copyText = lines\n .slice(Math.min(sel.start, sel.end) - 1, Math.max(sel.start, sel.end))\n .map(l => l.chunks.map(c => c.text).join(''))\n .join('\\n');\n copyToClipboard(copyText);\n setSelection(undefined);\n }\n },\n };\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useEffect, useMemo, useRef } from 'react';\nimport IconButton from '@material-ui/core/IconButton';\nimport CopyIcon from '@material-ui/icons/FileCopy';\nimport AutoSizer from 'react-virtualized-auto-sizer';\nimport { FixedSizeList } from 'react-window';\nimport { AnsiProcessor } from './AnsiProcessor';\nimport { HEADER_SIZE, useStyles } from './styles';\nimport classnames from 'classnames';\nimport { LogLine } from './LogLine';\nimport { LogViewerControls } from './LogViewerControls';\nimport { useLogViewerSearch } from './useLogViewerSearch';\nimport { useLogViewerSelection } from './useLogViewerSelection';\n\nexport interface RealLogViewerProps {\n text: string;\n classes?: { root?: string };\n}\n\nexport function RealLogViewer(props: RealLogViewerProps) {\n const classes = useStyles({ classes: props.classes });\n const listRef = useRef<FixedSizeList | null>(null);\n\n // The processor keeps state that optimizes appending to the text\n const processor = useMemo(() => new AnsiProcessor(), []);\n const lines = processor.process(props.text);\n\n const search = useLogViewerSearch(lines);\n const selection = useLogViewerSelection(lines);\n\n useEffect(() => {\n if (search.resultLine !== undefined && listRef.current) {\n listRef.current.scrollToItem(search.resultLine - 1, 'center');\n }\n }, [search.resultLine]);\n\n const handleSelectLine = (\n line: number,\n event: { shiftKey: boolean; preventDefault: () => void },\n ) => {\n event.preventDefault();\n selection.setSelection(line, event.shiftKey);\n };\n\n return (\n <AutoSizer>\n {({ height, width }) => (\n <div style={{ width, height }} className={classes.root}>\n <div className={classes.header}>\n <LogViewerControls {...search} />\n </div>\n <FixedSizeList\n ref={listRef}\n className={classes.log}\n height={height - HEADER_SIZE}\n width={width}\n itemData={search.lines}\n itemSize={20}\n itemCount={search.lines.length}\n >\n {({ index, style, data }) => {\n const line = data[index];\n const { lineNumber } = line;\n return (\n <div\n style={{ ...style }}\n className={classnames(classes.line, {\n [classes.lineSelected]: selection.isSelected(lineNumber),\n })}\n >\n {selection.shouldShowButton(lineNumber) && (\n <IconButton\n data-testid=\"copy-button\"\n size=\"small\"\n className={classes.lineCopyButton}\n onClick={() => selection.copySelection()}\n >\n <CopyIcon fontSize=\"inherit\" />\n </IconButton>\n )}\n <a\n role=\"row\"\n target=\"_self\"\n href={`#line-${lineNumber}`}\n className={classes.lineNumber}\n onClick={event => handleSelectLine(lineNumber, event)}\n onKeyPress={event => handleSelectLine(lineNumber, event)}\n >\n {lineNumber}\n </a>\n <LogLine\n line={line}\n classes={classes}\n searchText={search.searchText}\n highlightResultIndex={\n search.resultLine === lineNumber\n ? search.resultLineIndex\n : undefined\n }\n />\n </div>\n );\n }}\n </FixedSizeList>\n </div>\n )}\n </AutoSizer>\n );\n}\n"],"names":["classnames","ChevronRightIcon","FilterListIcon"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { ButtonProps as ButtonProps$1 } from '@material-ui/core/Button';
|
|
|
5
5
|
import { LinkProps as LinkProps$1 } from '@material-ui/core/Link';
|
|
6
6
|
import { LinkProps as LinkProps$2, NavLinkProps } from 'react-router-dom';
|
|
7
7
|
import CSS from 'csstype';
|
|
8
|
+
import { Options } from 'react-markdown';
|
|
8
9
|
import { TooltipProps } from '@material-ui/core/Tooltip';
|
|
9
10
|
import { TextTruncateProps } from 'react-text-truncate';
|
|
10
11
|
import { LinearProgressProps } from '@material-ui/core/LinearProgress';
|
|
@@ -65,13 +66,14 @@ declare function Avatar(props: AvatarProps): JSX.Element;
|
|
|
65
66
|
|
|
66
67
|
declare type LinkProps = LinkProps$1 & LinkProps$2 & {
|
|
67
68
|
component?: ElementType<any>;
|
|
69
|
+
noTrack?: boolean;
|
|
68
70
|
};
|
|
69
71
|
/**
|
|
70
72
|
* Thin wrapper on top of material-ui's Link component, which...
|
|
71
73
|
* - Makes the Link use react-router
|
|
72
74
|
* - Captures Link clicks as analytics events.
|
|
73
75
|
*/
|
|
74
|
-
declare const ActualLink: React__default.ForwardRefExoticComponent<Pick<LinkProps, "replace" | "type" | "key" | "id" | "media" | "state" | "color" | "display" | "translate" | "hidden" | "dir" | "slot" | "style" | "title" | "target" | "accessKey" | "draggable" | "lang" | "className" | "prefix" | "children" | "contentEditable" | "inputMode" | "tabIndex" | "underline" | "download" | "href" | "hrefLang" | "defaultChecked" | "defaultValue" | "suppressContentEditableWarning" | "suppressHydrationWarning" | "contextMenu" | "placeholder" | "spellCheck" | "radioGroup" | "role" | "about" | "datatype" | "inlist" | "property" | "resource" | "typeof" | "vocab" | "autoCapitalize" | "autoCorrect" | "autoSave" | "itemProp" | "itemScope" | "itemType" | "itemID" | "itemRef" | "results" | "security" | "unselectable" | "is" | "aria-activedescendant" | "aria-atomic" | "aria-autocomplete" | "aria-busy" | "aria-checked" | "aria-colcount" | "aria-colindex" | "aria-colspan" | "aria-controls" | "aria-current" | "aria-describedby" | "aria-details" | "aria-disabled" | "aria-dropeffect" | "aria-errormessage" | "aria-expanded" | "aria-flowto" | "aria-grabbed" | "aria-haspopup" | "aria-hidden" | "aria-invalid" | "aria-keyshortcuts" | "aria-label" | "aria-labelledby" | "aria-level" | "aria-live" | "aria-modal" | "aria-multiline" | "aria-multiselectable" | "aria-orientation" | "aria-owns" | "aria-placeholder" | "aria-posinset" | "aria-pressed" | "aria-readonly" | "aria-relevant" | "aria-required" | "aria-roledescription" | "aria-rowcount" | "aria-rowindex" | "aria-rowspan" | "aria-selected" | "aria-setsize" | "aria-sort" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "to" | "rel" | "dangerouslySetInnerHTML" | "onCopy" | "onCopyCapture" | "onCut" | "onCutCapture" | "onPaste" | "onPasteCapture" | "onCompositionEnd" | "onCompositionEndCapture" | "onCompositionStart" | "onCompositionStartCapture" | "onCompositionUpdate" | "onCompositionUpdateCapture" | "onFocus" | "onFocusCapture" | "onBlur" | "onBlurCapture" | "onChange" | "onChangeCapture" | "onBeforeInput" | "onBeforeInputCapture" | "onInput" | "onInputCapture" | "onReset" | "onResetCapture" | "onSubmit" | "onSubmitCapture" | "onInvalid" | "onInvalidCapture" | "onLoad" | "onLoadCapture" | "onError" | "onErrorCapture" | "onKeyDown" | "onKeyDownCapture" | "onKeyPress" | "onKeyPressCapture" | "onKeyUp" | "onKeyUpCapture" | "onAbort" | "onAbortCapture" | "onCanPlay" | "onCanPlayCapture" | "onCanPlayThrough" | "onCanPlayThroughCapture" | "onDurationChange" | "onDurationChangeCapture" | "onEmptied" | "onEmptiedCapture" | "onEncrypted" | "onEncryptedCapture" | "onEnded" | "onEndedCapture" | "onLoadedData" | "onLoadedDataCapture" | "onLoadedMetadata" | "onLoadedMetadataCapture" | "onLoadStart" | "onLoadStartCapture" | "onPause" | "onPauseCapture" | "onPlay" | "onPlayCapture" | "onPlaying" | "onPlayingCapture" | "onProgress" | "onProgressCapture" | "onRateChange" | "onRateChangeCapture" | "onSeeked" | "onSeekedCapture" | "onSeeking" | "onSeekingCapture" | "onStalled" | "onStalledCapture" | "onSuspend" | "onSuspendCapture" | "onTimeUpdate" | "onTimeUpdateCapture" | "onVolumeChange" | "onVolumeChangeCapture" | "onWaiting" | "onWaitingCapture" | "onAuxClick" | "onAuxClickCapture" | "onClick" | "onClickCapture" | "onContextMenu" | "onContextMenuCapture" | "onDoubleClick" | "onDoubleClickCapture" | "onDrag" | "onDragCapture" | "onDragEnd" | "onDragEndCapture" | "onDragEnter" | "onDragEnterCapture" | "onDragExit" | "onDragExitCapture" | "onDragLeave" | "onDragLeaveCapture" | "onDragOver" | "onDragOverCapture" | "onDragStart" | "onDragStartCapture" | "onDrop" | "onDropCapture" | "onMouseDown" | "onMouseDownCapture" | "onMouseEnter" | "onMouseLeave" | "onMouseMove" | "onMouseMoveCapture" | "onMouseOut" | "onMouseOutCapture" | "onMouseOver" | "onMouseOverCapture" | "onMouseUp" | "onMouseUpCapture" | "onSelect" | "onSelectCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerMove" | "onPointerMoveCapture" | "onPointerUp" | "onPointerUpCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerEnter" | "onPointerEnterCapture" | "onPointerLeave" | "onPointerLeaveCapture" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onScroll" | "onScrollCapture" | "onWheel" | "onWheelCapture" | "onAnimationStart" | "onAnimationStartCapture" | "onAnimationEnd" | "onAnimationEndCapture" | "onAnimationIteration" | "onAnimationIterationCapture" | "onTransitionEnd" | "onTransitionEndCapture" | "ping" | "referrerPolicy" | "align" | "variant" | "component" | "classes" | "innerRef" | "noWrap" | "gutterBottom" | "paragraph" | "variantMapping" | "TypographyClasses"> & React__default.RefAttributes<any>>;
|
|
76
|
+
declare const ActualLink: React__default.ForwardRefExoticComponent<Pick<LinkProps, "replace" | "type" | "key" | "id" | "media" | "state" | "color" | "display" | "translate" | "hidden" | "dir" | "slot" | "style" | "title" | "target" | "accessKey" | "draggable" | "lang" | "className" | "prefix" | "children" | "contentEditable" | "inputMode" | "tabIndex" | "underline" | "download" | "href" | "hrefLang" | "defaultChecked" | "defaultValue" | "suppressContentEditableWarning" | "suppressHydrationWarning" | "contextMenu" | "placeholder" | "spellCheck" | "radioGroup" | "role" | "about" | "datatype" | "inlist" | "property" | "resource" | "typeof" | "vocab" | "autoCapitalize" | "autoCorrect" | "autoSave" | "itemProp" | "itemScope" | "itemType" | "itemID" | "itemRef" | "results" | "security" | "unselectable" | "is" | "aria-activedescendant" | "aria-atomic" | "aria-autocomplete" | "aria-busy" | "aria-checked" | "aria-colcount" | "aria-colindex" | "aria-colspan" | "aria-controls" | "aria-current" | "aria-describedby" | "aria-details" | "aria-disabled" | "aria-dropeffect" | "aria-errormessage" | "aria-expanded" | "aria-flowto" | "aria-grabbed" | "aria-haspopup" | "aria-hidden" | "aria-invalid" | "aria-keyshortcuts" | "aria-label" | "aria-labelledby" | "aria-level" | "aria-live" | "aria-modal" | "aria-multiline" | "aria-multiselectable" | "aria-orientation" | "aria-owns" | "aria-placeholder" | "aria-posinset" | "aria-pressed" | "aria-readonly" | "aria-relevant" | "aria-required" | "aria-roledescription" | "aria-rowcount" | "aria-rowindex" | "aria-rowspan" | "aria-selected" | "aria-setsize" | "aria-sort" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "to" | "rel" | "dangerouslySetInnerHTML" | "onCopy" | "onCopyCapture" | "onCut" | "onCutCapture" | "onPaste" | "onPasteCapture" | "onCompositionEnd" | "onCompositionEndCapture" | "onCompositionStart" | "onCompositionStartCapture" | "onCompositionUpdate" | "onCompositionUpdateCapture" | "onFocus" | "onFocusCapture" | "onBlur" | "onBlurCapture" | "onChange" | "onChangeCapture" | "onBeforeInput" | "onBeforeInputCapture" | "onInput" | "onInputCapture" | "onReset" | "onResetCapture" | "onSubmit" | "onSubmitCapture" | "onInvalid" | "onInvalidCapture" | "onLoad" | "onLoadCapture" | "onError" | "onErrorCapture" | "onKeyDown" | "onKeyDownCapture" | "onKeyPress" | "onKeyPressCapture" | "onKeyUp" | "onKeyUpCapture" | "onAbort" | "onAbortCapture" | "onCanPlay" | "onCanPlayCapture" | "onCanPlayThrough" | "onCanPlayThroughCapture" | "onDurationChange" | "onDurationChangeCapture" | "onEmptied" | "onEmptiedCapture" | "onEncrypted" | "onEncryptedCapture" | "onEnded" | "onEndedCapture" | "onLoadedData" | "onLoadedDataCapture" | "onLoadedMetadata" | "onLoadedMetadataCapture" | "onLoadStart" | "onLoadStartCapture" | "onPause" | "onPauseCapture" | "onPlay" | "onPlayCapture" | "onPlaying" | "onPlayingCapture" | "onProgress" | "onProgressCapture" | "onRateChange" | "onRateChangeCapture" | "onSeeked" | "onSeekedCapture" | "onSeeking" | "onSeekingCapture" | "onStalled" | "onStalledCapture" | "onSuspend" | "onSuspendCapture" | "onTimeUpdate" | "onTimeUpdateCapture" | "onVolumeChange" | "onVolumeChangeCapture" | "onWaiting" | "onWaitingCapture" | "onAuxClick" | "onAuxClickCapture" | "onClick" | "onClickCapture" | "onContextMenu" | "onContextMenuCapture" | "onDoubleClick" | "onDoubleClickCapture" | "onDrag" | "onDragCapture" | "onDragEnd" | "onDragEndCapture" | "onDragEnter" | "onDragEnterCapture" | "onDragExit" | "onDragExitCapture" | "onDragLeave" | "onDragLeaveCapture" | "onDragOver" | "onDragOverCapture" | "onDragStart" | "onDragStartCapture" | "onDrop" | "onDropCapture" | "onMouseDown" | "onMouseDownCapture" | "onMouseEnter" | "onMouseLeave" | "onMouseMove" | "onMouseMoveCapture" | "onMouseOut" | "onMouseOutCapture" | "onMouseOver" | "onMouseOverCapture" | "onMouseUp" | "onMouseUpCapture" | "onSelect" | "onSelectCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerMove" | "onPointerMoveCapture" | "onPointerUp" | "onPointerUpCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerEnter" | "onPointerEnterCapture" | "onPointerLeave" | "onPointerLeaveCapture" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onScroll" | "onScrollCapture" | "onWheel" | "onWheelCapture" | "onAnimationStart" | "onAnimationStartCapture" | "onAnimationEnd" | "onAnimationEndCapture" | "onAnimationIteration" | "onAnimationIterationCapture" | "onTransitionEnd" | "onTransitionEndCapture" | "ping" | "referrerPolicy" | "align" | "variant" | "component" | "classes" | "innerRef" | "noWrap" | "gutterBottom" | "paragraph" | "variantMapping" | "noTrack" | "TypographyClasses"> & React__default.RefAttributes<any>>;
|
|
75
77
|
|
|
76
78
|
/**
|
|
77
79
|
* Properties for {@link Button}
|
|
@@ -669,6 +671,7 @@ declare type MarkdownContentClassKey = 'markdown';
|
|
|
669
671
|
declare type Props$b = {
|
|
670
672
|
content: string;
|
|
671
673
|
dialect?: 'gfm' | 'common-mark';
|
|
674
|
+
linkTarget?: Options['linkTarget'];
|
|
672
675
|
};
|
|
673
676
|
/**
|
|
674
677
|
* MarkdownContent
|
|
@@ -763,6 +766,7 @@ declare type Props$9 = {
|
|
|
763
766
|
children?: ReactNode;
|
|
764
767
|
headerStyle?: object;
|
|
765
768
|
headerProps?: CardHeaderProps;
|
|
769
|
+
icon?: ReactNode;
|
|
766
770
|
action?: ReactNode;
|
|
767
771
|
actionsClassName?: string;
|
|
768
772
|
actions?: ReactNode;
|
|
@@ -781,7 +785,7 @@ declare type Props$9 = {
|
|
|
781
785
|
declare function InfoCard(props: Props$9): JSX.Element;
|
|
782
786
|
|
|
783
787
|
/** @public */
|
|
784
|
-
declare type GaugeClassKey = 'root' | 'overlay' | 'circle' | 'colorUnknown';
|
|
788
|
+
declare type GaugeClassKey = 'root' | 'overlay' | 'description' | 'circle' | 'colorUnknown';
|
|
785
789
|
/** @public */
|
|
786
790
|
declare type GaugeProps = {
|
|
787
791
|
value: number;
|
|
@@ -789,6 +793,7 @@ declare type GaugeProps = {
|
|
|
789
793
|
inverse?: boolean;
|
|
790
794
|
unit?: string;
|
|
791
795
|
max?: number;
|
|
796
|
+
description?: ReactNode;
|
|
792
797
|
getColor?: GaugePropsGetColor;
|
|
793
798
|
};
|
|
794
799
|
/** @public */
|
|
@@ -814,6 +819,8 @@ declare type Props$8 = {
|
|
|
814
819
|
variant?: InfoCardVariants;
|
|
815
820
|
/** Progress in % specified as decimal, e.g. "0.23" */
|
|
816
821
|
progress: number;
|
|
822
|
+
description?: ReactNode;
|
|
823
|
+
icon?: ReactNode;
|
|
817
824
|
inverse?: boolean;
|
|
818
825
|
deepLink?: BottomLinkProps;
|
|
819
826
|
getColor?: GaugePropsGetColor;
|
|
@@ -1142,7 +1149,8 @@ declare function ContentHeader(props: PropsWithChildren<ContentHeaderProps>): JS
|
|
|
1142
1149
|
interface IErrorPageProps {
|
|
1143
1150
|
status: string;
|
|
1144
1151
|
statusMessage: string;
|
|
1145
|
-
additionalInfo?:
|
|
1152
|
+
additionalInfo?: React__default.ReactNode;
|
|
1153
|
+
supportUrl?: string;
|
|
1146
1154
|
}
|
|
1147
1155
|
/** @public */
|
|
1148
1156
|
declare type ErrorPageClassKey = 'container' | 'title' | 'subtitle';
|
|
@@ -1332,8 +1340,9 @@ declare function ItemCardHeader(props: ItemCardHeaderProps): JSX.Element;
|
|
|
1332
1340
|
declare type PageClassKey = 'root';
|
|
1333
1341
|
declare type Props$3 = {
|
|
1334
1342
|
themeId: string;
|
|
1343
|
+
children?: React__default.ReactNode;
|
|
1335
1344
|
};
|
|
1336
|
-
declare function Page(props:
|
|
1345
|
+
declare function Page(props: Props$3): JSX.Element;
|
|
1337
1346
|
|
|
1338
1347
|
declare type PageWithHeaderProps = ComponentProps<typeof Header> & {
|
|
1339
1348
|
themeId: string;
|
package/dist/index.esm.js
CHANGED
|
@@ -3,7 +3,7 @@ import Snackbar from '@material-ui/core/Snackbar';
|
|
|
3
3
|
import IconButton from '@material-ui/core/IconButton';
|
|
4
4
|
import CloseIcon from '@material-ui/icons/Close';
|
|
5
5
|
import { Alert } from '@material-ui/lab';
|
|
6
|
-
import { useApi, alertApiRef, useAnalytics, errorApiRef, storageApiRef, useApp, oauthRequestApiRef, configApiRef, useElementFilter, attachComponentData, discoveryApiRef
|
|
6
|
+
import { useApi, alertApiRef, useAnalytics, errorApiRef, storageApiRef, useApp, oauthRequestApiRef, useApiHolder, configApiRef, useElementFilter, attachComponentData, discoveryApiRef } from '@backstage/core-plugin-api';
|
|
7
7
|
import pluralize from 'pluralize';
|
|
8
8
|
import { makeStyles, createStyles, useTheme, darken, lighten, withStyles, styled, ThemeProvider } from '@material-ui/core/styles';
|
|
9
9
|
import MaterialAvatar from '@material-ui/core/Avatar';
|
|
@@ -220,7 +220,7 @@ const getNodeText = (node) => {
|
|
|
220
220
|
}
|
|
221
221
|
return "";
|
|
222
222
|
};
|
|
223
|
-
const ActualLink = React.forwardRef(({ onClick, ...props }, ref) => {
|
|
223
|
+
const ActualLink = React.forwardRef(({ onClick, noTrack, ...props }, ref) => {
|
|
224
224
|
const analytics = useAnalytics();
|
|
225
225
|
const to = String(props.to);
|
|
226
226
|
const linkText = getNodeText(props.children) || to;
|
|
@@ -228,7 +228,9 @@ const ActualLink = React.forwardRef(({ onClick, ...props }, ref) => {
|
|
|
228
228
|
const newWindow = external && !!/^https?:/.exec(to);
|
|
229
229
|
const handleClick = (event) => {
|
|
230
230
|
onClick == null ? void 0 : onClick(event);
|
|
231
|
-
|
|
231
|
+
if (!noTrack) {
|
|
232
|
+
analytics.captureEvent("click", linkText, { attributes: { to } });
|
|
233
|
+
}
|
|
232
234
|
};
|
|
233
235
|
return external ? /* @__PURE__ */ React.createElement(Link, {
|
|
234
236
|
ref,
|
|
@@ -1613,7 +1615,7 @@ function Lifecycle(props) {
|
|
|
1613
1615
|
}, alpha ? "Alpha" : "Beta");
|
|
1614
1616
|
}
|
|
1615
1617
|
|
|
1616
|
-
const RealLogViewer = lazy(() => import('./esm/RealLogViewer-
|
|
1618
|
+
const RealLogViewer = lazy(() => import('./esm/RealLogViewer-e0ae55bd.esm.js').then((m) => ({ default: m.RealLogViewer })));
|
|
1617
1619
|
function LogViewer(props) {
|
|
1618
1620
|
const { Progress } = useApp().getComponents();
|
|
1619
1621
|
return /* @__PURE__ */ React.createElement(Suspense, {
|
|
@@ -1673,13 +1675,14 @@ const components = {
|
|
|
1673
1675
|
}
|
|
1674
1676
|
};
|
|
1675
1677
|
function MarkdownContent(props) {
|
|
1676
|
-
const { content, dialect = "gfm" } = props;
|
|
1678
|
+
const { content, dialect = "gfm", linkTarget } = props;
|
|
1677
1679
|
const classes = useStyles$C();
|
|
1678
1680
|
return /* @__PURE__ */ React.createElement(ReactMarkdown, {
|
|
1679
1681
|
remarkPlugins: dialect === "gfm" ? [gfm] : [],
|
|
1680
1682
|
className: classes.markdown,
|
|
1681
1683
|
children: content,
|
|
1682
|
-
components
|
|
1684
|
+
components,
|
|
1685
|
+
linkTarget
|
|
1683
1686
|
});
|
|
1684
1687
|
}
|
|
1685
1688
|
|
|
@@ -1897,7 +1900,10 @@ const useStyles$y = makeStyles((theme) => ({
|
|
|
1897
1900
|
},
|
|
1898
1901
|
headerAvatar: {},
|
|
1899
1902
|
headerAction: {},
|
|
1900
|
-
headerContent: {}
|
|
1903
|
+
headerContent: {},
|
|
1904
|
+
subheader: {
|
|
1905
|
+
display: "flex"
|
|
1906
|
+
}
|
|
1901
1907
|
}), { name: "BackstageInfoCard" });
|
|
1902
1908
|
const CardActionsTopRight = withStyles((theme) => ({
|
|
1903
1909
|
root: {
|
|
@@ -1945,6 +1951,7 @@ function InfoCard(props) {
|
|
|
1945
1951
|
children,
|
|
1946
1952
|
headerStyle,
|
|
1947
1953
|
headerProps,
|
|
1954
|
+
icon,
|
|
1948
1955
|
action,
|
|
1949
1956
|
actionsClassName,
|
|
1950
1957
|
actions,
|
|
@@ -1970,6 +1977,13 @@ function InfoCard(props) {
|
|
|
1970
1977
|
};
|
|
1971
1978
|
});
|
|
1972
1979
|
}
|
|
1980
|
+
const cardSubTitle = () => {
|
|
1981
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
1982
|
+
className: classes.headerSubheader
|
|
1983
|
+
}, subheader && /* @__PURE__ */ React.createElement("div", {
|
|
1984
|
+
className: classes.subheader
|
|
1985
|
+
}, subheader), icon);
|
|
1986
|
+
};
|
|
1973
1987
|
const errProps = errorBoundaryProps || (slackChannel ? { slackChannel } : {});
|
|
1974
1988
|
return /* @__PURE__ */ React.createElement(Card, {
|
|
1975
1989
|
style: calculatedStyle,
|
|
@@ -1986,7 +2000,7 @@ function InfoCard(props) {
|
|
|
1986
2000
|
content: classes.headerContent
|
|
1987
2001
|
},
|
|
1988
2002
|
title,
|
|
1989
|
-
subheader,
|
|
2003
|
+
subheader: cardSubTitle(),
|
|
1990
2004
|
action,
|
|
1991
2005
|
style: { ...headerStyle },
|
|
1992
2006
|
titleTypographyProps,
|
|
@@ -2017,6 +2031,15 @@ const useStyles$x = makeStyles((theme) => ({
|
|
|
2017
2031
|
fontWeight: "bold",
|
|
2018
2032
|
color: theme.palette.textContrast
|
|
2019
2033
|
},
|
|
2034
|
+
description: {
|
|
2035
|
+
fontSize: "100%",
|
|
2036
|
+
top: "50%",
|
|
2037
|
+
left: "50%",
|
|
2038
|
+
transform: "translate(-50%, -50%)",
|
|
2039
|
+
position: "absolute",
|
|
2040
|
+
wordBreak: "break-all",
|
|
2041
|
+
display: "inline-block"
|
|
2042
|
+
},
|
|
2020
2043
|
circle: {
|
|
2021
2044
|
width: "80%",
|
|
2022
2045
|
transform: "translate(10%, 0)"
|
|
@@ -2048,16 +2071,35 @@ const getProgressColor = ({
|
|
|
2048
2071
|
return palette.status.ok;
|
|
2049
2072
|
};
|
|
2050
2073
|
function Gauge(props) {
|
|
2074
|
+
const [hoverRef, setHoverRef] = useState(null);
|
|
2051
2075
|
const { getColor = getProgressColor } = props;
|
|
2052
2076
|
const classes = useStyles$x(props);
|
|
2053
2077
|
const { palette } = useTheme();
|
|
2054
|
-
const { value, fractional, inverse, unit, max } = {
|
|
2078
|
+
const { value, fractional, inverse, unit, max, description } = {
|
|
2055
2079
|
...defaultGaugeProps,
|
|
2056
2080
|
...props
|
|
2057
2081
|
};
|
|
2058
2082
|
const asPercentage = fractional ? Math.round(value * max) : value;
|
|
2059
2083
|
const asActual = max !== 100 ? Math.round(value) : asPercentage;
|
|
2084
|
+
const [isHovering, setIsHovering] = useState(false);
|
|
2085
|
+
useEffect(() => {
|
|
2086
|
+
const node = hoverRef;
|
|
2087
|
+
const handleMouseOver = () => setIsHovering(true);
|
|
2088
|
+
const handleMouseOut = () => setIsHovering(false);
|
|
2089
|
+
if (node && description) {
|
|
2090
|
+
node.addEventListener("mouseenter", handleMouseOver);
|
|
2091
|
+
node.addEventListener("mouseleave", handleMouseOut);
|
|
2092
|
+
return () => {
|
|
2093
|
+
node.removeEventListener("mouseenter", handleMouseOver);
|
|
2094
|
+
node.removeEventListener("mouseleave", handleMouseOut);
|
|
2095
|
+
};
|
|
2096
|
+
}
|
|
2097
|
+
return () => {
|
|
2098
|
+
setIsHovering(false);
|
|
2099
|
+
};
|
|
2100
|
+
}, [description, hoverRef]);
|
|
2060
2101
|
return /* @__PURE__ */ React.createElement("div", {
|
|
2102
|
+
ref: setHoverRef,
|
|
2061
2103
|
className: classes.root
|
|
2062
2104
|
}, /* @__PURE__ */ React.createElement(Circle, {
|
|
2063
2105
|
strokeLinecap: "butt",
|
|
@@ -2066,7 +2108,9 @@ function Gauge(props) {
|
|
|
2066
2108
|
trailWidth: 12,
|
|
2067
2109
|
strokeColor: getColor({ palette, value: asActual, inverse, max }),
|
|
2068
2110
|
className: classes.circle
|
|
2069
|
-
}), /* @__PURE__ */ React.createElement("div", {
|
|
2111
|
+
}), description && isHovering ? /* @__PURE__ */ React.createElement("div", {
|
|
2112
|
+
className: classes.description
|
|
2113
|
+
}, description) : /* @__PURE__ */ React.createElement("div", {
|
|
2070
2114
|
className: classes.overlay
|
|
2071
2115
|
}, isNaN(value) ? "N/A" : `${asActual}${unit}`));
|
|
2072
2116
|
}
|
|
@@ -2079,9 +2123,20 @@ const useStyles$w = makeStyles({
|
|
|
2079
2123
|
}, { name: "BackstageGaugeCard" });
|
|
2080
2124
|
function GaugeCard(props) {
|
|
2081
2125
|
const classes = useStyles$w(props);
|
|
2082
|
-
const {
|
|
2126
|
+
const {
|
|
2127
|
+
title,
|
|
2128
|
+
subheader,
|
|
2129
|
+
progress,
|
|
2130
|
+
inverse,
|
|
2131
|
+
deepLink,
|
|
2132
|
+
description,
|
|
2133
|
+
icon,
|
|
2134
|
+
variant,
|
|
2135
|
+
getColor
|
|
2136
|
+
} = props;
|
|
2083
2137
|
const gaugeProps = {
|
|
2084
2138
|
inverse,
|
|
2139
|
+
description,
|
|
2085
2140
|
getColor,
|
|
2086
2141
|
value: progress
|
|
2087
2142
|
};
|
|
@@ -2091,7 +2146,8 @@ function GaugeCard(props) {
|
|
|
2091
2146
|
title,
|
|
2092
2147
|
subheader,
|
|
2093
2148
|
deepLink,
|
|
2094
|
-
variant
|
|
2149
|
+
variant,
|
|
2150
|
+
icon
|
|
2095
2151
|
}, /* @__PURE__ */ React.createElement(Gauge, {
|
|
2096
2152
|
...gaugeProps
|
|
2097
2153
|
})));
|
|
@@ -2763,8 +2819,9 @@ const DEFAULT_SUPPORT_CONFIG = {
|
|
|
2763
2819
|
]
|
|
2764
2820
|
};
|
|
2765
2821
|
function useSupportConfig() {
|
|
2766
|
-
const
|
|
2767
|
-
const
|
|
2822
|
+
const apiHolder = useApiHolder();
|
|
2823
|
+
const config = apiHolder.get(configApiRef);
|
|
2824
|
+
const supportConfig = config == null ? void 0 : config.getOptionalConfig("app.support");
|
|
2768
2825
|
if (!supportConfig) {
|
|
2769
2826
|
return DEFAULT_SUPPORT_CONFIG;
|
|
2770
2827
|
}
|
|
@@ -3115,6 +3172,9 @@ const useStyles$m = makeStyles((theme) => ({
|
|
|
3115
3172
|
},
|
|
3116
3173
|
overlayHeaderClose: {
|
|
3117
3174
|
color: theme.palette.bursts.fontColor
|
|
3175
|
+
},
|
|
3176
|
+
marginMobileSidebar: {
|
|
3177
|
+
marginBottom: `${sidebarConfig.mobileSidebarHeight}px`
|
|
3118
3178
|
}
|
|
3119
3179
|
}));
|
|
3120
3180
|
const sortSidebarGroupsForPriority = (children) => orderBy(children, ({ props: { priority } }) => Number.isInteger(priority) ? priority : -1, "desc");
|
|
@@ -3130,7 +3190,13 @@ const OverlayMenu = ({
|
|
|
3130
3190
|
anchor: "bottom",
|
|
3131
3191
|
open,
|
|
3132
3192
|
onClose,
|
|
3133
|
-
|
|
3193
|
+
ModalProps: {
|
|
3194
|
+
BackdropProps: { classes: { root: classes.marginMobileSidebar } }
|
|
3195
|
+
},
|
|
3196
|
+
classes: {
|
|
3197
|
+
root: classes.marginMobileSidebar,
|
|
3198
|
+
paperAnchorBottom: classes.overlay
|
|
3199
|
+
}
|
|
3134
3200
|
}, /* @__PURE__ */ React.createElement(Box, {
|
|
3135
3201
|
className: classes.overlayHeader
|
|
3136
3202
|
}, /* @__PURE__ */ React.createElement(Typography, {
|
|
@@ -5010,7 +5076,7 @@ const useStyles$6 = makeStyles((theme) => ({
|
|
|
5010
5076
|
}
|
|
5011
5077
|
}), { name: "BackstageErrorPage" });
|
|
5012
5078
|
function ErrorPage(props) {
|
|
5013
|
-
const { status, statusMessage, additionalInfo } = props;
|
|
5079
|
+
const { status, statusMessage, additionalInfo, supportUrl } = props;
|
|
5014
5080
|
const classes = useStyles$6();
|
|
5015
5081
|
const navigate = useNavigate();
|
|
5016
5082
|
const support = useSupportConfig();
|
|
@@ -5039,8 +5105,8 @@ function ErrorPage(props) {
|
|
|
5039
5105
|
to: "#",
|
|
5040
5106
|
"data-testid": "go-back-link",
|
|
5041
5107
|
onClick: () => navigate(-1)
|
|
5042
|
-
}, "Go back"), "... or please ", /* @__PURE__ */ React.createElement(ActualLink, {
|
|
5043
|
-
to: support.url
|
|
5108
|
+
}, "Go back"), "... or please", " ", /* @__PURE__ */ React.createElement(ActualLink, {
|
|
5109
|
+
to: supportUrl || support.url
|
|
5044
5110
|
}, "contact support"), " if you think this is a bug.")));
|
|
5045
5111
|
}
|
|
5046
5112
|
|
|
@@ -5133,7 +5199,7 @@ const useStyles$5 = makeStyles((theme) => ({
|
|
|
5133
5199
|
marginBottom: 0
|
|
5134
5200
|
},
|
|
5135
5201
|
subtitle: {
|
|
5136
|
-
color: theme.palette.
|
|
5202
|
+
color: theme.palette.bursts.fontColor,
|
|
5137
5203
|
opacity: 0.8,
|
|
5138
5204
|
display: "inline-block",
|
|
5139
5205
|
marginTop: theme.spacing(1),
|
|
@@ -5408,18 +5474,19 @@ function ItemCardGrid(props) {
|
|
|
5408
5474
|
}
|
|
5409
5475
|
|
|
5410
5476
|
const useStyles$1 = makeStyles(() => ({
|
|
5411
|
-
root: {
|
|
5477
|
+
root: ({ isMobile }) => ({
|
|
5412
5478
|
display: "grid",
|
|
5413
5479
|
gridTemplateAreas: "'pageHeader pageHeader pageHeader' 'pageSubheader pageSubheader pageSubheader' 'pageNav pageContent pageSidebar'",
|
|
5414
5480
|
gridTemplateRows: "max-content auto 1fr",
|
|
5415
5481
|
gridTemplateColumns: "auto 1fr auto",
|
|
5416
|
-
height: "100%",
|
|
5482
|
+
height: isMobile ? "100%" : "100vh",
|
|
5417
5483
|
overflowY: "auto"
|
|
5418
|
-
}
|
|
5484
|
+
})
|
|
5419
5485
|
}), { name: "BackstagePage" });
|
|
5420
5486
|
function Page(props) {
|
|
5421
5487
|
const { themeId, children } = props;
|
|
5422
|
-
const
|
|
5488
|
+
const { isMobile } = useContext(SidebarPinStateContext);
|
|
5489
|
+
const classes = useStyles$1({ isMobile });
|
|
5423
5490
|
return /* @__PURE__ */ React.createElement(ThemeProvider, {
|
|
5424
5491
|
theme: (baseTheme) => ({
|
|
5425
5492
|
...baseTheme,
|