Upgrade react-md, improve query explorer and improve more things

This commit is contained in:
Yair 2018-05-29 23:04:03 +03:00
Родитель 60f0739a20
Коммит 7ee71697fd
27 изменённых файлов: 633 добавлений и 116 удалений

2
client/@types/kusto.d.ts поставляемый
Просмотреть файл

@ -9,5 +9,5 @@ interface KustoTable {
DataType: string,
ColumnType: string
}[],
Rows: any[][]
Rows: {}[][]
}

Просмотреть файл

@ -30,7 +30,7 @@
"react-leaflet": "^1.7.8",
"react-leaflet-div-icon": "^1.1.0",
"react-leaflet-markercluster": "^1.1.8",
"react-md": "^1.0.18",
"react-md": "^1.3.1",
"react-render-html": "^0.1.6",
"react-router": "3.0.0",
"react-scripts-ts": "^2.6.0",
@ -54,7 +54,8 @@
"react-ace": "^5.0.1",
"react-adal": "^0.4.17",
"react-json-tree": "^0.10.9",
"xhr-request": "^1.0.1"
"xhr-request": "^1.0.1",
"react-monaco-editor": "^0.17.0"
},
"scripts": {
"css:build": "node-sass src/ -o src/",

Просмотреть файл

@ -29,7 +29,7 @@
To begin the development, run `npm start`.
To create a production bundle, use `npm run build`.
-->
<script src="../node_modules/kusto-language-service/bridge.js"></script>
<script src="../node_modules/kusto-language-service/kusto.javascript.client.js"></script>
<!-- <script src="../node_modules/kusto-language-service/bridge.js"></script>
<script src="../node_modules/kusto-language-service/kusto.javascript.client.js"></script> -->
</body>
</html>

Просмотреть файл

@ -0,0 +1,47 @@
import alt, { AbstractActions } from '../alt';
import KustoClientApi from '../api/external/KustoClientApi';
interface IQueryExplorerActions {
prepareExecuteQuery(query: string): any;
updateQuery(query: string): any;
updateResponse(response: KustoQueryResults): any;
executeQuery(clusterName: string, databaseName: string, query: string): any;
updateRenderType(newRenderType: string): any;
}
class QueryExplorerActions extends AbstractActions implements IQueryExplorerActions {
prepareExecuteQuery(query: string) {
return { query };
}
updateQuery(query: string) {
return { query };
}
updateResponse(response: KustoQueryResults) {
return { response };
}
updateRenderType(newRenderType: string) {
return { newRenderType };
}
executeQuery(clusterName: string, databaseName: string, query: string) {
this.prepareExecuteQuery(query);
let kustoClientApi = new KustoClientApi();
kustoClientApi.executeQuery(clusterName, databaseName, query)
.then((value: KustoQueryResults) => {
this.updateResponse(value);
})
.catch((reason: any) => {
// tslint:disable-next-line:no-console
console.log(reason);
});
}
}
const queryExplorerActions = alt.createActions<IQueryExplorerActions>(QueryExplorerActions);
export default queryExplorerActions;

31
client/src/api/external/KustoClientApi.ts поставляемый Normal file
Просмотреть файл

@ -0,0 +1,31 @@
import { getToken } from '../../utils/authorization';
export default class KustoClient {
public async executeQuery(cluster: string, database: string, query: string): Promise<KustoQueryResults> {
let aadToken: string = await getToken();
let kustoResponse = await fetch(`https://${cluster}.kusto.windows.net/v1/rest/query`, {
method: 'POST',
body: JSON.stringify({
'db': database,
'csl': query
}),
headers: {
'Content-Type': 'application/json; charset=utf-8',
'Authorization': `Bearer ${aadToken}`,
}
});
// 1. In case request wasn't successful - throw
if (kustoResponse.status > 300) {
let responseContent = await kustoResponse.text();
throw `Failed to query Kusto. Status code: ${kustoResponse.status},
response: ${responseContent}`;
}
let kustoResponseData: KustoQueryResults = await kustoResponse.json();
return kustoResponseData;
}
}

Просмотреть файл

@ -221,7 +221,7 @@ export default class Home extends React.Component<any, IHomeState> {
this.setState({ fileName: value });
}
onLoad(importedFileContent: any, uploadResult: string) {
onLoad(importedFileContent: File, uploadResult: string, event: Event) {
const { name, size, type, lastModifiedDate } = importedFileContent;
this.setState({ fileName: name.substr(0, name.indexOf('.')), content: uploadResult });
}
@ -233,7 +233,7 @@ export default class Home extends React.Component<any, IHomeState> {
this.setState({ importVisible: false });
}
setFile(importedFileContent: string) {
setFile(importedFileContent: File, event: Event) {
this.setState({ importedFileContent });
}

Просмотреть файл

@ -70,16 +70,16 @@ export default class Navbar extends React.Component<any, any> {
let navigationItems = [];
let toolbarTitle = null;
// Add the query explorer item
// Add the query (query explorer) item
navigationItems.push(
<ListItem
key={1001}
component={Link}
href={'/queryExplorer'}
active={'/queryExplorer' === pathname}
href={'/query'}
active={'/query' === pathname}
leftIcon={<FontIcon>{'search'}</FontIcon>}
tileClassName="md-list-tile--mini"
primaryText={name || 'Dashboard'}
primaryText={name || 'Visualization'}
/>
);

Просмотреть файл

@ -1,9 +1,12 @@
import * as React from 'react';
import injectTooltip from 'react-md/lib/Tooltips';
const Tooltip = injectTooltip(
({children, className, tooltip, ...props }) => (
<div {...props} className={(className || '') + ' inline-rel-container'} style={{position: 'relative'}}>
const Tooltip = injectTooltip<{ className?: string, children?: React.ReactNode,
style?: React.CSSProperties, tooltip?: React.ReactNode,
onClick?: (event: React.MouseEvent<HTMLElement>) => void; }>(
({children, className, style, tooltip, ...props }) => (
<div {...props} className={(className || '') + ' inline-rel-container'}
style={[style, { position: 'relative'}]}>
{tooltip}
{children}
</div>

Просмотреть файл

@ -5,7 +5,9 @@ import injectTooltip from 'react-md/lib/Tooltips';
// Material icons shouldn't have any other children other than the child string and
// it gets converted into a span if the tooltip is added, so we add a container
// around the two.
const TooltipFontIcon = injectTooltip(({
const TooltipFontIcon = injectTooltip<{ forceIconFontSize?: boolean, iconClassName?: string, className?: string,
forceIconSize?: number, style?: any, iconStyle?: React.CSSProperties,
children?: React.ReactNode, tooltip?: React.ReactNode }>(({
children, iconClassName, className, tooltip, forceIconFontSize, forceIconSize, style, iconStyle, ...props }) => (
<div {...props} style={style} className={(className || '') + ' inline-rel-container'}>

Просмотреть файл

@ -1,5 +1,4 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import XLabels from './XLabels';
import DataGrid from './DataGrid';

Просмотреть файл

@ -31,7 +31,7 @@ export interface ITableColumnProps {
click?: string;
color?: string;
tooltip?: string;
tooltipPosition?: string;
tooltipPosition?: 'top' | 'right' | 'bottom' | 'left';
}
export interface ITableProps extends IGenericProps {
@ -185,7 +185,7 @@ export default class Table extends GenericComponent<ITableProps, ITableState> {
title={title}
className={hideBorders ? 'hide-borders' : ''}
contentStyle={styles.autoscroll}>
<DataTable plain={!checkboxes} data={checkboxes} className={className} baseId="pagination" responsive={false}>
<DataTable plain={!checkboxes} className={className} baseId="pagination" responsive={false}>
<TableHeader>
<TableRow autoAdjust={false}>
{cols.map((col, i) => (

Просмотреть файл

@ -1,6 +1,8 @@
import { DataSourcePlugin, IOptions } from '../DataSourcePlugin';
import { getToken } from '../../../utils/authorization';
import KustoConnection from '../../connections/kusto';
import KustoClient from '../../../api/external/KustoClientApi';
import * as KustoUtils from '../../../utils/kusto/kustoUtils';
let connectionType = new KustoConnection();
@ -17,6 +19,8 @@ export default class KustoQuery extends DataSourcePlugin<IQueryParams> {
defaultProperty = 'values';
connectionType = connectionType.type;
private kustoClient: KustoClient = new KustoClient();
/**
* @param options - Options object
* @param connections - List of available connections
@ -58,39 +62,13 @@ export default class KustoQuery extends DataSourcePlugin<IQueryParams> {
};
return (dispatch) => {
getToken().then((token: string) => {
fetch(`https://${clusterName}.kusto.windows.net/v1/rest/query`, {
method: 'POST',
body: JSON.stringify({
'db': databaseName,
'csl': query,
}),
headers: {
'Content-Type': 'application/json; charset=utf-8',
'Authorization': `Bearer ${token}`,
}
})
.then((response) => {
response.json().then((resultTables: KustoQueryResults) => {
let parsedKustoResponse = this.mapAllTables(resultTables);
// Assign the result table
returnedResults.values = parsedKustoResponse[0];
// Extracting calculated values
if (typeof params.calculated === 'function') {
let additionalValues = params.calculated(parsedKustoResponse[0]) || {};
Object.assign(returnedResults, additionalValues);
}
return dispatch(returnedResults);
});
})
.catch((reason) => {
// tslint:disable-next-line:no-console
console.log(reason);
});
});
this.kustoClient.executeQuery(clusterName, databaseName, query)
.then((resultTables: KustoQueryResults) => {
return dispatch(KustoUtils.convertKustoResultsToJsonObjects(resultTables));
})
.catch((reason) =>
// tslint:disable-next-line:no-console
console.log(reason));
};
}
@ -108,28 +86,4 @@ export default class KustoQuery extends DataSourcePlugin<IQueryParams> {
private validateParams(params: IQueryParams): void {
}
private mapAllTables(results: KustoQueryResults): {}[][] {
if (!results || !results.Tables || !results.Tables.length) {
return [];
}
return results.Tables.map((table, idx) => this.mapTable(table));
}
/**
* Map the Kusto results array into JSON objects
* @param table Results table to be mapped into JSON object
*/
private mapTable(table: KustoTable): Array<{}> {
return table.Rows.map((rowValues, rowIdx) => {
let row = {};
table.Columns.forEach((col, idx) => {
row[col.ColumnName] = rowValues[idx];
});
return row;
});
}
}

Просмотреть файл

@ -6,6 +6,7 @@ import NotFound from './pages/NotFound';
import Home from './pages/Home';
import Dashboard from './pages/Dashboard';
import Setup from './pages/Setup';
import QueryExplorer from './scenes/QueryExplorer';
export default (
<Route component={App}>
@ -14,6 +15,7 @@ export default (
<Route path="/dashboard" component={Dashboard} />
<Route path="/dashboard/:id" component={Dashboard}/>
<Route path="/setup" component={Setup} />
<Route path="/query" component={QueryExplorer} />
<Route path="*" component={NotFound} />
</Route>
);

Просмотреть файл

@ -0,0 +1,71 @@
import * as React from 'react';
import TextField from 'react-md/lib/TextFields';
import Button from 'react-md/lib/Buttons/Button';
import MonacoQueryEditor from './components/monacoQueryEditor';
import QueryResultPreview from './components/queryResultPreview';
import QueryExplorerActions from '../../actions/QueryExplorerActions';
import './QueryExplorerStyle.css';
export interface QueryExplorerProps {
renderAs?: 'table';
}
export default class QueryExplorer extends React.Component<QueryExplorerProps> {
private queryText: string;
constructor(props: QueryExplorerProps) {
super(props);
this.onQueryTextChanged = this.onQueryTextChanged.bind(this);
this.onExecuteQuery = this.onExecuteQuery.bind(this);
this.queryText = 'MaQosSummary | limit 1000 | summarize count() by bin(TIMESTAMP, 1s)';
}
public render() {
return (
<div className="query-explorer-container">
<div className="connection-container">
<TextField
id="cluster"
label="Cluster:"
lineDirection="center"
className="md-cell--stretch"
/>
<TextField
id="database"
label="Database:"
lineDirection="center"
className="md-cell--stretch"
/>
</div>
<Button
primary
raised
label="Go"
style={{ width: 100 }}
onClick={this.onExecuteQuery}
/>
<MonacoQueryEditor onChange={this.onQueryTextChanged}/>
<div style={{ height: '21px', backgroundColor: 'gray' }} />
<QueryResultPreview renderAs="timeline" />
</div>
);
}
private onQueryTextChanged(value: string) {
this.queryText = value;
}
private onExecuteQuery() {
QueryExplorerActions.executeQuery('kuskus', 'kuskus', this.queryText);
}
}

Просмотреть файл

@ -0,0 +1,7 @@
.query-explorer-container {
height: 100vh;
& > .connection-container {
display: flex;
}
}

Просмотреть файл

@ -0,0 +1,59 @@
import * as React from 'react';
import MonacoEditor from 'react-monaco-editor';
import * as monacoEditor from 'monaco-editor';
export interface MonacoQueryEditorProps {
onChange?: (value: string) => void;
}
export default class MonacoQueryEditor extends React.Component<MonacoQueryEditorProps> {
constructor(props: MonacoQueryEditorProps) {
super(props);
}
public render() {
return (
<div style={{ height: '30%' }}>
<MonacoEditor
width="100%"
language="kusto"
theme="vs"
value="MaQosSummary | limit 1000 | summarize count() by bin(TIMESTAMP, 1s)"
options={this.getMonacoEditorSettings()}
onChange={this.props.onChange}
/>
</div>
);
}
private getMonacoEditorSettings(): monacoEditor.editor.IEditorOptions {
var minimapOptions: monacoEditor.editor.IEditorMinimapOptions = {
enabled: false
};
var scrollbarOptions: monacoEditor.editor.IEditorScrollbarOptions = {
horizontal: 'Hidden',
arrowSize: 30,
useShadows: false
};
var editorOptions: monacoEditor.editor.IEditorOptions = {
minimap: minimapOptions,
scrollbar: scrollbarOptions,
lineNumbers: 'off',
lineHeight: 19,
// fontSize: 19,
suggestFontSize: 13,
dragAndDrop: false,
occurrencesHighlight: false,
selectionHighlight: false,
renderIndentGuides: false,
wordWrap: 'off',
wordWrapColumn: 0,
renderLineHighlight: 'none',
automaticLayout: true // Auto resize whenever DOM is changing (e.g. zooming)
};
return editorOptions;
}
}

Просмотреть файл

@ -0,0 +1,3 @@
import MonacoQueryEditor from './MonacoQueryEditor';
export default MonacoQueryEditor;

Просмотреть файл

@ -0,0 +1,67 @@
import * as React from 'react';
import CircularProgress from 'react-md/lib/Progress/CircularProgress';
import TableVisual from './components/DataVisualization/TableVisual';
import TimelineVisual from './components/DataVisualization/TimelineVisual';
import QueryExplorerStore, { QueryExplorerState, QueryInformation } from '../../../../stores/QueryExplorerStore';
export interface QueryResultPreviewProps {
queryResponse?: KustoQueryResults;
renderAs?: 'table' | 'timeline';
}
export interface QueryResultPreviewState {
queryResponseInformation?: QueryInformation;
}
export default class QueryResultPreview extends React.Component<QueryResultPreviewProps, QueryResultPreviewState> {
constructor(props: QueryResultPreviewProps) {
super(props);
this.state = {
queryResponseInformation: {
isLoading: false,
query: null,
renderAs: null,
response: null
}
};
this.onQueriesExplorerStoreChange = this.onQueriesExplorerStoreChange.bind(this);
}
public componentDidMount() {
QueryExplorerStore.listen(this.onQueriesExplorerStoreChange);
}
public render() {
return (
<div style={{ height: '40%' }}>
{
(this.state.queryResponseInformation &&
this.state.queryResponseInformation.isLoading &&
<div style={{ width: '100%', top: 130, left: 0 }}>
<CircularProgress id="testerProgress" />
</div>)
}
{
(this.state.queryResponseInformation &&
!this.state.queryResponseInformation.isLoading &&
this.props.renderAs === 'table' &&
<TableVisual queryResponse={this.state.queryResponseInformation.response} />)
}
{
(this.state.queryResponseInformation &&
!this.state.queryResponseInformation.isLoading &&
this.props.renderAs === 'timeline' &&
<TimelineVisual queryResponse={this.state.queryResponseInformation.response} />)
}
</div>
);
}
private onQueriesExplorerStoreChange(queryExplorerStoreState: QueryExplorerState) {
this.setState({ queryResponseInformation: queryExplorerStoreState.queryInformation });
}
}

Просмотреть файл

@ -0,0 +1,70 @@
import * as React from 'react';
import DataTable from 'react-md/lib/DataTables/DataTable';
import TableHeader from 'react-md/lib/DataTables/TableHeader';
import TableBody from 'react-md/lib/DataTables/TableBody';
import TableRow from 'react-md/lib/DataTables/TableRow';
import TableColumn from 'react-md/lib/DataTables/TableColumn';
export interface TableVisualProps {
queryResponse?: KustoQueryResults;
}
export default class TableVisual extends React.Component<TableVisualProps> {
constructor(props: TableVisualProps) {
super(props);
}
public render() {
// Map between the Kusto response to table view
let mapResult = (response: KustoQueryResults) => {
const result = response &&
response.Tables &&
response.Tables.length > 0 &&
response.Tables[0].Rows || [];
const rows = result.map((_, i) => (
<TableRow key={i}>
{_.map(val => (<TableColumn>{val}</TableColumn>))}
</TableRow>
));
return rows;
};
// Map between
let mapColumns = (response: KustoQueryResults) => {
const result = response &&
response.Tables &&
response.Tables.length > 0 &&
response.Tables[0].Columns || [];
const columns = (
<TableRow>
{result.map((column) => (
<TableColumn>
{column.ColumnName}
</TableColumn>
))}
</TableRow>
);
return columns;
};
return (
<div style={{
background: 'white',
border: '1px',
borderStyle: 'groove'
}}>
<DataTable plain>
<TableHeader>
{mapColumns(this.props.queryResponse)}
</TableHeader>
<TableBody>
{mapResult(this.props.queryResponse)}
</TableBody>
</DataTable>
</div>
);
}
}

Просмотреть файл

@ -0,0 +1,59 @@
import * as React from 'react';
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';
import * as KustoUtils from '../../../../../../utils/kusto/kustoUtils';
export interface TimelineVisualProps {
queryResponse?: KustoQueryResults;
}
export default class TimelineVisual extends React.Component<TimelineVisualProps> {
public render() {
if (!this.isValidTimelineData(this.props.queryResponse)) {
return (<div>d</div>);
}
const data = [
{name: 'Page A', uv: 4000, pv: 2400, amt: 2400},
{name: 'Page B', uv: 3000, pv: 1398, amt: 2210},
{name: 'Page C', uv: 2000, pv: 9800, amt: 2290},
{name: 'Page D', uv: 2780, pv: 3908, amt: 2000},
{name: 'Page E', uv: 1890, pv: 4800, amt: 2181},
{name: 'Page F', uv: 2390, pv: 3800, amt: 2500},
{name: 'Page G', uv: 3490, pv: 4300, amt: 2100},
];
// Convert kusto results to valid JSON
let kustoResponseAsJsons = KustoUtils.convertKustoResultsToJsonObjects(this.props.queryResponse);
let chartData = kustoResponseAsJsons[0];
return (
<ResponsiveContainer width="100%" height="100%">
<LineChart data={chartData}
margin={{top: 5, right: 30, left: 20, bottom: 5}}>
<XAxis dataKey="TIMESTAMP"/>
<YAxis/>
<CartesianGrid strokeDasharray="3 3"/>
<Tooltip/>
<Legend />
<Line type="monotone" dataKey="count_" stroke="#8884d8" activeDot={{r: 8}}/>
</LineChart>
</ResponsiveContainer>
);
}
private isValidTimelineData(queryResponse: KustoQueryResults): boolean {
if (!queryResponse || !queryResponse.Tables || !queryResponse.Tables[0]) {
return false;
}
// Timeline data must have one datetime
let datetimeColumns = queryResponse.Tables[0].Columns
.filter(column => column.ColumnType === 'datetime');
if (!datetimeColumns || datetimeColumns.length !== 1) {
return false;
}
return true;
}
}

Просмотреть файл

@ -0,0 +1,3 @@
import QueryResultPreview from './QueryResultPreview';
export default QueryResultPreview;

Просмотреть файл

@ -1,11 +1,3 @@
import * as React from 'react';
import QueryExplorer from './QueryExplorer';
export default class QueryExplorer extends React.Component {
public render() {
return (
<div>
yalla
</div>
);
}
}
export default QueryExplorer;

Просмотреть файл

@ -0,0 +1,56 @@
import alt, { AbstractStoreModel } from '../alt';
import queryExplorerActions from '../actions/QueryExplorerActions';
export interface QueryInformation {
query?: string;
response?: KustoQueryResults;
isLoading?: boolean;
renderAs?: 'table' | 'timeline' | 'bars' | 'pie';
}
export interface QueryExplorerState {
queryInformation: QueryInformation;
}
class QueryExplorerStore extends AbstractStoreModel<QueryExplorerState> implements QueryExplorerState {
queryInformation: QueryInformation;
constructor() {
super();
this.queryInformation = {
isLoading: false,
};
// TODO - get the values from a cookie, else initialize it
this.bindListeners({
prepareExecuteQuery: queryExplorerActions.prepareExecuteQuery,
updateQuery: queryExplorerActions.updateQuery,
updateResponse: queryExplorerActions.updateResponse,
updateRenderType: queryExplorerActions.updateRenderType
});
}
updateQuery(state: any) {
this.queryInformation.query = state.query;
}
updateResponse(state: any) {
this.queryInformation.isLoading = false;
this.queryInformation.response = state.response;
}
updateRenderType(state: any) {
this.queryInformation.renderAs = state.newRenderType;
}
prepareExecuteQuery(state: any) {
this.queryInformation.isLoading = true;
}
}
const queryExplorerStore = alt.createStore<QueryExplorerState>((QueryExplorerStore as AltJS.StoreModel<any>),
'QueryExplorerStore');
export default queryExplorerStore;

Просмотреть файл

@ -52,7 +52,7 @@ export function timespan(
'P90D';
let granularity =
state.selectedValue === '24 hours' ? '5m' :
state.selectedValue === '24 hours' ? '1h' :
state.selectedValue === '1 week' ? '1d' : '1d';
let result = {

Просмотреть файл

@ -0,0 +1,27 @@
/**
* Convert the given Kusto query result to a list of JSON object per table
* @param results The Kusto response
*/
export function convertKustoResultsToJsonObjects(results: KustoQueryResults): {}[][] {
if (!results || !results.Tables || !results.Tables.length) {
return [];
}
return results.Tables.map((table, idx) => mapTable(table));
}
/**
* Map the Kusto results array into JSON objects
* @param table Results table to be mapped into JSON object
*/
function mapTable(table: KustoTable): Array<{}> {
return table.Rows.map((rowValues, rowIdx) => {
let row = {};
table.Columns.forEach((col, idx) => {
row[col.ColumnName] = rowValues[idx];
});
return row;
});
}

Просмотреть файл

@ -2,6 +2,13 @@
# yarn lockfile v1
"@babel/runtime@^7.0.0-beta.42":
version "7.0.0-beta.47"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.0.0-beta.47.tgz#273f5e71629e80f6cbcd7507503848615e59f7e0"
dependencies:
core-js "^2.5.3"
regenerator-runtime "^0.11.1"
"@types/alt@^0.16.32":
version "0.16.34"
resolved "https://registry.yarnpkg.com/@types/alt/-/alt-0.16.34.tgz#8097539b86912f24bf1841d5414a7408c98fc7b1"
@ -535,7 +542,7 @@ babel-runtime@6.23.0:
core-js "^2.4.0"
regenerator-runtime "^0.10.0"
babel-runtime@^6.20.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.26.0, babel-runtime@^6.6.1:
babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.26.0, babel-runtime@^6.6.1:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
dependencies:
@ -1194,6 +1201,10 @@ core-js@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.0.tgz#569c050918be6486b3837552028ae0466b717086"
core-js@^2.5.3:
version "2.5.6"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.6.tgz#0fe6d45bf3cac3ac364a9d72de7576f4eb221b9d"
core-util-is@1.0.2, core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
@ -2032,6 +2043,18 @@ fbjs@0.1.0-alpha.7:
promise "^7.0.3"
whatwg-fetch "^0.9.0"
fbjs@^0.8.16:
version "0.8.16"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db"
dependencies:
core-js "^1.0.0"
isomorphic-fetch "^2.1.1"
loose-envify "^1.0.0"
object-assign "^4.1.0"
promise "^7.1.1"
setimmediate "^1.0.5"
ua-parser-js "^0.7.9"
fbjs@^0.8.4, fbjs@^0.8.9:
version "0.8.14"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.14.tgz#d1dbe2be254c35a91e09f31f9cd50a40b2a0ed1c"
@ -3806,6 +3829,10 @@ moment@^2.10.6, moment@^2.14.1, moment@^2.18.0:
version "2.18.1"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.18.1.tgz#c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f"
monaco-editor@^0.13.1:
version "0.13.1"
resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.13.1.tgz#6b9ce20e4d1c945042d256825eb133cb23315a52"
monaco-kusto@^0.0.10:
version "0.0.10"
resolved "https://1essharedassets.pkgs.visualstudio.com/_packaging/Kusto/npm/registry/monaco-kusto/-/monaco-kusto-0.0.10.tgz#afa6d1c5525dd60a1b6b45873fb3f23ef531268b"
@ -4837,6 +4864,14 @@ promise@7.1.1, promise@^7.0.3, promise@^7.1.1:
dependencies:
asap "~2.0.3"
prop-types@15.6.0:
version "15.6.0"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856"
dependencies:
fbjs "^0.8.16"
loose-envify "^1.3.1"
object-assign "^4.1.1"
prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.6, prop-types@^15.5.8:
version "15.5.10"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.10.tgz#2797dfc3126182e3a95e3dfbb2e893ddd7456154"
@ -4844,6 +4879,14 @@ prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.6, prop-types@^15.5.8:
fbjs "^0.8.9"
loose-envify "^1.3.1"
prop-types@^15.6.0, prop-types@^15.6.1:
version "15.6.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.1.tgz#36644453564255ddda391191fb3a125cbdf654ca"
dependencies:
fbjs "^0.8.16"
loose-envify "^1.3.1"
object-assign "^4.1.1"
propagate@0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/propagate/-/propagate-0.4.0.tgz#f3fcca0a6fe06736a7ba572966069617c130b481"
@ -5069,13 +5112,13 @@ react-error-overlay@^1.0.8:
settle-promise "1.0.0"
source-map "0.5.6"
react-event-listener@^0.4.5:
version "0.4.5"
resolved "https://registry.yarnpkg.com/react-event-listener/-/react-event-listener-0.4.5.tgz#e3e895a0970cf14ee8f890113af68197abf3d0b1"
react-event-listener@^0.5.1:
version "0.5.6"
resolved "https://registry.yarnpkg.com/react-event-listener/-/react-event-listener-0.5.6.tgz#f9349fda4b7735fc6886ca403bdcfd6057e89ceb"
dependencies:
babel-runtime "^6.20.0"
fbjs "^0.8.4"
prop-types "^15.5.4"
"@babel/runtime" "^7.0.0-beta.42"
fbjs "^0.8.16"
prop-types "^15.6.0"
warning "^3.0.0"
react-grid-layout@^0.14.7:
@ -5116,19 +5159,26 @@ react-leaflet@^1.7.8:
lodash-es "^4.0.0"
warning "^3.0.0"
react-md@^1.0.18:
version "1.0.19"
resolved "https://registry.yarnpkg.com/react-md/-/react-md-1.0.19.tgz#45d46b240435a008218121b5db8b0af71cf63ae8"
react-md@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/react-md/-/react-md-1.3.1.tgz#4423610cc191b5ce3a6e322ace75c3aba610ebe9"
dependencies:
classnames "^2.2.5"
invariant "^2.2.1"
prop-types "^15.5.8"
prop-types "15.6.0"
react-motion "^0.5.0"
react-prop-types "^0.4.0"
react-swipeable-views "^0.12.1"
react-transition-group "^1.1.3"
react-swipeable-views "^0.12.8"
react-transition-group "^1.2.1"
resize-observer-polyfill "^1.4.2"
react-monaco-editor@^0.17.0:
version "0.17.0"
resolved "https://registry.yarnpkg.com/react-monaco-editor/-/react-monaco-editor-0.17.0.tgz#d8e79f797c5b7684079424693daec8ca1258bb51"
dependencies:
"@types/react" "*"
monaco-editor "^0.13.1"
prop-types "^15.6.1"
react-motion@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/react-motion/-/react-motion-0.5.0.tgz#1708fc2aee552900d21c1e6bed28346863e017b6"
@ -5220,36 +5270,36 @@ react-smooth@0.1.20:
raf "^3.2.0"
react-addons-transition-group "^0.14.0 || ^15.0.0"
react-swipeable-views-core@^0.12.5:
version "0.12.5"
resolved "https://registry.yarnpkg.com/react-swipeable-views-core/-/react-swipeable-views-core-0.12.5.tgz#7113f3a5c84f85042447a7c49e3f2a206eab7931"
react-swipeable-views-core@^0.12.11:
version "0.12.11"
resolved "https://registry.yarnpkg.com/react-swipeable-views-core/-/react-swipeable-views-core-0.12.11.tgz#3cf2b4daffbb36f9d69bd19bf5b2d5370b6b2c1b"
dependencies:
babel-runtime "^6.23.0"
warning "^3.0.0"
react-swipeable-views-utils@^0.12.5:
version "0.12.5"
resolved "https://registry.yarnpkg.com/react-swipeable-views-utils/-/react-swipeable-views-utils-0.12.5.tgz#878de2108c8fb5160cc3122de10c3ff741a28801"
react-swipeable-views-utils@^0.12.13:
version "0.12.13"
resolved "https://registry.yarnpkg.com/react-swipeable-views-utils/-/react-swipeable-views-utils-0.12.13.tgz#fe102524180bf568f746e844c8d74b9cd3e7e0b8"
dependencies:
babel-runtime "^6.23.0"
fbjs "^0.8.4"
keycode "^2.1.7"
prop-types "^15.5.4"
react-event-listener "^0.4.5"
react-swipeable-views-core "^0.12.5"
prop-types "^15.6.0"
react-event-listener "^0.5.1"
react-swipeable-views-core "^0.12.11"
react-swipeable-views@^0.12.1:
version "0.12.5"
resolved "https://registry.yarnpkg.com/react-swipeable-views/-/react-swipeable-views-0.12.5.tgz#ff43b35e05c56614bb63ab032769ec8fe9259b0e"
react-swipeable-views@^0.12.8:
version "0.12.13"
resolved "https://registry.yarnpkg.com/react-swipeable-views/-/react-swipeable-views-0.12.13.tgz#247442dbe14922efe5ad6fe0297599c817600bf9"
dependencies:
babel-runtime "^6.23.0"
dom-helpers "^3.2.1"
prop-types "^15.5.4"
react-swipeable-views-core "^0.12.5"
react-swipeable-views-utils "^0.12.5"
react-swipeable-views-core "^0.12.11"
react-swipeable-views-utils "^0.12.13"
warning "^3.0.0"
react-transition-group@^1.1.3, react-transition-group@^1.2.0:
react-transition-group@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-1.2.0.tgz#b51fc921b0c3835a7ef7c571c79fc82c73e9204f"
dependencies:
@ -5259,6 +5309,16 @@ react-transition-group@^1.1.3, react-transition-group@^1.2.0:
prop-types "^15.5.6"
warning "^3.0.0"
react-transition-group@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-1.2.1.tgz#e11f72b257f921b213229a774df46612346c7ca6"
dependencies:
chain-function "^1.0.0"
dom-helpers "^3.2.0"
loose-envify "^1.3.1"
prop-types "^15.5.6"
warning "^3.0.0"
react@^15.4.2:
version "15.6.1"
resolved "https://registry.yarnpkg.com/react/-/react-15.6.1.tgz#baa8434ec6780bde997cdc380b79cd33b96393df"
@ -5393,6 +5453,10 @@ regenerator-runtime@^0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz#7e54fe5b5ccd5d6624ea6255c3473be090b802e1"
regenerator-runtime@^0.11.1:
version "0.11.1"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
regex-cache@^0.4.2:
version "0.4.3"
resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145"

Просмотреть файл

@ -38,7 +38,7 @@ Or
# Examples
## Updading selected values in filter
## Updating selected values in filter
```ts
{