Fix: reverted back to import * as module instead of using namespaces (#23069)

* Removed namespace declaration to prevent issues with external plugins.

* fixed imports and tests.
This commit is contained in:
Marcus Andersson 2020-03-25 17:01:43 +01:00 committed by GitHub
parent c4693378dd
commit f75387bd14
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 427 additions and 438 deletions

View File

@ -1,7 +1,7 @@
import sinon, { SinonFakeTimers } from 'sinon'; import sinon, { SinonFakeTimers } from 'sinon';
import each from 'lodash/each'; import each from 'lodash/each';
import { dateMath } from './datemath'; import * as dateMath from './datemath';
import { dateTime, DurationUnit, DateTime } from './moment_wrapper'; import { dateTime, DurationUnit, DateTime } from './moment_wrapper';
describe('DateMath', () => { describe('DateMath', () => {

View File

@ -5,161 +5,158 @@ import { TimeZone } from '../types/index';
const units: DurationUnit[] = ['y', 'M', 'w', 'd', 'h', 'm', 's']; const units: DurationUnit[] = ['y', 'M', 'w', 'd', 'h', 'm', 's'];
// eslint-disable-next-line @typescript-eslint/no-namespace export function isMathString(text: string | DateTime | Date): boolean {
export namespace dateMath { if (!text) {
export function isMathString(text: string | DateTime | Date): boolean {
if (!text) {
return false;
}
if (typeof text === 'string' && (text.substring(0, 3) === 'now' || text.includes('||'))) {
return true;
} else {
return false;
}
}
/**
* Parses different types input to a moment instance. There is a specific formatting language that can be used
* if text arg is string. See unit tests for examples.
* @param text
* @param roundUp See parseDateMath function.
* @param timezone Only string 'utc' is acceptable here, for anything else, local timezone is used.
*/
export function parse(
text?: string | DateTime | Date | null,
roundUp?: boolean,
timezone?: TimeZone
): DateTime | undefined {
if (!text) {
return undefined;
}
if (typeof text !== 'string') {
if (isDateTime(text)) {
return text;
}
if (isDate(text)) {
return dateTime(text);
}
// We got some non string which is not a moment nor Date. TS should be able to check for that but not always.
return undefined;
} else {
let time;
let mathString = '';
let index;
let parseString;
if (text.substring(0, 3) === 'now') {
time = dateTimeForTimeZone(timezone);
mathString = text.substring('now'.length);
} else {
index = text.indexOf('||');
if (index === -1) {
parseString = text;
mathString = ''; // nothing else
} else {
parseString = text.substring(0, index);
mathString = text.substring(index + 2);
}
// We're going to just require ISO8601 timestamps, k?
time = dateTime(parseString, ISO_8601);
}
if (!mathString.length) {
return time;
}
return parseDateMath(mathString, time, roundUp);
}
}
/**
* Checks if text is a valid date which in this context means that it is either a Moment instance or it can be parsed
* by parse function. See parse function to see what is considered acceptable.
* @param text
*/
export function isValid(text: string | DateTime): boolean {
const date = parse(text);
if (!date) {
return false;
}
if (isDateTime(date)) {
return date.isValid();
}
return false; return false;
} }
/** if (typeof text === 'string' && (text.substring(0, 3) === 'now' || text.includes('||'))) {
* Parses math part of the time string and shifts supplied time according to that math. See unit tests for examples. return true;
* @param mathString } else {
* @param time return false;
* @param roundUp If true it will round the time to endOf time unit, otherwise to startOf time unit. }
*/ }
// TODO: Had to revert Andrejs `time: moment.Moment` to `time: any`
export function parseDateMath(mathString: string, time: any, roundUp?: boolean): DateTime | undefined {
const strippedMathString = mathString.replace(/\s/g, '');
const dateTime = time;
let i = 0;
const len = strippedMathString.length;
while (i < len) { /**
const c = strippedMathString.charAt(i++); * Parses different types input to a moment instance. There is a specific formatting language that can be used
let type; * if text arg is string. See unit tests for examples.
let num; * @param text
let unit; * @param roundUp See parseDateMath function.
* @param timezone Only string 'utc' is acceptable here, for anything else, local timezone is used.
*/
export function parse(
text?: string | DateTime | Date | null,
roundUp?: boolean,
timezone?: TimeZone
): DateTime | undefined {
if (!text) {
return undefined;
}
if (c === '/') { if (typeof text !== 'string') {
type = 0; if (isDateTime(text)) {
} else if (c === '+') { return text;
type = 1; }
} else if (c === '-') { if (isDate(text)) {
type = 2; return dateTime(text);
}
// We got some non string which is not a moment nor Date. TS should be able to check for that but not always.
return undefined;
} else {
let time;
let mathString = '';
let index;
let parseString;
if (text.substring(0, 3) === 'now') {
time = dateTimeForTimeZone(timezone);
mathString = text.substring('now'.length);
} else {
index = text.indexOf('||');
if (index === -1) {
parseString = text;
mathString = ''; // nothing else
} else { } else {
return undefined; parseString = text.substring(0, index);
mathString = text.substring(index + 2);
} }
// We're going to just require ISO8601 timestamps, k?
time = dateTime(parseString, ISO_8601);
}
if (isNaN(parseInt(strippedMathString.charAt(i), 10))) { if (!mathString.length) {
num = 1; return time;
} else if (strippedMathString.length === 2) { }
num = strippedMathString.charAt(i);
} else {
const numFrom = i;
while (!isNaN(parseInt(strippedMathString.charAt(i), 10))) {
i++;
if (i > 10) {
return undefined;
}
}
num = parseInt(strippedMathString.substring(numFrom, i), 10);
}
if (type === 0) { return parseDateMath(mathString, time, roundUp);
// rounding is only allowed on whole, single, units (eg M or 1M, not 0.5M or 2M) }
if (num !== 1) { }
/**
* Checks if text is a valid date which in this context means that it is either a Moment instance or it can be parsed
* by parse function. See parse function to see what is considered acceptable.
* @param text
*/
export function isValid(text: string | DateTime): boolean {
const date = parse(text);
if (!date) {
return false;
}
if (isDateTime(date)) {
return date.isValid();
}
return false;
}
/**
* Parses math part of the time string and shifts supplied time according to that math. See unit tests for examples.
* @param mathString
* @param time
* @param roundUp If true it will round the time to endOf time unit, otherwise to startOf time unit.
*/
// TODO: Had to revert Andrejs `time: moment.Moment` to `time: any`
export function parseDateMath(mathString: string, time: any, roundUp?: boolean): DateTime | undefined {
const strippedMathString = mathString.replace(/\s/g, '');
const dateTime = time;
let i = 0;
const len = strippedMathString.length;
while (i < len) {
const c = strippedMathString.charAt(i++);
let type;
let num;
let unit;
if (c === '/') {
type = 0;
} else if (c === '+') {
type = 1;
} else if (c === '-') {
type = 2;
} else {
return undefined;
}
if (isNaN(parseInt(strippedMathString.charAt(i), 10))) {
num = 1;
} else if (strippedMathString.length === 2) {
num = strippedMathString.charAt(i);
} else {
const numFrom = i;
while (!isNaN(parseInt(strippedMathString.charAt(i), 10))) {
i++;
if (i > 10) {
return undefined; return undefined;
} }
} }
unit = strippedMathString.charAt(i++); num = parseInt(strippedMathString.substring(numFrom, i), 10);
}
if (!includes(units, unit)) { if (type === 0) {
// rounding is only allowed on whole, single, units (eg M or 1M, not 0.5M or 2M)
if (num !== 1) {
return undefined; return undefined;
} else {
if (type === 0) {
if (roundUp) {
dateTime.endOf(unit);
} else {
dateTime.startOf(unit);
}
} else if (type === 1) {
dateTime.add(num, unit);
} else if (type === 2) {
dateTime.subtract(num, unit);
}
} }
} }
return dateTime; unit = strippedMathString.charAt(i++);
if (!includes(units, unit)) {
return undefined;
} else {
if (type === 0) {
if (roundUp) {
dateTime.endOf(unit);
} else {
dateTime.startOf(unit);
}
} else if (type === 1) {
dateTime.add(num, unit);
} else if (type === 2) {
dateTime.subtract(num, unit);
}
}
} }
return dateTime;
} }

View File

@ -1,6 +1,7 @@
// Names are too general to export globally // Names are too general to export globally
export { dateMath } from './datemath'; import * as dateMath from './datemath';
export { rangeUtil } from './rangeutil'; import * as rangeUtil from './rangeutil';
export * from './moment_wrapper'; export * from './moment_wrapper';
export * from './timezones'; export * from './timezones';
export * from './formats'; export * from './formats';
export { dateMath, rangeUtil };

View File

@ -3,183 +3,180 @@ import groupBy from 'lodash/groupBy';
import { RawTimeRange } from '../types/time'; import { RawTimeRange } from '../types/time';
import { dateMath } from './datemath'; import * as dateMath from './datemath';
import { isDateTime, DateTime } from './moment_wrapper'; import { isDateTime, DateTime } from './moment_wrapper';
// eslint-disable-next-line @typescript-eslint/no-namespace const spans: { [key: string]: { display: string; section?: number } } = {
export namespace rangeUtil { s: { display: 'second' },
const spans: { [key: string]: { display: string; section?: number } } = { m: { display: 'minute' },
s: { display: 'second' }, h: { display: 'hour' },
m: { display: 'minute' }, d: { display: 'day' },
h: { display: 'hour' }, w: { display: 'week' },
d: { display: 'day' }, M: { display: 'month' },
w: { display: 'week' }, y: { display: 'year' },
M: { display: 'month' }, };
y: { display: 'year' },
};
const rangeOptions = [ const rangeOptions = [
{ from: 'now/d', to: 'now/d', display: 'Today', section: 2 }, { from: 'now/d', to: 'now/d', display: 'Today', section: 2 },
{ from: 'now/d', to: 'now', display: 'Today so far', section: 2 }, { from: 'now/d', to: 'now', display: 'Today so far', section: 2 },
{ from: 'now/w', to: 'now/w', display: 'This week', section: 2 }, { from: 'now/w', to: 'now/w', display: 'This week', section: 2 },
{ from: 'now/w', to: 'now', display: 'This week so far', section: 2 }, { from: 'now/w', to: 'now', display: 'This week so far', section: 2 },
{ from: 'now/M', to: 'now/M', display: 'This month', section: 2 }, { from: 'now/M', to: 'now/M', display: 'This month', section: 2 },
{ from: 'now/M', to: 'now', display: 'This month so far', section: 2 }, { from: 'now/M', to: 'now', display: 'This month so far', section: 2 },
{ from: 'now/y', to: 'now/y', display: 'This year', section: 2 }, { from: 'now/y', to: 'now/y', display: 'This year', section: 2 },
{ from: 'now/y', to: 'now', display: 'This year so far', section: 2 }, { from: 'now/y', to: 'now', display: 'This year so far', section: 2 },
{ from: 'now-1d/d', to: 'now-1d/d', display: 'Yesterday', section: 1 }, { from: 'now-1d/d', to: 'now-1d/d', display: 'Yesterday', section: 1 },
{ {
from: 'now-2d/d', from: 'now-2d/d',
to: 'now-2d/d', to: 'now-2d/d',
display: 'Day before yesterday', display: 'Day before yesterday',
section: 1, section: 1,
}, },
{ {
from: 'now-7d/d', from: 'now-7d/d',
to: 'now-7d/d', to: 'now-7d/d',
display: 'This day last week', display: 'This day last week',
section: 1, section: 1,
}, },
{ from: 'now-1w/w', to: 'now-1w/w', display: 'Previous week', section: 1 }, { from: 'now-1w/w', to: 'now-1w/w', display: 'Previous week', section: 1 },
{ from: 'now-1M/M', to: 'now-1M/M', display: 'Previous month', section: 1 }, { from: 'now-1M/M', to: 'now-1M/M', display: 'Previous month', section: 1 },
{ from: 'now-1y/y', to: 'now-1y/y', display: 'Previous year', section: 1 }, { from: 'now-1y/y', to: 'now-1y/y', display: 'Previous year', section: 1 },
{ from: 'now-5m', to: 'now', display: 'Last 5 minutes', section: 3 }, { from: 'now-5m', to: 'now', display: 'Last 5 minutes', section: 3 },
{ from: 'now-15m', to: 'now', display: 'Last 15 minutes', section: 3 }, { from: 'now-15m', to: 'now', display: 'Last 15 minutes', section: 3 },
{ from: 'now-30m', to: 'now', display: 'Last 30 minutes', section: 3 }, { from: 'now-30m', to: 'now', display: 'Last 30 minutes', section: 3 },
{ from: 'now-1h', to: 'now', display: 'Last 1 hour', section: 3 }, { from: 'now-1h', to: 'now', display: 'Last 1 hour', section: 3 },
{ from: 'now-3h', to: 'now', display: 'Last 3 hours', section: 3 }, { from: 'now-3h', to: 'now', display: 'Last 3 hours', section: 3 },
{ from: 'now-6h', to: 'now', display: 'Last 6 hours', section: 3 }, { from: 'now-6h', to: 'now', display: 'Last 6 hours', section: 3 },
{ from: 'now-12h', to: 'now', display: 'Last 12 hours', section: 3 }, { from: 'now-12h', to: 'now', display: 'Last 12 hours', section: 3 },
{ from: 'now-24h', to: 'now', display: 'Last 24 hours', section: 3 }, { from: 'now-24h', to: 'now', display: 'Last 24 hours', section: 3 },
{ from: 'now-2d', to: 'now', display: 'Last 2 days', section: 0 }, { from: 'now-2d', to: 'now', display: 'Last 2 days', section: 0 },
{ from: 'now-7d', to: 'now', display: 'Last 7 days', section: 0 }, { from: 'now-7d', to: 'now', display: 'Last 7 days', section: 0 },
{ from: 'now-30d', to: 'now', display: 'Last 30 days', section: 0 }, { from: 'now-30d', to: 'now', display: 'Last 30 days', section: 0 },
{ from: 'now-90d', to: 'now', display: 'Last 90 days', section: 0 }, { from: 'now-90d', to: 'now', display: 'Last 90 days', section: 0 },
{ from: 'now-6M', to: 'now', display: 'Last 6 months', section: 0 }, { from: 'now-6M', to: 'now', display: 'Last 6 months', section: 0 },
{ from: 'now-1y', to: 'now', display: 'Last 1 year', section: 0 }, { from: 'now-1y', to: 'now', display: 'Last 1 year', section: 0 },
{ from: 'now-2y', to: 'now', display: 'Last 2 years', section: 0 }, { from: 'now-2y', to: 'now', display: 'Last 2 years', section: 0 },
{ from: 'now-5y', to: 'now', display: 'Last 5 years', section: 0 }, { from: 'now-5y', to: 'now', display: 'Last 5 years', section: 0 },
]; ];
const absoluteFormat = 'YYYY-MM-DD HH:mm:ss'; const absoluteFormat = 'YYYY-MM-DD HH:mm:ss';
const rangeIndex: any = {}; const rangeIndex: any = {};
each(rangeOptions, (frame: any) => { each(rangeOptions, (frame: any) => {
rangeIndex[frame.from + ' to ' + frame.to] = frame; rangeIndex[frame.from + ' to ' + frame.to] = frame;
});
export function getRelativeTimesList(timepickerSettings: any, currentDisplay: any) {
const groups = groupBy(rangeOptions, (option: any) => {
option.active = option.display === currentDisplay;
return option.section;
}); });
export function getRelativeTimesList(timepickerSettings: any, currentDisplay: any) { // _.each(timepickerSettings.time_options, (duration: string) => {
const groups = groupBy(rangeOptions, (option: any) => { // let info = describeTextRange(duration);
option.active = option.display === currentDisplay; // if (info.section) {
return option.section; // groups[info.section].push(info);
}); // }
// });
// _.each(timepickerSettings.time_options, (duration: string) => { return groups;
// let info = describeTextRange(duration); }
// if (info.section) {
// groups[info.section].push(info);
// }
// });
return groups; function formatDate(date: DateTime) {
return date.format(absoluteFormat);
}
// handles expressions like
// 5m
// 5m to now/d
// now/d to now
// now/d
// if no to <expr> then to now is assumed
export function describeTextRange(expr: any) {
const isLast = expr.indexOf('+') !== 0;
if (expr.indexOf('now') === -1) {
expr = (isLast ? 'now-' : 'now') + expr;
} }
function formatDate(date: DateTime) { let opt = rangeIndex[expr + ' to now'];
return date.format(absoluteFormat); if (opt) {
}
// handles expressions like
// 5m
// 5m to now/d
// now/d to now
// now/d
// if no to <expr> then to now is assumed
export function describeTextRange(expr: any) {
const isLast = expr.indexOf('+') !== 0;
if (expr.indexOf('now') === -1) {
expr = (isLast ? 'now-' : 'now') + expr;
}
let opt = rangeIndex[expr + ' to now'];
if (opt) {
return opt;
}
if (isLast) {
opt = { from: expr, to: 'now' };
} else {
opt = { from: 'now', to: expr };
}
const parts = /^now([-+])(\d+)(\w)/.exec(expr);
if (parts) {
const unit = parts[3];
const amount = parseInt(parts[2], 10);
const span = spans[unit];
if (span) {
opt.display = isLast ? 'Last ' : 'Next ';
opt.display += amount + ' ' + span.display;
opt.section = span.section;
if (amount > 1) {
opt.display += 's';
}
}
} else {
opt.display = opt.from + ' to ' + opt.to;
opt.invalid = true;
}
return opt; return opt;
} }
/** if (isLast) {
* Use this function to get a properly formatted string representation of a {@link @grafana/data:RawTimeRange | range}. opt = { from: expr, to: 'now' };
* } else {
* @example opt = { from: 'now', to: expr };
* ```
* // Prints "2":
* console.log(add(1,1));
* ```
* @category TimeUtils
* @param range - a time range (usually specified by the TimePicker)
* @alpha
*/
export function describeTimeRange(range: RawTimeRange): string {
const option = rangeIndex[range.from.toString() + ' to ' + range.to.toString()];
if (option) {
return option.display;
}
if (isDateTime(range.from) && isDateTime(range.to)) {
return formatDate(range.from) + ' to ' + formatDate(range.to);
}
if (isDateTime(range.from)) {
const toMoment = dateMath.parse(range.to, true);
return toMoment ? formatDate(range.from) + ' to ' + toMoment.fromNow() : '';
}
if (isDateTime(range.to)) {
const from = dateMath.parse(range.from, false);
return from ? from.fromNow() + ' to ' + formatDate(range.to) : '';
}
if (range.to.toString() === 'now') {
const res = describeTextRange(range.from);
return res.display;
}
return range.from.toString() + ' to ' + range.to.toString();
} }
export const isValidTimeSpan = (value: string) => { const parts = /^now([-+])(\d+)(\w)/.exec(expr);
if (value.indexOf('$') === 0 || value.indexOf('+$') === 0) { if (parts) {
return true; const unit = parts[3];
const amount = parseInt(parts[2], 10);
const span = spans[unit];
if (span) {
opt.display = isLast ? 'Last ' : 'Next ';
opt.display += amount + ' ' + span.display;
opt.section = span.section;
if (amount > 1) {
opt.display += 's';
}
} }
} else {
opt.display = opt.from + ' to ' + opt.to;
opt.invalid = true;
}
const info = describeTextRange(value); return opt;
return info.invalid !== true;
};
} }
/**
* Use this function to get a properly formatted string representation of a {@link @grafana/data:RawTimeRange | range}.
*
* @example
* ```
* // Prints "2":
* console.log(add(1,1));
* ```
* @category TimeUtils
* @param range - a time range (usually specified by the TimePicker)
* @alpha
*/
export function describeTimeRange(range: RawTimeRange): string {
const option = rangeIndex[range.from.toString() + ' to ' + range.to.toString()];
if (option) {
return option.display;
}
if (isDateTime(range.from) && isDateTime(range.to)) {
return formatDate(range.from) + ' to ' + formatDate(range.to);
}
if (isDateTime(range.from)) {
const toMoment = dateMath.parse(range.to, true);
return toMoment ? formatDate(range.from) + ' to ' + toMoment.fromNow() : '';
}
if (isDateTime(range.to)) {
const from = dateMath.parse(range.from, false);
return from ? from.fromNow() + ' to ' + formatDate(range.to) : '';
}
if (range.to.toString() === 'now') {
const res = describeTextRange(range.from);
return res.display;
}
return range.from.toString() + ' to ' + range.to.toString();
}
export const isValidTimeSpan = (value: string) => {
if (value.indexOf('$') === 0 || value.indexOf('+$') === 0) {
return true;
}
const info = describeTextRange(value);
return info.invalid !== true;
};

View File

@ -5,11 +5,8 @@ export interface AppEvent<T> {
payload?: T; payload?: T;
} }
// eslint-disable-next-line @typescript-eslint/no-namespace export type AlertPayload = [string, string?];
export namespace AppEvents {
export type AlertPayload = [string, string?];
export const alertSuccess = eventFactory<AlertPayload>('alert-success'); export const alertSuccess = eventFactory<AlertPayload>('alert-success');
export const alertWarning = eventFactory<AlertPayload>('alert-warning'); export const alertWarning = eventFactory<AlertPayload>('alert-warning');
export const alertError = eventFactory<AlertPayload>('alert-error'); export const alertError = eventFactory<AlertPayload>('alert-error');
}

View File

@ -24,5 +24,9 @@ export * from './theme';
export * from './orgs'; export * from './orgs';
export * from './flot'; export * from './flot';
export { AppEvent, AppEvents } from './appEvents'; import * as AppEvents from './appEvents';
export { PanelEvents } from './panelEvents'; import { AppEvent } from './appEvents';
export { AppEvent, AppEvents };
import * as PanelEvents from './panelEvents';
export { PanelEvents };

View File

@ -2,28 +2,25 @@ import { eventFactory } from './utils';
import { DataQueryError, DataQueryResponseData } from './datasource'; import { DataQueryError, DataQueryResponseData } from './datasource';
import { AngularPanelMenuItem } from './panel'; import { AngularPanelMenuItem } from './panel';
// eslint-disable-next-line @typescript-eslint/no-namespace /** Payloads */
export namespace PanelEvents { export interface PanelChangeViewPayload {
/** Payloads */ fullscreen?: boolean;
export interface PanelChangeViewPayload { edit?: boolean;
fullscreen?: boolean; panelId?: number;
edit?: boolean; toggle?: boolean;
panelId?: number;
toggle?: boolean;
}
/** Events */
export const refresh = eventFactory('refresh');
export const componentDidMount = eventFactory('component-did-mount');
export const dataError = eventFactory<DataQueryError>('data-error');
export const dataReceived = eventFactory<DataQueryResponseData[]>('data-received');
export const dataSnapshotLoad = eventFactory<DataQueryResponseData[]>('data-snapshot-load');
export const editModeInitialized = eventFactory('init-edit-mode');
export const initPanelActions = eventFactory<AngularPanelMenuItem[]>('init-panel-actions');
export const panelChangeView = eventFactory<PanelChangeViewPayload>('panel-change-view');
export const panelInitialized = eventFactory('panel-initialized');
export const panelSizeChanged = eventFactory('panel-size-changed');
export const panelTeardown = eventFactory('panel-teardown');
export const render = eventFactory<any>('render');
export const viewModeChanged = eventFactory('view-mode-changed');
} }
/** Events */
export const refresh = eventFactory('refresh');
export const componentDidMount = eventFactory('component-did-mount');
export const dataError = eventFactory<DataQueryError>('data-error');
export const dataReceived = eventFactory<DataQueryResponseData[]>('data-received');
export const dataSnapshotLoad = eventFactory<DataQueryResponseData[]>('data-snapshot-load');
export const editModeInitialized = eventFactory('init-edit-mode');
export const initPanelActions = eventFactory<AngularPanelMenuItem[]>('init-panel-actions');
export const panelChangeView = eventFactory<PanelChangeViewPayload>('panel-change-view');
export const panelInitialized = eventFactory('panel-initialized');
export const panelSizeChanged = eventFactory('panel-size-changed');
export const panelTeardown = eventFactory('panel-teardown');
export const render = eventFactory<any>('render');
export const viewModeChanged = eventFactory('view-mode-changed');

View File

@ -2,7 +2,7 @@ import React, { ChangeEvent } from 'react';
import { HorizontalGroup } from '../Layout/Layout'; import { HorizontalGroup } from '../Layout/Layout';
import Forms from '../Forms'; import Forms from '../Forms';
import { MappingType, RangeMap, ValueMap, ValueMapping } from '@grafana/data'; import { MappingType, RangeMap, ValueMap, ValueMapping } from '@grafana/data';
import { styleMixins } from '../../themes/mixins'; import * as styleMixins from '../../themes/mixins';
import { useTheme } from '../../themes'; import { useTheme } from '../../themes';
import { FieldConfigItemHeaderTitle } from '../FieldConfigs/FieldConfigItemHeaderTitle'; import { FieldConfigItemHeaderTitle } from '../FieldConfigs/FieldConfigItemHeaderTitle';

View File

@ -3,4 +3,6 @@ import { getTheme, mockTheme } from './getTheme';
import { selectThemeVariant } from './selectThemeVariant'; import { selectThemeVariant } from './selectThemeVariant';
export { stylesFactory } from './stylesFactory'; export { stylesFactory } from './stylesFactory';
export { ThemeContext, withTheme, mockTheme, getTheme, selectThemeVariant, useTheme, mockThemeContext }; export { ThemeContext, withTheme, mockTheme, getTheme, selectThemeVariant, useTheme, mockThemeContext };
export { styleMixins } from './mixins';
import * as styleMixins from './mixins';
export { styleMixins };

View File

@ -3,11 +3,9 @@ import { selectThemeVariant } from './selectThemeVariant';
import { css } from 'emotion'; import { css } from 'emotion';
import { stylesFactory } from './stylesFactory'; import { stylesFactory } from './stylesFactory';
// eslint-disable-next-line @typescript-eslint/no-namespace export function cardChrome(theme: GrafanaTheme): string {
export namespace styleMixins { if (theme.isDark) {
export function cardChrome(theme: GrafanaTheme): string { return `
if (theme.isDark) {
return `
background: linear-gradient(135deg, ${theme.colors.dark8}, ${theme.colors.dark6}); background: linear-gradient(135deg, ${theme.colors.dark8}, ${theme.colors.dark6});
&:hover { &:hover {
background: linear-gradient(135deg, ${theme.colors.dark9}, ${theme.colors.dark6}); background: linear-gradient(135deg, ${theme.colors.dark9}, ${theme.colors.dark6});
@ -15,9 +13,9 @@ export namespace styleMixins {
box-shadow: -1px -1px 0 0 hsla(0, 0%, 100%, 0.1), 1px 1px 0 0 rgba(0, 0, 0, 0.3); box-shadow: -1px -1px 0 0 hsla(0, 0%, 100%, 0.1), 1px 1px 0 0 rgba(0, 0, 0, 0.3);
border-radius: ${theme.border.radius.md}; border-radius: ${theme.border.radius.md};
`; `;
} }
return ` return `
background: linear-gradient(135deg, ${theme.colors.gray6}, ${theme.colors.gray7}); background: linear-gradient(135deg, ${theme.colors.gray6}, ${theme.colors.gray7});
&:hover { &:hover {
background: linear-gradient(135deg, ${theme.colors.gray7}, ${theme.colors.gray6}); background: linear-gradient(135deg, ${theme.colors.gray7}, ${theme.colors.gray6});
@ -25,11 +23,11 @@ export namespace styleMixins {
box-shadow: -1px -1px 0 0 hsla(0, 0%, 100%, 0.1), 1px 1px 0 0 rgba(0, 0, 0, 0.1); box-shadow: -1px -1px 0 0 hsla(0, 0%, 100%, 0.1), 1px 1px 0 0 rgba(0, 0, 0, 0.1);
border-radius: ${theme.border.radius.md}; border-radius: ${theme.border.radius.md};
`; `;
} }
export function listItem(theme: GrafanaTheme): string { export function listItem(theme: GrafanaTheme): string {
if (theme.isDark) { if (theme.isDark) {
return ` return `
background: ${theme.colors.dark7}; background: ${theme.colors.dark7};
&:hover { &:hover {
background: ${theme.colors.dark9}; background: ${theme.colors.dark9};
@ -37,9 +35,9 @@ export namespace styleMixins {
box-shadow: -1px -1px 0 0 hsla(0, 0%, 100%, 0.1), 1px 1px 0 0 rgba(0, 0, 0, 0.3); box-shadow: -1px -1px 0 0 hsla(0, 0%, 100%, 0.1), 1px 1px 0 0 rgba(0, 0, 0, 0.3);
border-radius: ${theme.border.radius.md}; border-radius: ${theme.border.radius.md};
`; `;
} }
return ` return `
background: ${theme.colors.gray7}; background: ${theme.colors.gray7};
&:hover { &:hover {
background: ${theme.colors.gray6}; background: ${theme.colors.gray6};
@ -47,55 +45,54 @@ export namespace styleMixins {
box-shadow: -1px -1px 0 0 hsla(0, 0%, 100%, 0.1), 1px 1px 0 0 rgba(0, 0, 0, 0.1); box-shadow: -1px -1px 0 0 hsla(0, 0%, 100%, 0.1), 1px 1px 0 0 rgba(0, 0, 0, 0.1);
border-radius: ${theme.border.radius.md}; border-radius: ${theme.border.radius.md};
`; `;
} }
export const panelEditorNestedListStyles = stylesFactory((theme: GrafanaTheme) => { export const panelEditorNestedListStyles = stylesFactory((theme: GrafanaTheme) => {
const borderColor = selectThemeVariant( const borderColor = selectThemeVariant(
{ {
light: theme.colors.gray85, light: theme.colors.gray85,
dark: theme.colors.dark9, dark: theme.colors.dark9,
}, },
theme.type theme.type
); );
const shadow = selectThemeVariant( const shadow = selectThemeVariant(
{ {
light: theme.colors.gray85, light: theme.colors.gray85,
dark: theme.colors.black, dark: theme.colors.black,
}, },
theme.type theme.type
); );
const headerBg = selectThemeVariant( const headerBg = selectThemeVariant(
{ {
light: theme.colors.white, light: theme.colors.white,
dark: theme.colors.dark1, dark: theme.colors.dark1,
}, },
theme.type theme.type
); );
return { return {
wrapper: css` wrapper: css`
border: 1px dashed ${borderColor}; border: 1px dashed ${borderColor};
margin-bottom: ${theme.spacing.md}; margin-bottom: ${theme.spacing.md};
transition: box-shadow 0.5s cubic-bezier(0.19, 1, 0.22, 1); transition: box-shadow 0.5s cubic-bezier(0.19, 1, 0.22, 1);
box-shadow: none; box-shadow: none;
&:hover { &:hover {
box-shadow: 0 0 10px ${shadow}; box-shadow: 0 0 10px ${shadow};
} }
`, `,
headerWrapper: css` headerWrapper: css`
background: ${headerBg}; background: ${headerBg};
padding: ${theme.spacing.xs} 0; padding: ${theme.spacing.xs} 0;
`, `,
content: css` content: css`
padding: ${theme.spacing.xs} ${theme.spacing.sm} ${theme.spacing.sm} ${theme.spacing.sm}; padding: ${theme.spacing.xs} ${theme.spacing.sm} ${theme.spacing.sm} ${theme.spacing.sm};
border-top: 1px dashed ${borderColor}; border-top: 1px dashed ${borderColor};
> *:last-child { > *:last-child {
margin-bottom: 0; margin-bottom: 0;
`, `,
itemContent: css` itemContent: css`
padding: ${theme.spacing.xs} ${theme.spacing.sm} ${theme.spacing.sm} ${theme.spacing.sm}; padding: ${theme.spacing.xs} ${theme.spacing.sm} ${theme.spacing.sm} ${theme.spacing.sm};
`, `,
}; };
}); });
}

View File

@ -1,44 +1,41 @@
// eslint-disable-next-line @typescript-eslint/no-namespace // Node.closest() polyfill
export namespace DOMUtil { if ('Element' in window && !Element.prototype.closest) {
// Node.closest() polyfill Element.prototype.closest = function(this: any, s: string) {
if ('Element' in window && !Element.prototype.closest) { const matches = (this.document || this.ownerDocument).querySelectorAll(s);
Element.prototype.closest = function(this: any, s: string) { let el = this;
const matches = (this.document || this.ownerDocument).querySelectorAll(s); let i;
let el = this; // eslint-disable-next-line
let i; do {
i = matches.length;
// eslint-disable-next-line // eslint-disable-next-line
do { while (--i >= 0 && matches.item(i) !== el) {}
i = matches.length; el = el.parentElement;
// eslint-disable-next-line } while (i < 0 && el);
while (--i >= 0 && matches.item(i) !== el) {} return el;
el = el.parentElement; };
} while (i < 0 && el); }
return el;
}; export function getPreviousCousin(node: any, selector: string) {
} let sibling = node.parentElement.previousSibling;
let el;
export function getPreviousCousin(node: any, selector: string) { while (sibling) {
let sibling = node.parentElement.previousSibling; el = sibling.querySelector(selector);
let el; if (el) {
while (sibling) { return el;
el = sibling.querySelector(selector); }
if (el) { sibling = sibling.previousSibling;
return el; }
} return undefined;
sibling = sibling.previousSibling; }
}
return undefined; export function getNextCharacter(global?: any) {
} const selection = (global || window).getSelection();
if (!selection || !selection.anchorNode) {
export function getNextCharacter(global?: any) { return null;
const selection = (global || window).getSelection(); }
if (!selection || !selection.anchorNode) {
return null; const range = selection.getRangeAt(0);
} const text = selection.anchorNode.textContent;
const offset = range.startOffset;
const range = selection.getRangeAt(0); return text!.substr(offset, 1);
const text = selection.anchorNode.textContent;
const offset = range.startOffset;
return text!.substr(offset, 1);
}
} }

View File

@ -6,5 +6,5 @@ export * from './tags';
export * from './measureText'; export * from './measureText';
export { default as ansicolor } from './ansicolor'; export { default as ansicolor } from './ansicolor';
// Export with a namespace import * as DOMUtil from './dom'; // includes Element.closest polyfil
export { DOMUtil } from './dom'; // includes Element.closest polyfil export { DOMUtil };