mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
* Add Integrations page and POC CodeBlock usage * Adds new route hidden behind a config var (`xpack.code.integrations.enabld`) * Updates CodeBlock component to have a smaller API surface * Adds several example components for various pieces of the new APM integration designs. * Pare down stub data Hits and ranges were both part of our search results queries; O11y won't have that information.
This commit is contained in:
parent
573d48db4d
commit
3d3aa912de
14 changed files with 434 additions and 69 deletions
|
@ -39,6 +39,7 @@ export const code = (kibana: any) =>
|
|||
const config = server.config();
|
||||
return {
|
||||
codeUiEnabled: config.get('xpack.code.ui.enabled'),
|
||||
codeIntegrationsEnabled: config.get('xpack.code.integrations.enabled'),
|
||||
};
|
||||
},
|
||||
hacks: ['plugins/code/hacks/toggle_app_link_in_nav'],
|
||||
|
@ -50,6 +51,9 @@ export const code = (kibana: any) =>
|
|||
ui: Joi.object({
|
||||
enabled: Joi.boolean().default(true),
|
||||
}).default(),
|
||||
integrations: Joi.object({
|
||||
enabled: Joi.boolean().default(false),
|
||||
}).default(),
|
||||
enabled: Joi.boolean().default(true),
|
||||
}).default();
|
||||
},
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
import React from 'react';
|
||||
import { HashRouter as Router, Redirect, Switch } from 'react-router-dom';
|
||||
|
||||
import chrome from 'ui/chrome';
|
||||
import { connect } from 'react-redux';
|
||||
import { RootState } from '../reducers';
|
||||
import { Admin } from './admin_page/admin';
|
||||
|
@ -17,6 +18,7 @@ import { NotFound } from './main/not_found';
|
|||
import { Route } from './route';
|
||||
import * as ROUTES from './routes';
|
||||
import { Search } from './search_page/search';
|
||||
import { Integrations } from './integrations';
|
||||
|
||||
const RooComponent = (props: { setupOk?: boolean }) => {
|
||||
if (props.setupOk) {
|
||||
|
@ -33,6 +35,8 @@ const Root = connect(mapStateToProps)(RooComponent);
|
|||
|
||||
const Empty = () => null;
|
||||
|
||||
const integrationsEnabled = chrome.getInjected('codeIntegrationsEnabled');
|
||||
|
||||
export const App = () => {
|
||||
return (
|
||||
<Router>
|
||||
|
@ -45,6 +49,9 @@ export const App = () => {
|
|||
<Route path={ROUTES.SEARCH} component={Search} />
|
||||
<Route path={ROUTES.REPO} render={Empty} exact={true} />
|
||||
<Route path={ROUTES.SETUP} component={SetupGuide} exact={true} />
|
||||
{integrationsEnabled && (
|
||||
<Route path={ROUTES.INTEGRATIONS} component={Integrations} exact={true} />
|
||||
)}
|
||||
<Route path="*" component={NotFound} />
|
||||
</Switch>
|
||||
</Router>
|
||||
|
|
|
@ -5,50 +5,72 @@
|
|||
*/
|
||||
|
||||
import { EuiPanel } from '@elastic/eui';
|
||||
import { editor, IPosition, IRange } from 'monaco-editor';
|
||||
import { editor, IRange } from 'monaco-editor';
|
||||
import React from 'react';
|
||||
|
||||
import { ResizeChecker } from '../shared/resize_checker';
|
||||
import { monaco } from '../../monaco/monaco';
|
||||
import { registerEditor } from '../../monaco/single_selection_helper';
|
||||
|
||||
interface Props {
|
||||
code: string;
|
||||
fileComponent?: React.ReactNode;
|
||||
startLine?: number;
|
||||
language?: string;
|
||||
highlightRanges?: IRange[];
|
||||
onClick?: (event: IPosition) => void;
|
||||
export interface Position {
|
||||
lineNumber: string;
|
||||
column: number;
|
||||
}
|
||||
|
||||
export interface Props {
|
||||
content: string;
|
||||
header: React.ReactNode;
|
||||
language: string;
|
||||
highlightRanges: IRange[];
|
||||
onClick: (event: Position) => void;
|
||||
folding: boolean;
|
||||
lineNumbersFunc: (line: number) => string;
|
||||
/**
|
||||
* Returns the line number to display for a given line.
|
||||
* @param lineIndex The index of the given line (0-indexed)
|
||||
*/
|
||||
lineNumber: (lineIndex: number) => string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export class CodeBlock extends React.PureComponent<Props> {
|
||||
static defaultProps = {
|
||||
header: undefined,
|
||||
folding: false,
|
||||
highlightRanges: [],
|
||||
language: 'text',
|
||||
lineNumber: String,
|
||||
onClick: () => {},
|
||||
};
|
||||
|
||||
private el: HTMLDivElement | null = null;
|
||||
private ed?: editor.IStandaloneCodeEditor;
|
||||
private resizeChecker?: ResizeChecker;
|
||||
private currentHighlightDecorations: string[] = [];
|
||||
|
||||
public async componentDidMount() {
|
||||
const { content, highlightRanges, language, onClick } = this.props;
|
||||
|
||||
if (this.el) {
|
||||
await this.tryLoadFile(this.props.code, this.props.language || 'text');
|
||||
await this.tryLoadFile(content, language);
|
||||
this.ed!.onMouseDown((e: editor.IEditorMouseEvent) => {
|
||||
if (
|
||||
this.props.onClick &&
|
||||
onClick &&
|
||||
(e.target.type === monaco.editor.MouseTargetType.GUTTER_LINE_NUMBERS ||
|
||||
e.target.type === monaco.editor.MouseTargetType.CONTENT_TEXT)
|
||||
) {
|
||||
const position = e.target.position || { lineNumber: 0, column: 0 };
|
||||
const lineNumber = (this.props.startLine || 0) + position.lineNumber;
|
||||
this.props.onClick({
|
||||
const lineNumber = this.lineNumber(position.lineNumber);
|
||||
|
||||
onClick({
|
||||
lineNumber,
|
||||
column: position.column,
|
||||
});
|
||||
}
|
||||
});
|
||||
registerEditor(this.ed!);
|
||||
if (this.props.highlightRanges) {
|
||||
const decorations = this.props.highlightRanges.map((range: IRange) => {
|
||||
|
||||
if (highlightRanges.length) {
|
||||
const decorations = highlightRanges.map((range: IRange) => {
|
||||
return {
|
||||
range,
|
||||
options: {
|
||||
|
@ -66,6 +88,7 @@ export class CodeBlock extends React.PureComponent<Props> {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
private async tryLoadFile(code: string, language: string) {
|
||||
try {
|
||||
await monaco.editor.colorize(code, language, {});
|
||||
|
@ -79,7 +102,7 @@ export class CodeBlock extends React.PureComponent<Props> {
|
|||
this.ed = monaco.editor.create(this.el!, {
|
||||
value: code,
|
||||
language,
|
||||
lineNumbers: this.lineNumbersFunc.bind(this),
|
||||
lineNumbers: this.lineNumber,
|
||||
readOnly: true,
|
||||
folding: this.props.folding,
|
||||
minimap: {
|
||||
|
@ -103,17 +126,16 @@ export class CodeBlock extends React.PureComponent<Props> {
|
|||
}
|
||||
|
||||
public componentDidUpdate(prevProps: Readonly<Props>) {
|
||||
if (
|
||||
prevProps.code !== this.props.code ||
|
||||
prevProps.highlightRanges !== this.props.highlightRanges
|
||||
) {
|
||||
const { content, highlightRanges } = this.props;
|
||||
|
||||
if (prevProps.content !== content || prevProps.highlightRanges !== highlightRanges) {
|
||||
if (this.ed) {
|
||||
const model = this.ed.getModel();
|
||||
if (model) {
|
||||
model.setValue(this.props.code);
|
||||
model.setValue(content);
|
||||
|
||||
if (this.props.highlightRanges) {
|
||||
const decorations = this.props.highlightRanges!.map((range: IRange) => {
|
||||
if (highlightRanges.length) {
|
||||
const decorations = highlightRanges!.map((range: IRange) => {
|
||||
return {
|
||||
range,
|
||||
options: {
|
||||
|
@ -138,19 +160,20 @@ export class CodeBlock extends React.PureComponent<Props> {
|
|||
}
|
||||
|
||||
public render() {
|
||||
const linesCount = this.props.code.split('\n').length;
|
||||
const { className, header } = this.props;
|
||||
const height = this.lines.length * 18;
|
||||
|
||||
return (
|
||||
<EuiPanel style={{ marginBottom: '2rem' }} paddingSize="s">
|
||||
{this.props.fileComponent}
|
||||
<div ref={r => (this.el = r)} style={{ height: linesCount * 18 }} />
|
||||
<EuiPanel paddingSize="s" className={className}>
|
||||
{header}
|
||||
<div ref={r => (this.el = r)} style={{ height }} />
|
||||
</EuiPanel>
|
||||
);
|
||||
}
|
||||
|
||||
private lineNumbersFunc = (line: number) => {
|
||||
if (this.props.lineNumbersFunc) {
|
||||
return this.props.lineNumbersFunc(line);
|
||||
}
|
||||
return `${(this.props.startLine || 0) + line}`;
|
||||
};
|
||||
private lineNumber = (lineIndex: number) => this.props.lineNumber(lineIndex - 1);
|
||||
|
||||
private get lines(): string[] {
|
||||
return this.props.content.split('\n');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,13 +14,12 @@ import {
|
|||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
import classname from 'classnames';
|
||||
import { IPosition } from 'monaco-editor';
|
||||
import queryString from 'querystring';
|
||||
import React from 'react';
|
||||
import { parseSchema } from '../../../common/uri_util';
|
||||
import { GroupedFileResults, GroupedRepoResults } from '../../actions';
|
||||
import { history } from '../../utils/url';
|
||||
import { CodeBlock } from '../codeblock/codeblock';
|
||||
import { CodeBlock, Position } from '../codeblock/codeblock';
|
||||
|
||||
interface Props {
|
||||
isLoading: boolean;
|
||||
|
@ -114,12 +113,9 @@ export class ReferencesPanel extends React.Component<Props, State> {
|
|||
|
||||
private renderReference(file: GroupedFileResults) {
|
||||
const key = `${file.uri}`;
|
||||
const lineNumberFn = (l: number) => {
|
||||
return file.lineNumbers[l - 1];
|
||||
};
|
||||
const fileComponent = (
|
||||
const header = (
|
||||
<React.Fragment>
|
||||
<EuiText>
|
||||
<EuiText size="s">
|
||||
<a href={`#${this.computeUrl(file.uri)}`}>{file.file}</a>
|
||||
</EuiText>
|
||||
<EuiSpacer size="s" />
|
||||
|
@ -128,23 +124,22 @@ export class ReferencesPanel extends React.Component<Props, State> {
|
|||
|
||||
return (
|
||||
<CodeBlock
|
||||
className="referencesPanel__code-block"
|
||||
key={key}
|
||||
header={header}
|
||||
content={file.code}
|
||||
language={file.language}
|
||||
startLine={0}
|
||||
code={file.code}
|
||||
folding={false}
|
||||
lineNumbersFunc={lineNumberFn}
|
||||
lineNumber={i => file.lineNumbers[i]}
|
||||
highlightRanges={file.highlights}
|
||||
fileComponent={fileComponent}
|
||||
onClick={this.onCodeClick.bind(this, file.lineNumbers, file.uri)}
|
||||
onClick={this.onCodeClick(file.uri)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
private onCodeClick(lineNumbers: string[], url: string, pos: IPosition) {
|
||||
const line = parseInt(lineNumbers[pos.lineNumber - 1], 10);
|
||||
history.push(this.computeUrl(url, line));
|
||||
}
|
||||
private onCodeClick = (url: string) => (position: Position) => {
|
||||
const lineNum = parseInt(position.lineNumber, 10);
|
||||
history.push(this.computeUrl(url, lineNum));
|
||||
};
|
||||
|
||||
private computeUrl(url: string, line?: number) {
|
||||
const { uri } = parseSchema(url)!;
|
||||
|
@ -158,6 +153,7 @@ export class ReferencesPanel extends React.Component<Props, State> {
|
|||
tab: 'references',
|
||||
refUrl: this.props.refUrl,
|
||||
});
|
||||
|
||||
return line !== undefined ? `${uri}!L${line}:0?${query}` : `${uri}?${query}`;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export interface Snippet {
|
||||
uri: string;
|
||||
filePath: string;
|
||||
language?: string;
|
||||
compositeContent: {
|
||||
content: string;
|
||||
lineMapping: string[];
|
||||
};
|
||||
}
|
||||
|
||||
export type Results = Record<string, Snippet>;
|
||||
|
||||
export const results: Results = {
|
||||
'ringside.ts#L18': {
|
||||
uri: 'github.com/rylnd/ringside',
|
||||
filePath: 'src/ringside.ts',
|
||||
language: 'typescript',
|
||||
compositeContent: {
|
||||
content:
|
||||
"\nimport { fitsInside, fitsOutside } from './fitting';\n\nexport interface RingsideInterface {\n positions(): FittedPosition[];\n}\n\nclass Ringside implements RingsideInterface {\n readonly innerBounds: FullRect;\n readonly outerBounds: FullRect;\n\n}\n\nexport default Ringside;\n",
|
||||
lineMapping: [
|
||||
'..',
|
||||
'13',
|
||||
'14',
|
||||
'15',
|
||||
'16',
|
||||
'17',
|
||||
'18',
|
||||
'19',
|
||||
'20',
|
||||
'21',
|
||||
'..',
|
||||
'67',
|
||||
'68',
|
||||
'69',
|
||||
'70',
|
||||
],
|
||||
},
|
||||
},
|
||||
'ringside.story.tsx#L12': {
|
||||
uri: 'github.com/rylnd/ringside',
|
||||
filePath: 'stories/ringside.story.tsx',
|
||||
language: 'typescript',
|
||||
compositeContent: {
|
||||
content:
|
||||
"\nimport { interpolateRainbow } from 'd3-scale-chromatic';\n\nimport { Ringside } from '../src';\nimport { XAlignment, YAlignment, XBasis, YBasis } from '../src/types';\n\nlet ringside: Ringside;\n\nconst enumKeys: (e: any) => string[] = e =>\n\n\nconst color = position => {\n const combos = ringside.positions().map(p => JSON.stringify(p));\n const hash = combos.indexOf(JSON.stringify(position)) / combos.length;\n\n\n};\n\nconst Stories = storiesOf('Ringside', module).addDecorator(withKnobs);\n\nStories.add('Ringside', () => {\n",
|
||||
lineMapping: [
|
||||
'..',
|
||||
'5',
|
||||
'6',
|
||||
'7',
|
||||
'8',
|
||||
'9',
|
||||
'10',
|
||||
'11',
|
||||
'12',
|
||||
'..',
|
||||
'14',
|
||||
'15',
|
||||
'16',
|
||||
'17',
|
||||
'18',
|
||||
'..',
|
||||
'20',
|
||||
'21',
|
||||
'22',
|
||||
'23',
|
||||
'24',
|
||||
'..',
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
'ringside.story.tsx#L8': {
|
||||
uri: 'github.com/rylnd/ringside',
|
||||
filePath: 'stories/ringside.story.tsx',
|
||||
language: 'typescript',
|
||||
compositeContent: {
|
||||
content:
|
||||
"import { Ringside } from '../src';\n\ndescribe('Ringside', () => {\n let inner;\n let outer;\n let height;\n let width;\n let ringside: Ringside;\n\n beforeEach(() => {\n\n width = 50;\n\n ringside = new Ringside(inner, outer, height, width);\n });\n\n",
|
||||
lineMapping: [
|
||||
'1',
|
||||
'2',
|
||||
'3',
|
||||
'4',
|
||||
'5',
|
||||
'6',
|
||||
'7',
|
||||
'8',
|
||||
'9',
|
||||
'10',
|
||||
'..',
|
||||
'14',
|
||||
'15',
|
||||
'16',
|
||||
'17',
|
||||
'18',
|
||||
'..',
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
'ringside.story.tsx#L14': {
|
||||
uri: 'github.com/rylnd/ringside',
|
||||
filePath: 'stories/ringside.story.tsx',
|
||||
language: 'typescript',
|
||||
compositeContent: {
|
||||
content:
|
||||
"import { Ringside } from '../src';\n\ndescribe('Ringside', () => {\n let inner;\n let outer;\n let height;\n let width;\n let ringside: Ringside;\n\n beforeEach(() => {\n\n width = 50;\n\n ringside = new Ringside(inner, outer, height, width);\n });\n\n",
|
||||
lineMapping: [
|
||||
'1',
|
||||
'2',
|
||||
'3',
|
||||
'4',
|
||||
'5',
|
||||
'6',
|
||||
'7',
|
||||
'8',
|
||||
'9',
|
||||
'10',
|
||||
'..',
|
||||
'14',
|
||||
'15',
|
||||
'16',
|
||||
'17',
|
||||
'18',
|
||||
'..',
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export interface Frame {
|
||||
fileName: string;
|
||||
lineNumber: number;
|
||||
functionName?: string;
|
||||
}
|
||||
|
||||
export const frames: Frame[] = [
|
||||
{ fileName: 'ringside.ts', lineNumber: 18 },
|
||||
{ fileName: 'node_modules/library_code.js', lineNumber: 100 },
|
||||
{ fileName: 'ringside.story.tsx', lineNumber: 8 },
|
||||
{ fileName: 'node_modules/other_stuff.js', lineNumber: 58 },
|
||||
{ fileName: 'node_modules/other/other.js', lineNumber: 3 },
|
||||
{ fileName: 'ringside.story.tsx', lineNumber: 12 },
|
||||
{ fileName: 'ringside.story.tsx', lineNumber: 14 },
|
||||
];
|
||||
|
||||
export const repos = [
|
||||
'https://github.com/a/repo',
|
||||
'https://github.com/another/repo',
|
||||
'https://github.com/also/a_repo',
|
||||
];
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { EuiButtonIcon, EuiFlexGroup, EuiLink, EuiText, EuiTextColor } from '@elastic/eui';
|
||||
|
||||
export const FrameHeader = ({
|
||||
fileName,
|
||||
lineNumber,
|
||||
onClick,
|
||||
}: {
|
||||
fileName: string;
|
||||
lineNumber: number | string;
|
||||
onClick: () => void;
|
||||
}) => (
|
||||
<EuiFlexGroup
|
||||
className="integrations__snippet-info"
|
||||
alignItems="center"
|
||||
justifyContent="spaceBetween"
|
||||
gutterSize="none"
|
||||
>
|
||||
<EuiText size="s">
|
||||
<EuiLink onClick={onClick}>{fileName}</EuiLink>
|
||||
<span> at </span>
|
||||
<EuiLink onClick={onClick}>line {lineNumber}</EuiLink>
|
||||
</EuiText>
|
||||
<EuiText size="xs">
|
||||
<EuiTextColor color="subdued">Last updated: 14 mins ago</EuiTextColor>
|
||||
<EuiButtonIcon
|
||||
className="integrations__link--external integrations__button-icon"
|
||||
iconType="codeApp"
|
||||
onClick={onClick}
|
||||
/>
|
||||
</EuiText>
|
||||
</EuiFlexGroup>
|
||||
);
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
// TODO(rylnd): make this an actual external link
|
||||
export const externalFileURI: (repoUri: string, filePath: string) => string = (uri, path) =>
|
||||
`/${uri}/blob/HEAD/${path}`;
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { EuiFlexGroup, EuiText } from '@elastic/eui';
|
||||
|
||||
import { CodeBlock } from '../codeblock/codeblock';
|
||||
import { history } from '../../utils/url';
|
||||
import { FrameHeader } from './frame_header';
|
||||
import { RepoTitle } from './repo_title';
|
||||
import { externalFileURI } from './helpers';
|
||||
import { frames, results } from './data';
|
||||
|
||||
export const Integrations = () => (
|
||||
<div className="codeContainer__root integrations__container">
|
||||
{frames.map(frame => {
|
||||
const { fileName, lineNumber } = frame;
|
||||
const key = `${fileName}#L${lineNumber}`;
|
||||
const snippet = results[key];
|
||||
|
||||
if (snippet) {
|
||||
const { compositeContent, filePath, language, uri } = snippet;
|
||||
const { content, lineMapping } = compositeContent;
|
||||
const fileUrl = externalFileURI(uri, filePath);
|
||||
|
||||
return (
|
||||
<div key={key} className="integrations__frame">
|
||||
<RepoTitle uri={snippet.uri} />
|
||||
<CodeBlock
|
||||
content={content}
|
||||
header={
|
||||
<FrameHeader
|
||||
fileName={fileName}
|
||||
lineNumber={lineNumber}
|
||||
onClick={() => history.push(fileUrl)}
|
||||
/>
|
||||
}
|
||||
language={language}
|
||||
lineNumber={i => lineMapping[i]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div key={key} className="integrations__frame">
|
||||
<EuiFlexGroup justifyContent="spaceBetween" gutterSize="none" alignItems="center">
|
||||
<EuiText size="s" className="integrations__code">
|
||||
<span>{fileName}</span>
|
||||
<span className="integrations__preposition">at</span>
|
||||
<span>line {lineNumber}</span>
|
||||
</EuiText>
|
||||
</EuiFlexGroup>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
|
@ -0,0 +1,43 @@
|
|||
.integrations__container {
|
||||
padding: $euiSize;
|
||||
}
|
||||
|
||||
.integrations__frame {
|
||||
margin: $euiSizeS 0;
|
||||
}
|
||||
|
||||
.integrations__code {
|
||||
@include euiCodeFont;
|
||||
}
|
||||
|
||||
.integrations__link--external {
|
||||
margin-left: $euiSizeS;
|
||||
}
|
||||
|
||||
.integrations__preposition {
|
||||
margin: 0 $euiSizeS;
|
||||
color: $euiColorMediumShade;
|
||||
}
|
||||
|
||||
.integrations__button-icon {
|
||||
padding: $euiSizeXS;
|
||||
background-color: $euiColorLightestShade;
|
||||
border: 1px solid $euiColorLightShade;
|
||||
}
|
||||
|
||||
.integrations__snippet-info {
|
||||
margin-bottom: $euiSizeS;
|
||||
}
|
||||
|
||||
.integrations__snippet-title {
|
||||
margin-bottom: $euiSizeS;
|
||||
}
|
||||
|
||||
.integrations__text--bold {
|
||||
font-weight: $euiFontWeightBold;
|
||||
}
|
||||
|
||||
.integrations__popover {
|
||||
margin-bottom: 1rem;
|
||||
width: 300px;
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { EuiText } from '@elastic/eui';
|
||||
import { RepositoryUtils } from '../../../common/repository_utils';
|
||||
|
||||
export const RepoTitle = ({ uri }: { uri: string }) => {
|
||||
const org = RepositoryUtils.orgNameFromUri(uri);
|
||||
const name = RepositoryUtils.repoNameFromUri(uri);
|
||||
|
||||
return (
|
||||
<EuiText size="s" className="integrations__snippet-title">
|
||||
<span>{org}/</span>
|
||||
<span className="integrations__text--bold">{name}</span>
|
||||
</EuiText>
|
||||
);
|
||||
};
|
|
@ -15,3 +15,4 @@ export const REPO = `/:resource/:org/:repo`;
|
|||
export const MAIN_ROOT = `/:resource/:org/:repo/${pathTypes}/:revision`;
|
||||
export const ADMIN = '/admin';
|
||||
export const SEARCH = '/search';
|
||||
export const INTEGRATIONS = '/integrations';
|
||||
|
|
|
@ -6,13 +6,12 @@
|
|||
|
||||
import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { IPosition } from 'monaco-editor';
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { RepositoryUtils } from '../../../common/repository_utils';
|
||||
import { history } from '../../utils/url';
|
||||
import { CodeBlock } from '../codeblock/codeblock';
|
||||
import { CodeBlock, Position } from '../codeblock/codeblock';
|
||||
|
||||
interface Props {
|
||||
query: string;
|
||||
|
@ -22,15 +21,14 @@ interface Props {
|
|||
export class CodeResult extends React.PureComponent<Props> {
|
||||
public render() {
|
||||
const { results, query } = this.props;
|
||||
|
||||
return results.map(item => {
|
||||
const { uri, filePath, hits, compositeContent } = item;
|
||||
const { compositeContent, filePath, hits, language, uri } = item;
|
||||
const { content, lineMapping, ranges } = compositeContent;
|
||||
const repoLinkUrl = `/${uri}/tree/HEAD/`;
|
||||
const fileLinkUrl = `/${uri}/blob/HEAD/${filePath}`;
|
||||
const key = `${uri}-${filePath}-${query}`;
|
||||
const lineMappingFunc = (l: number) => {
|
||||
return lineMapping[l - 1];
|
||||
};
|
||||
const repoLinkUrl = `/${uri}/tree/HEAD/`;
|
||||
const fileLinkUrl = `/${uri}/blob/HEAD/${filePath}`; // TODO(rylnd) move these to link helpers
|
||||
|
||||
return (
|
||||
<div key={`resultitem${key}`} data-test-subj="codeSearchResultList">
|
||||
<div style={{ marginBottom: '.5rem' }}>
|
||||
|
@ -75,23 +73,23 @@ export class CodeResult extends React.PureComponent<Props> {
|
|||
</EuiFlexGroup>
|
||||
<CodeBlock
|
||||
key={`code${key}`}
|
||||
language={item.language}
|
||||
startLine={0}
|
||||
code={content}
|
||||
className="codeResult__code-block"
|
||||
content={content}
|
||||
language={language}
|
||||
highlightRanges={ranges}
|
||||
folding={false}
|
||||
lineNumbersFunc={lineMappingFunc}
|
||||
onClick={this.onCodeClick.bind(this, lineMapping, fileLinkUrl)}
|
||||
lineNumber={i => lineMapping[i]}
|
||||
onClick={this.onCodeClick(fileLinkUrl)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private onCodeClick(lineNumbers: string[], fileUrl: string, pos: IPosition) {
|
||||
const line = parseInt(lineNumbers[pos.lineNumber - 1], 10);
|
||||
if (!isNaN(line)) {
|
||||
history.push(`${fileUrl}!L${line}:0`);
|
||||
private onCodeClick = (url: string) => (position: Position) => {
|
||||
const lineNumber = parseInt(position.lineNumber, 10);
|
||||
|
||||
if (!isNaN(lineNumber)) {
|
||||
history.push(`${url}!L${lineNumber}:0`);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
@import "./monaco/override_monaco_styles.scss";
|
||||
@import "./components/diff_page/diff.scss";
|
||||
@import "./components/main/main.scss";
|
||||
@import "./components/integrations/integrations.scss";
|
||||
|
||||
// TODO: Cleanup everything above this line
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
.monaco-editor.mac .margin-view-overlays .line-numbers {
|
||||
cursor: pointer;
|
||||
color: $euiColorMediumShade;
|
||||
background-color: $euiColorLightestShade;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue