diff --git a/ui/src/dashboards/actions/cellEditorOverlay.ts b/ui/src/dashboards/actions/cellEditorOverlay.ts index 701bf8f6a8..4c571c7e73 100644 --- a/ui/src/dashboards/actions/cellEditorOverlay.ts +++ b/ui/src/dashboards/actions/cellEditorOverlay.ts @@ -1,205 +1,113 @@ -import {Cell} from 'src/types' -import {CellType, ThresholdType} from 'src/types/dashboard' -import {ColorNumber, ColorString} from 'src/types/colors' -import { - Axes, - DecimalPlaces, - FieldOption, - TableOptions, -} from 'src/types/dashboard' +import * as CellEditorOverlayActions from 'src/types/actions/cellEditorOverlay' +import * as ColorsModels from 'src/types/colors' +import * as DashboardsModels from 'src/types/dashboards' -export type Action = - | ShowCellEditorOverlayAction - | HideCellEditorOverlayAction - | ChangeCellTypeAction - | RenameCellAction - | UpdateThresholdsListColorsAction - | UpdateThresholdsListTypeAction - | UpdateGaugeColorsAction - | UpdateAxesAction - | UpdateTableOptionsAction - | UpdateLineColorsAction - | ChangeTimeFormatAction - | ChangeDecimalPlacesAction - | UpdateFieldOptionsAction - -interface ShowCellEditorOverlayAction { - type: 'SHOW_CELL_EDITOR_OVERLAY' - payload: { - cell: Cell - } -} -export const showCellEditorOverlay = ( - cell: Cell -): ShowCellEditorOverlayAction => ({ +export const showCellEditorOverlay: CellEditorOverlayActions.ShowCellEditorOverlayActionCreator = ( + cell: DashboardsModels.Cell +): CellEditorOverlayActions.ShowCellEditorOverlayAction => ({ type: 'SHOW_CELL_EDITOR_OVERLAY', payload: { cell, }, }) -interface HideCellEditorOverlayAction { - type: 'HIDE_CELL_EDITOR_OVERLAY' -} -export const hideCellEditorOverlay = (): HideCellEditorOverlayAction => ({ +export const hideCellEditorOverlay = (): CellEditorOverlayActions.HideCellEditorOverlayAction => ({ type: 'HIDE_CELL_EDITOR_OVERLAY', }) -interface ChangeCellTypeAction { - type: 'CHANGE_CELL_TYPE' - payload: { - cellType: CellType - } -} - -export const changeCellType = (cellType: CellType): ChangeCellTypeAction => ({ +export const changeCellType = ( + cellType: DashboardsModels.CellType +): CellEditorOverlayActions.ChangeCellTypeAction => ({ type: 'CHANGE_CELL_TYPE', payload: { cellType, }, }) -interface RenameCellAction { - type: 'RENAME_CELL' - payload: { - cellName: string - } -} -export const renameCell = (cellName: string): RenameCellAction => ({ +export const renameCell = ( + cellName: string +): CellEditorOverlayActions.RenameCellAction => ({ type: 'RENAME_CELL', payload: { cellName, }, }) -interface UpdateThresholdsListColorsAction { - type: 'UPDATE_THRESHOLDS_LIST_COLORS' - payload: { - thresholdsListColors: ColorNumber[] - } -} export const updateThresholdsListColors = ( - thresholdsListColors: ColorNumber[] -): UpdateThresholdsListColorsAction => ({ + thresholdsListColors: ColorsModels.ColorNumber[] +): CellEditorOverlayActions.UpdateThresholdsListColorsAction => ({ type: 'UPDATE_THRESHOLDS_LIST_COLORS', payload: { thresholdsListColors, }, }) -interface UpdateThresholdsListTypeAction { - type: 'UPDATE_THRESHOLDS_LIST_TYPE' - payload: { - thresholdsListType: ThresholdType - } -} - export const updateThresholdsListType = ( - thresholdsListType: ThresholdType -): UpdateThresholdsListTypeAction => ({ + thresholdsListType: DashboardsModels.ThresholdType +): CellEditorOverlayActions.UpdateThresholdsListTypeAction => ({ type: 'UPDATE_THRESHOLDS_LIST_TYPE', payload: { thresholdsListType, }, }) -interface UpdateGaugeColorsAction { - type: 'UPDATE_GAUGE_COLORS' - payload: { - gaugeColors: ColorNumber[] - } -} export const updateGaugeColors = ( - gaugeColors: ColorNumber[] -): UpdateGaugeColorsAction => ({ + gaugeColors: ColorsModels.ColorNumber[] +): CellEditorOverlayActions.UpdateGaugeColorsAction => ({ type: 'UPDATE_GAUGE_COLORS', payload: { gaugeColors, }, }) -interface UpdateAxesAction { - type: 'UPDATE_AXES' - payload: { - axes: Axes - } -} -export const updateAxes = (axes: Axes): UpdateAxesAction => ({ +export const updateAxes = ( + axes: DashboardsModels.Axes +): CellEditorOverlayActions.UpdateAxesAction => ({ type: 'UPDATE_AXES', payload: { axes, }, }) -interface UpdateTableOptionsAction { - type: 'UPDATE_TABLE_OPTIONS' - payload: { - tableOptions: TableOptions - } -} export const updateTableOptions = ( - tableOptions: TableOptions -): UpdateTableOptionsAction => ({ + tableOptions: DashboardsModels.TableOptions +): CellEditorOverlayActions.UpdateTableOptionsAction => ({ type: 'UPDATE_TABLE_OPTIONS', payload: { tableOptions, }, }) -interface UpdateLineColorsAction { - type: 'UPDATE_LINE_COLORS' - payload: { - lineColors: ColorString[] - } -} export const updateLineColors = ( - lineColors: ColorString[] -): UpdateLineColorsAction => ({ + lineColors: ColorsModels.ColorString[] +): CellEditorOverlayActions.UpdateLineColorsAction => ({ type: 'UPDATE_LINE_COLORS', payload: { lineColors, }, }) -interface ChangeTimeFormatAction { - type: 'CHANGE_TIME_FORMAT' - payload: { - timeFormat: string - } -} export const changeTimeFormat = ( timeFormat: string -): ChangeTimeFormatAction => ({ +): CellEditorOverlayActions.ChangeTimeFormatAction => ({ type: 'CHANGE_TIME_FORMAT', payload: { timeFormat, }, }) -interface ChangeDecimalPlacesAction { - type: 'CHANGE_DECIMAL_PLACES' - payload: { - decimalPlaces: DecimalPlaces - } -} export const changeDecimalPlaces = ( - decimalPlaces: DecimalPlaces -): ChangeDecimalPlacesAction => ({ + decimalPlaces: DashboardsModels.DecimalPlaces +): CellEditorOverlayActions.ChangeDecimalPlacesAction => ({ type: 'CHANGE_DECIMAL_PLACES', payload: { decimalPlaces, }, }) -interface UpdateFieldOptionsAction { - type: 'UPDATE_FIELD_OPTIONS' - payload: { - fieldOptions: FieldOption[] - } -} export const updateFieldOptions = ( - fieldOptions: FieldOption[] -): UpdateFieldOptionsAction => ({ + fieldOptions: DashboardsModels.FieldOption[] +): CellEditorOverlayActions.UpdateFieldOptionsAction => ({ type: 'UPDATE_FIELD_OPTIONS', payload: { fieldOptions, diff --git a/ui/src/dashboards/actions/index.ts b/ui/src/dashboards/actions/index.ts index 62419f4ebb..1c0bd0cc91 100644 --- a/ui/src/dashboards/actions/index.ts +++ b/ui/src/dashboards/actions/index.ts @@ -1,6 +1,4 @@ import {bindActionCreators} from 'redux' -import {InjectedRouter} from 'react-router' -import {Location} from 'history' import {replace} from 'react-router-redux' import _ from 'lodash' import queryString from 'query-string' @@ -55,28 +53,27 @@ import idNormalizer, {TYPE_ID} from 'src/normalizers/id' import {defaultTimeRange} from 'src/shared/data/timeRanges' -import { - Dashboard, - TimeRange, - Cell, - Source, - Template, - TemplateType, - URLQueryParams, -} from 'src/types' -import {CellType, DashboardName} from 'src/types/dashboard' +// Types +import {Dispatch} from 'redux' +import {InjectedRouter} from 'react-router' +import {Location} from 'history' +import {AxiosResponse} from 'axios' +import {LocationAction} from 'react-router-redux' +import * as AuthReducers from 'src/types/reducers/auth' +import * as DashboardsActions from 'src/types/actions/dashboards' +import * as DashboardsApis from 'src/types/apis/dashboards' +import * as DashboardsModels from 'src/types/dashboards' +import * as DashboardsReducers from 'src/types/reducers/dashboards' +import * as ErrorsActions from 'src/types/actions/errors' +import * as QueriesModels from 'src/types/queries' +import * as SourcesModels from 'src/types/sources' +import * as TempVarsModels from 'src/types/tempVars' +import * as NotificationsActions from 'src/types/actions/notifications' -interface LoadDashboardsAction { - type: 'LOAD_DASHBOARDS' - payload: { - dashboards: Dashboard[] - dashboardID: number - } -} -export const loadDashboards = ( - dashboards: Dashboard[], +export const loadDashboards: DashboardsActions.LoadDashboardsActionCreator = ( + dashboards: DashboardsModels.Dashboard[], dashboardID?: number -): LoadDashboardsAction => ({ +): DashboardsActions.LoadDashboardsAction => ({ type: 'LOAD_DASHBOARDS', payload: { dashboards, @@ -84,30 +81,19 @@ export const loadDashboards = ( }, }) -interface LoadDashboardAction { - type: 'LOAD_DASHBOARD' - payload: { - dashboard: Dashboard - } -} -export const loadDashboard = (dashboard: Dashboard): LoadDashboardAction => ({ +export const loadDashboard: DashboardsActions.LoadDashboardActionCreator = ( + dashboard: DashboardsModels.Dashboard +): DashboardsActions.LoadDashboardAction => ({ type: 'LOAD_DASHBOARD', payload: { dashboard, }, }) -interface SetDashTimeV1Action { - type: 'SET_DASHBOARD_TIME_V1' - payload: { - dashboardID: number - timeRange: TimeRange - } -} -export const setDashTimeV1 = ( +export const setDashTimeV1: DashboardsActions.SetDashTimeV1ActionCreator = ( dashboardID: number, - timeRange: TimeRange -): SetDashTimeV1Action => ({ + timeRange: QueriesModels.TimeRange +): DashboardsActions.SetDashTimeV1Action => ({ type: 'SET_DASHBOARD_TIME_V1', payload: { dashboardID, @@ -115,120 +101,71 @@ export const setDashTimeV1 = ( }, }) -interface RetainRangesDashTimeV1Action { - type: 'RETAIN_RANGES_DASHBOARD_TIME_V1' - payload: { - dashboardIDs: string[] - } -} -export const retainRangesDashTimeV1 = ( +export const retainRangesDashTimeV1: DashboardsActions.RetainRangesDashTimeV1ActionCreator = ( dashboardIDs: string[] -): RetainRangesDashTimeV1Action => ({ +): DashboardsActions.RetainRangesDashTimeV1Action => ({ type: 'RETAIN_RANGES_DASHBOARD_TIME_V1', payload: {dashboardIDs}, }) -interface SetTimeRangeAction { - type: 'SET_DASHBOARD_TIME_RANGE' - payload: { - timeRange: TimeRange - } -} -export const setTimeRange = (timeRange: TimeRange): SetTimeRangeAction => ({ +export const setTimeRange: DashboardsActions.SetTimeRangeActionCreator = ( + timeRange: QueriesModels.TimeRange +): DashboardsActions.SetTimeRangeAction => ({ type: 'SET_DASHBOARD_TIME_RANGE', payload: { timeRange, }, }) -interface SetZoomedTimeRangeAction { - type: 'SET_DASHBOARD_ZOOMED_TIME_RANGE' - payload: { - zoomedTimeRange: TimeRange - } -} -export const setZoomedTimeRange = ( - zoomedTimeRange: TimeRange -): SetZoomedTimeRangeAction => ({ +export const setZoomedTimeRange: DashboardsActions.SetZoomedTimeRangeActionCreator = ( + zoomedTimeRange: QueriesModels.TimeRange +): DashboardsActions.SetZoomedTimeRangeAction => ({ type: 'SET_DASHBOARD_ZOOMED_TIME_RANGE', payload: { zoomedTimeRange, }, }) -interface UpdateDashboardAction { - type: 'UPDATE_DASHBOARD' - payload: { - dashboard: Dashboard - } -} -export const updateDashboard = ( - dashboard: Dashboard -): UpdateDashboardAction => ({ +export const updateDashboard: DashboardsActions.UpdateDashboardActionCreator = ( + dashboard: DashboardsModels.Dashboard +): DashboardsActions.UpdateDashboardAction => ({ type: 'UPDATE_DASHBOARD', payload: { dashboard, }, }) -interface CreateDashboardAction { - type: 'CREATE_DASHBOARD' - payload: { - dashboard: Dashboard - } -} -export const createDashboard = ( - dashboard: Dashboard -): CreateDashboardAction => ({ +export const createDashboard: DashboardsActions.CreateDashboardActionCreator = ( + dashboard: DashboardsModels.Dashboard +): DashboardsActions.CreateDashboardAction => ({ type: 'CREATE_DASHBOARD', payload: { dashboard, }, }) -interface DeleteDashboardAction { - type: 'DELETE_DASHBOARD' - payload: { - dashboard: Dashboard - dashboardID: number - } -} -export const deleteDashboard = ( - dashboard: Dashboard -): DeleteDashboardAction => ({ +export const deleteDashboard: DashboardsActions.DeleteDashboardActionCreator = ( + dashboard: DashboardsModels.Dashboard +): DashboardsActions.DeleteDashboardAction => ({ type: 'DELETE_DASHBOARD', payload: { dashboard, - dashboardID: dashboard.id, }, }) -interface DeleteDashboardFailedAction { - type: 'DELETE_DASHBOARD_FAILED' - payload: { - dashboard: Dashboard - } -} -export const deleteDashboardFailed = ( - dashboard: Dashboard -): DeleteDashboardFailedAction => ({ +export const deleteDashboardFailed: DashboardsActions.DeleteDashboardFailedActionCreator = ( + dashboard: DashboardsModels.Dashboard +): DashboardsActions.DeleteDashboardFailedAction => ({ type: 'DELETE_DASHBOARD_FAILED', payload: { dashboard, }, }) -interface SyncDashboardCellAction { - type: 'SYNC_DASHBOARD_CELL' - payload: { - dashboard: Dashboard - cell: Cell - } -} -export const syncDashboardCell = ( - dashboard: Dashboard, - cell: Cell -): SyncDashboardCellAction => ({ +export const syncDashboardCell: DashboardsActions.SyncDashboardCellActionCreator = ( + dashboard: DashboardsModels.Dashboard, + cell: DashboardsModels.Cell +): DashboardsActions.SyncDashboardCellAction => ({ type: 'SYNC_DASHBOARD_CELL', payload: { dashboard, @@ -236,17 +173,10 @@ export const syncDashboardCell = ( }, }) -interface AddDashboardCellAction { - type: 'ADD_DASHBOARD_CELL' - payload: { - dashboard: Dashboard - cell: Cell - } -} -export const addDashboardCell = ( - dashboard: Dashboard, - cell: Cell -): AddDashboardCellAction => ({ +export const addDashboardCell: DashboardsActions.AddDashboardCellActionCreator = ( + dashboard: DashboardsModels.Dashboard, + cell: DashboardsModels.Cell +): DashboardsActions.AddDashboardCellAction => ({ type: 'ADD_DASHBOARD_CELL', payload: { dashboard, @@ -254,17 +184,10 @@ export const addDashboardCell = ( }, }) -interface DeleteDashboardCellAction { - type: 'DELETE_DASHBOARD_CELL' - payload: { - dashboard: Dashboard - cell: Cell - } -} -export const deleteDashboardCell = ( - dashboard: Dashboard, - cell: Cell -): DeleteDashboardCellAction => ({ +export const deleteDashboardCell: DashboardsActions.DeleteDashboardCellActionCreator = ( + dashboard: DashboardsModels.Dashboard, + cell: DashboardsModels.Cell +): DashboardsActions.DeleteDashboardCellAction => ({ type: 'DELETE_DASHBOARD_CELL', payload: { dashboard, @@ -272,17 +195,10 @@ export const deleteDashboardCell = ( }, }) -interface EditCellQueryStatusAction { - type: 'EDIT_CELL_QUERY_STATUS' - payload: { - queryID: string - status: string - } -} -export const editCellQueryStatus = ( +export const editCellQueryStatus: DashboardsActions.EditCellQueryStatusActionCreator = ( queryID: string, status: string -): EditCellQueryStatusAction => ({ +): DashboardsActions.EditCellQueryStatusAction => ({ type: 'EDIT_CELL_QUERY_STATUS', payload: { queryID, @@ -290,19 +206,11 @@ export const editCellQueryStatus = ( }, }) -interface TemplateVariableSelectedAction { - type: 'TEMPLATE_VARIABLE_SELECTED' - payload: { - dashboardID: number - templateID: string - values: any[] - } -} -export const templateVariableSelected = ( +export const templateVariableSelected: DashboardsActions.TemplateVariableSelectedActionCreator = ( dashboardID: number, templateID: string, values -): TemplateVariableSelectedAction => ({ +): DashboardsActions.TemplateVariableSelectedAction => ({ type: 'TEMPLATE_VARIABLE_SELECTED', payload: { dashboardID, @@ -311,17 +219,10 @@ export const templateVariableSelected = ( }, }) -interface TemplateVariablesSelectedByNameAction { - type: 'TEMPLATE_VARIABLES_SELECTED_BY_NAME' - payload: { - dashboardID: number - queryParams: URLQueryParams - } -} -export const templateVariablesSelectedByName = ( +export const templateVariablesSelectedByName: DashboardsActions.TemplateVariablesSelectedByNameActionCreator = ( dashboardID: number, - queryParams: URLQueryParams -): TemplateVariablesSelectedByNameAction => ({ + queryParams: TempVarsModels.URLQueryParams +): DashboardsActions.TemplateVariablesSelectedByNameAction => ({ type: 'TEMPLATE_VARIABLES_SELECTED_BY_NAME', payload: { dashboardID, @@ -329,19 +230,11 @@ export const templateVariablesSelectedByName = ( }, }) -interface EditTemplateVariableValuesAction { - type: 'EDIT_TEMPLATE_VARIABLE_VALUES' - payload: { - dashboardID: number - templateID: string - values: any[] - } -} -export const editTemplateVariableValues = ( +export const editTemplateVariableValues: DashboardsActions.EditTemplateVariableValuesActionCreator = ( dashboardID: number, templateID: string, values -): EditTemplateVariableValuesAction => ({ +): DashboardsActions.EditTemplateVariableValuesAction => ({ type: 'EDIT_TEMPLATE_VARIABLE_VALUES', payload: { dashboardID, @@ -350,26 +243,18 @@ export const editTemplateVariableValues = ( }, }) -interface SetHoverTimeAction { - type: 'SET_HOVER_TIME' - payload: { - hoverTime: string - } -} -export const setHoverTime = (hoverTime: string): SetHoverTimeAction => ({ +export const setHoverTime: DashboardsActions.SetHoverTimeActionCreator = ( + hoverTime: string +): DashboardsActions.SetHoverTimeAction => ({ type: 'SET_HOVER_TIME', payload: { hoverTime, }, }) -interface SetActiveCellAction { - type: 'SET_ACTIVE_CELL' - payload: { - activeCellID: string - } -} -export const setActiveCell = (activeCellID: string): SetActiveCellAction => ({ +export const setActiveCell: DashboardsActions.SetActiveCellActionCreator = ( + activeCellID: string +): DashboardsActions.SetActiveCellAction => ({ type: 'SET_ACTIVE_CELL', payload: { activeCellID, @@ -378,13 +263,18 @@ export const setActiveCell = (activeCellID: string): SetActiveCellAction => ({ // Async Action Creators -export const getDashboardsAsync = () => async ( - dispatch -): Promise => { +export const getDashboardsAsync: DashboardsActions.GetDashboardsDispatcher = (): DashboardsActions.GetDashboardsThunk => async ( + dispatch: Dispatch< + | DashboardsActions.LoadDashboardsActionCreator + | ErrorsActions.ErrorThrownActionCreator + > +): Promise => { try { const { data: {dashboards}, - } = await getDashboardsAJAX() + } = (await getDashboardsAJAX()) as AxiosResponse< + DashboardsApis.DashboardsResponse + > dispatch(loadDashboards(dashboards)) return dashboards } catch (error) { @@ -395,9 +285,11 @@ export const getDashboardsAsync = () => async ( // gets update-to-date names of dashboards, but does not dispatch action // in order to avoid duplicate and out-of-sync state problems in redux -export const getDashboardsNamesAsync = (sourceID: string) => async ( - dispatch -): Promise => { +export const getDashboardsNamesAsync: DashboardsActions.GetDashboardsNamesDispatcher = ( + sourceID: string +): DashboardsActions.GetDashboardsNamesThunk => async ( + dispatch: Dispatch +): Promise => { try { // TODO: change this from getDashboardsAJAX to getDashboardsNamesAJAX // to just get dashboard names (and links) as api view call when that @@ -405,7 +297,9 @@ export const getDashboardsNamesAsync = (sourceID: string) => async ( // dashboard for each const { data: {dashboards}, - } = await getDashboardsAJAX() + } = (await getDashboardsAJAX()) as AxiosResponse< + DashboardsApis.DashboardsResponse + > const dashboardsNames = dashboards.map(({id, name}) => ({ id, name, @@ -420,7 +314,7 @@ export const getDashboardsNamesAsync = (sourceID: string) => async ( export const getDashboardAsync = (dashboardID: number) => async ( dispatch -): Promise => { +): Promise => { try { const {data: dashboard} = await getDashboardAJAX(dashboardID) dispatch(loadDashboard(dashboard)) @@ -442,24 +336,33 @@ export const getChronografVersion = () => async (): Promise => { } } -const removeUnselectedTemplateValues = (dashboard: Dashboard): Template[] => { - const templates = getDeep(dashboard, 'templates', []).map( - template => { - if (template.type === TemplateType.CSV) { - return template - } - - const value = template.values.find(val => val.selected) - const values = value ? [value] : [] - - return {...template, values} +const removeUnselectedTemplateValues = ( + dashboard: DashboardsModels.Dashboard +): TempVarsModels.Template[] => { + const templates = getDeep( + dashboard, + 'templates', + [] + ).map(template => { + if (template.type === TempVarsModels.TemplateType.CSV) { + return template } - ) + + const value = template.values.find(val => val.selected) + const values = value ? [value] : [] + + return {...template, values} + }) return templates } -export const putDashboard = (dashboard: Dashboard) => async ( - dispatch +export const putDashboard = ( + dashboard: DashboardsModels.Dashboard +): DashboardsActions.PutDashboardThunk => async ( + dispatch: Dispatch< + | DashboardsActions.UpdateDashboardAction + | ErrorsActions.ErrorThrownActionCreator + > ): Promise => { try { // save only selected template values to server @@ -485,15 +388,19 @@ export const putDashboard = (dashboard: Dashboard) => async ( } } -export const putDashboardByID = (dashboardID: number) => async ( - dispatch, - getState +export const putDashboardByID: DashboardsActions.PutDashboardByIDDispatcher = ( + dashboardID: number +): DashboardsActions.PutDashboardByIDThunk => async ( + dispatch: Dispatch, + getState: () => DashboardsReducers.Dashboards ): Promise => { try { const { dashboardUI: {dashboards}, } = getState() - const dashboard: Dashboard = dashboards.find(d => d.id === +dashboardID) + const dashboard: DashboardsModels.Dashboard = dashboards.find( + d => d.id === +dashboardID + ) const templates = removeUnselectedTemplateValues(dashboard) await updateDashboardAJAX({...dashboard, templates}) } catch (error) { @@ -502,8 +409,14 @@ export const putDashboardByID = (dashboardID: number) => async ( } } -export const updateDashboardCell = (dashboard: Dashboard, cell: Cell) => async ( - dispatch +export const updateDashboardCell: DashboardsActions.UpdateDashboardCellDispatcher = ( + dashboard: DashboardsModels.Dashboard, + cell: DashboardsModels.Cell +): DashboardsActions.UpdateDashboardCellThunk => async ( + dispatch: Dispatch< + | DashboardsActions.SyncDashboardCellActionCreator + | ErrorsActions.ErrorThrownActionCreator + > ): Promise => { try { const {data} = await updateDashboardCellAJAX(cell) @@ -514,8 +427,15 @@ export const updateDashboardCell = (dashboard: Dashboard, cell: Cell) => async ( } } -export const deleteDashboardAsync = (dashboard: Dashboard) => async ( - dispatch +export const deleteDashboardAsync: DashboardsActions.DeleteDashboardDispatcher = ( + dashboard: DashboardsModels.Dashboard +): DashboardsActions.DeleteDashboardThunk => async ( + dispatch: Dispatch< + | DashboardsActions.DeleteDashboardActionCreator + | NotificationsActions.PublishNotificationActionCreator + | ErrorsActions.ErrorThrownActionCreator + | DashboardsActions.DeleteDashboardFailedActionCreator + > ): Promise => { dispatch(deleteDashboard(dashboard)) try { @@ -532,10 +452,16 @@ export const deleteDashboardAsync = (dashboard: Dashboard) => async ( } } -export const addDashboardCellAsync = ( - dashboard: Dashboard, - cellType: CellType -) => async (dispatch): Promise => { +export const addDashboardCellAsync: DashboardsActions.AddDashboardCellDispatcher = ( + dashboard: DashboardsModels.Dashboard, + cellType?: DashboardsModels.CellType +): DashboardsActions.AddDashboardCellThunk => async ( + dispatch: Dispatch< + | DashboardsActions.AddDashboardCellAction + | NotificationsActions.PublishNotificationActionCreator + | ErrorsActions.ErrorThrownActionCreator + > +): Promise => { try { const {data} = await addDashboardCellAJAX( dashboard, @@ -549,10 +475,16 @@ export const addDashboardCellAsync = ( } } -export const cloneDashboardCellAsync = ( - dashboard: Dashboard, - cell: Cell -) => async (dispatch): Promise => { +export const cloneDashboardCellAsync: DashboardsActions.CloneDashboardCellDispatcher = ( + dashboard: DashboardsModels.Dashboard, + cell: DashboardsModels.Cell +): DashboardsActions.CloneDashboardCellThunk => async ( + dispatch: Dispatch< + | DashboardsActions.AddDashboardCellActionCreator + | NotificationsActions.PublishNotificationActionCreator + | ErrorsActions.ErrorThrownActionCreator + > +): Promise => { try { const clonedCell = getClonedDashboardCell(dashboard, cell) const {data} = await addDashboardCellAJAX(dashboard, clonedCell) @@ -564,10 +496,16 @@ export const cloneDashboardCellAsync = ( } } -export const deleteDashboardCellAsync = ( - dashboard: Dashboard, - cell: Cell -) => async (dispatch): Promise => { +export const deleteDashboardCellAsync: DashboardsActions.DeleteDashboardCellDispatcher = ( + dashboard: DashboardsModels.Dashboard, + cell: DashboardsModels.Cell +): DashboardsActions.DeleteDashboardCellThunk => async ( + dispatch: Dispatch< + | DashboardsActions.DeleteDashboardCellActionCreator + | NotificationsActions.PublishNotificationActionCreator + | ErrorsActions.ErrorThrownActionCreator + > +): Promise => { try { await deleteDashboardCellAJAX(cell) dispatch(deleteDashboardCell(dashboard, cell)) @@ -578,9 +516,9 @@ export const deleteDashboardCellAsync = ( } } -export const importDashboardAsync = (dashboard: Dashboard) => async ( - dispatch -): Promise => { +export const importDashboardAsync = ( + dashboard: DashboardsModels.Dashboard +) => async (dispatch): Promise => { try { // save only selected template values to server const templatesWithOnlySelectedValues = removeUnselectedTemplateValues( @@ -604,7 +542,9 @@ export const importDashboardAsync = (dashboard: Dashboard) => async ( const { data: {dashboards}, - } = await getDashboardsAJAX() + } = (await getDashboardsAJAX()) as AxiosResponse< + DashboardsApis.DashboardsResponse + > dispatch(loadDashboards(dashboards)) dispatch(notify(notifyDashboardImported(name))) @@ -622,13 +562,13 @@ export const importDashboardAsync = (dashboard: Dashboard) => async ( export const hydrateTempVarValuesAsync = ( dashboardID: number, - source: Source + source: SourcesModels.Source ) => async (dispatch, getState): Promise => { try { const dashboard = getState().dashboardUI.dashboards.find( d => d.id === dashboardID ) - const templates: Template[] = dashboard.templates + const templates: TempVarsModels.Template[] = dashboard.templates const queries = templates .filter( template => getDeep(template, 'query.influxql', '') !== '' @@ -655,9 +595,11 @@ const removeNullValues = obj => _.pickBy(obj, o => o) export const syncURLQueryParamsFromQueryParamsObject = ( location: Location, - updatedURLQueryParams: URLQueryParams, - deletedURLQueryParams: URLQueryParams = {} -) => (dispatch): void => { + updatedURLQueryParams: TempVarsModels.URLQueryParams, + deletedURLQueryParams: TempVarsModels.URLQueryParams = {} +): DashboardsActions.SyncURLQueryFromQueryParamsObjectActionCreator => ( + dispatch: Dispatch +): void => { const updatedLocationQuery = removeNullValues({ ...location.query, ...updatedURLQueryParams, @@ -678,35 +620,49 @@ export const syncURLQueryParamsFromQueryParamsObject = ( dispatch(replace(updatedLocation)) } -export const syncURLQueryFromTempVars = ( +export const syncURLQueryFromTempVars: DashboardsActions.SyncURLQueryFromTempVarsDispatcher = ( location: Location, - tempVars: Template[], - deletedTempVars: Template[] = [], - urlQueryParamsTimeRanges: URLQueryParams = {} -) => (dispatch): void => { + tempVars: TempVarsModels.Template[], + deletedTempVars: TempVarsModels.Template[] = [], + urlQueryParamsTimeRanges?: TempVarsModels.URLQueryParams +): DashboardsActions.SyncURLQueryFromQueryParamsObjectActionCreator => ( + dispatch: Dispatch< + DashboardsActions.SyncURLQueryFromQueryParamsObjectDispatcher + > +): void => { const updatedURLQueryParams = generateURLQueryParamsFromTempVars(tempVars) const deletedURLQueryParams = generateURLQueryParamsFromTempVars( deletedTempVars ) - const updatedURLQueryParamsWithTimeRange = { + let updatedURLQueryParamsWithTimeRange = { ...updatedURLQueryParams, - ...urlQueryParamsTimeRanges, } - dispatch( - syncURLQueryParamsFromQueryParamsObject( - location, - updatedURLQueryParamsWithTimeRange, - deletedURLQueryParams - ) - ) + if (urlQueryParamsTimeRanges) { + updatedURLQueryParamsWithTimeRange = { + ...updatedURLQueryParamsWithTimeRange, + ...urlQueryParamsTimeRanges, + } + } + + syncURLQueryParamsFromQueryParamsObject( + location, + updatedURLQueryParamsWithTimeRange, + deletedURLQueryParams + )(dispatch) } const syncDashboardTempVarsFromURLQueryParams = ( dashboardID: number, - urlQueryParams: URLQueryParams -) => (dispatch, getState): void => { + urlQueryParams: TempVarsModels.URLQueryParams +): DashboardsActions.SyncDashboardTempVarsFromURLQueryParamsDispatcher => ( + dispatch: Dispatch< + | NotificationsActions.PublishNotificationActionCreator + | DashboardsActions.TemplateVariableSelectedAction + >, + getState: () => DashboardsReducers.Dashboards & AuthReducers.Auth +): void => { const { dashboardUI, auth: {isUsingAuth, me}, @@ -738,9 +694,12 @@ const syncDashboardTempVarsFromURLQueryParams = ( const syncDashboardTimeRangeFromURLQueryParams = ( dashboardID: number, - urlQueryParams: URLQueryParams, + urlQueryParams: TempVarsModels.URLQueryParams, location: Location -) => (dispatch, getState): void => { +): DashboardsActions.SyncDashboardTimeRangeFromURLQueryParamsDispatcher => ( + dispatch: Dispatch, + getState: () => DashboardsReducers.Dashboards & DashboardsReducers.DashTimeV1 +): void => { const { dashboardUI: {dashboards}, dashTimeV1, @@ -786,37 +745,45 @@ const syncDashboardTimeRangeFromURLQueryParams = ( zoomedLower: validatedZoomedTimeRange.lower, zoomedUpper: validatedZoomedTimeRange.upper, } - dispatch( - syncURLQueryFromTempVars( - location, - dashboard.templates, - [], - urlQueryParamsTimeRanges - ) - ) + + syncURLQueryFromTempVars( + location, + dashboard.templates, + [], + urlQueryParamsTimeRanges + )(dispatch) } const syncDashboardFromURLQueryParams = ( dashboardID: number, location: Location -) => (dispatch): void => { +): DashboardsActions.SyncDashboardFromURLQueryParamsDispatcher => ( + dispatch: Dispatch< + | DashboardsActions.SyncDashboardTempVarsFromURLQueryParamsDispatcher + | DashboardsActions.SyncDashboardTimeRangeFromURLQueryParamsDispatcher + > +): void => { const urlQueryParams = queryString.parse(window.location.search) - dispatch(syncDashboardTempVarsFromURLQueryParams(dashboardID, urlQueryParams)) - dispatch( - syncDashboardTimeRangeFromURLQueryParams( - dashboardID, - urlQueryParams, - location - ) + bindActionCreators(syncDashboardTempVarsFromURLQueryParams, dispatch)( + dashboardID, + urlQueryParams + ) + + bindActionCreators(syncDashboardTimeRangeFromURLQueryParams, dispatch)( + dashboardID, + urlQueryParams, + location ) } -export const getDashboardWithHydratedAndSyncedTempVarsAsync = ( +export const getDashboardWithHydratedAndSyncedTempVarsAsync: DashboardsActions.GetDashboardWithHydratedAndSyncedTempVarsAsyncDispatcher = ( dashboardID: number, - source: Source, + source: SourcesModels.Source, router: InjectedRouter, location: Location -) => async (dispatch): Promise => { +): DashboardsActions.GetDashboardWithHydratedAndSyncedTempVarsAsyncThunk => async ( + dispatch: Dispatch +): Promise => { const dashboard = await bindActionCreators(getDashboardAsync, dispatch)( dashboardID ) @@ -831,22 +798,29 @@ export const getDashboardWithHydratedAndSyncedTempVarsAsync = ( source ) - dispatch(syncDashboardFromURLQueryParams(+dashboardID, location)) + bindActionCreators(syncDashboardFromURLQueryParams, dispatch)( + +dashboardID, + location + ) } -export const setZoomedTimeRangeAsync = ( - zoomedTimeRange: TimeRange, +export const setZoomedTimeRangeAsync: DashboardsActions.SetZoomedTimeRangeDispatcher = ( + zoomedTimeRange: QueriesModels.TimeRange, location: Location -) => async (dispatch): Promise => { +): DashboardsActions.SetZoomedTimeRangeThunk => async ( + dispatch: Dispatch< + | DashboardsActions.SetZoomedTimeRangeActionCreator + | DashboardsActions.SyncURLQueryFromQueryParamsObjectDispatcher + > +): Promise => { dispatch(setZoomedTimeRange(zoomedTimeRange)) const urlQueryParamsZoomedTimeRange = { zoomedLower: zoomedTimeRange.lower, zoomedUpper: zoomedTimeRange.upper, } - dispatch( - syncURLQueryParamsFromQueryParamsObject( - location, - urlQueryParamsZoomedTimeRange - ) - ) + + syncURLQueryParamsFromQueryParamsObject( + location, + urlQueryParamsZoomedTimeRange + )(dispatch) } diff --git a/ui/src/dashboards/apis/index.js b/ui/src/dashboards/apis/index.ts similarity index 83% rename from ui/src/dashboards/apis/index.js rename to ui/src/dashboards/apis/index.ts index ff04e841a1..545c051ea6 100644 --- a/ui/src/dashboards/apis/index.js +++ b/ui/src/dashboards/apis/index.ts @@ -1,6 +1,11 @@ -import AJAX from 'utils/ajax' +import AJAX from 'src/utils/ajax' -export function getDashboards() { +import {AxiosResponse} from 'axios' +import {DashboardsResponse} from 'src/types/apis/dashboards' + +export const getDashboards = (): Promise< + AxiosResponse | DashboardsResponse +> => { return AJAX({ method: 'GET', resource: 'dashboards', @@ -19,7 +24,7 @@ export const getDashboard = async dashboardID => { } } -export function updateDashboard(dashboard) { +export const updateDashboard = dashboard => { return AJAX({ method: 'PUT', url: dashboard.links.self, @@ -27,7 +32,7 @@ export function updateDashboard(dashboard) { }) } -export function updateDashboardCell(cell) { +export const updateDashboardCell = cell => { return AJAX({ method: 'PUT', url: cell.links.self, diff --git a/ui/src/dashboards/components/CellEditorOverlay.tsx b/ui/src/dashboards/components/CellEditorOverlay.tsx index 6520416685..949eb2805a 100644 --- a/ui/src/dashboards/components/CellEditorOverlay.tsx +++ b/ui/src/dashboards/components/CellEditorOverlay.tsx @@ -1,9 +1,10 @@ +// Libraries import React, {Component} from 'react' - import _ from 'lodash' import uuid from 'uuid' -import {getDeep} from 'src/utils/wrappers' +// Components +import {ErrorHandling} from 'src/shared/decorators/errors' import ResizeContainer from 'src/shared/components/ResizeContainer' import QueryMaker from 'src/dashboards/components/QueryMaker' import Visualization from 'src/dashboards/components/Visualization' @@ -11,14 +12,18 @@ import OverlayControls from 'src/dashboards/components/OverlayControls' import DisplayOptions from 'src/dashboards/components/DisplayOptions' import CEOBottom from 'src/dashboards/components/CEOBottom' -import * as queryTransitions from 'src/utils/queryTransitions' +// APIs +import {getQueryConfigAndStatus} from 'src/shared/apis' +// Utils +import {getDeep} from 'src/utils/wrappers' +import * as queryTransitions from 'src/utils/queryTransitions' import defaultQueryConfig from 'src/utils/defaultQueryConfig' import {buildQuery} from 'src/utils/influxql' -import {getQueryConfigAndStatus} from 'src/shared/apis' -import {IS_STATIC_LEGEND} from 'src/shared/constants' import {nextSource} from 'src/dashboards/utils/sources' +// Constants +import {IS_STATIC_LEGEND} from 'src/shared/constants' import {TYPE_QUERY_CONFIG} from 'src/dashboards/constants' import {removeUnselectedTemplateValues} from 'src/tempVars/constants' import {OVERLAY_TECHNOLOGY} from 'src/shared/constants/classNames' @@ -30,19 +35,13 @@ import { } from 'src/shared/constants' import {getCellTypeColors} from 'src/dashboards/constants/cellEditor' -import {ErrorHandling} from 'src/shared/decorators/errors' - -import { - TimeRange, - Source, - QueryConfig, - Cell, - CellQuery, - Legend, - Status, -} from 'src/types' -import {ColorString, ColorNumber} from 'src/types/colors' -import {SourceOption} from 'src/dashboards/components/OverlayControls' +// Types +import * as CellEditorOverlayActions from 'src/types/actions/cellEditorOverlay' +import * as ColorsModels from 'src/types/colors' +import * as DashboardsActions from 'src/types/actions/dashboards' +import * as DashboardsModels from 'src/types/dashboards' +import * as QueriesModels from 'src/types/queries' +import * as SourcesModels from 'src/types/sources' type QueryTransitions = typeof queryTransitions type EditRawTextAsyncFunc = ( @@ -58,7 +57,7 @@ export type CellEditorOverlayActions = QueryActions & { editRawTextAsync: EditRawTextAsyncFunc } -const staticLegend: Legend = { +const staticLegend: DashboardsModels.Legend = { type: 'static', orientation: 'bottom', } @@ -69,37 +68,40 @@ interface Template { interface QueryStatus { queryID: string - status: Status + status: QueriesModels.Status } interface Props { - sources: Source[] - editQueryStatus: () => void + sources: SourcesModels.Source[] + editQueryStatus: DashboardsActions.EditCellQueryStatusActionCreator onCancel: () => void - onSave: (cell: Cell) => void - source: Source + onSave: (cell: DashboardsModels.Cell) => void + source: SourcesModels.Source dashboardID: number queryStatus: QueryStatus autoRefresh: number templates: Template[] - timeRange: TimeRange + timeRange: QueriesModels.TimeRange thresholdsListType: string - thresholdsListColors: ColorNumber[] - gaugeColors: ColorNumber[] - lineColors: ColorString[] - cell: Cell + thresholdsListColors: ColorsModels.ColorNumber[] + gaugeColors: ColorsModels.ColorNumber[] + lineColors: ColorsModels.ColorString[] + cell: DashboardsModels.Cell } interface State { - queriesWorkingDraft: QueryConfig[] + queriesWorkingDraft: QueriesModels.QueryConfig[] activeQueryIndex: number isDisplayOptionsTabActive: boolean isStaticLegend: boolean } -const createWorkingDraft = (source: Source, query: CellQuery): QueryConfig => { +const createWorkingDraft = ( + source: SourcesModels.Source, + query: DashboardsModels.CellQuery +): QueriesModels.QueryConfig => { const {queryConfig} = query - const draft: QueryConfig = { + const draft: QueriesModels.QueryConfig = { ...queryConfig, id: uuid.v4(), source, @@ -109,11 +111,13 @@ const createWorkingDraft = (source: Source, query: CellQuery): QueryConfig => { } const createWorkingDrafts = ( - source: Source, - queries: CellQuery[] -): QueryConfig[] => + source: SourcesModels.Source, + queries: DashboardsModels.CellQuery[] +): QueriesModels.QueryConfig[] => _.cloneDeep( - queries.map((query: CellQuery) => createWorkingDraft(source, query)) + queries.map((query: DashboardsModels.CellQuery) => + createWorkingDraft(source, query) + ) ) @ErrorHandling @@ -247,7 +251,7 @@ class CellEditorOverlay extends Component { ) } - private get formattedSources(): SourceOption[] { + private get formattedSources(): SourcesModels.SourceOption[] { const {sources} = this.props return sources.map(s => ({ ...s, @@ -302,8 +306,11 @@ class CellEditorOverlay extends Component { const {queriesWorkingDraft, isStaticLegend} = this.state const {cell, thresholdsListColors, gaugeColors, lineColors} = this.props - const queries: CellQuery[] = queriesWorkingDraft.map(q => { - const timeRange = q.range || {upper: null, lower: TEMP_VAR_DASHBOARD_TIME} + const queries: DashboardsModels.CellQuery[] = queriesWorkingDraft.map(q => { + const timeRange = q.range || { + upper: null, + lower: TEMP_VAR_DASHBOARD_TIME, + } const source = getDeep(q.source, 'links.self', null) return { queryConfig: q, @@ -319,7 +326,7 @@ class CellEditorOverlay extends Component { lineColors, }) - const newCell: Cell = { + const newCell: DashboardsModels.Cell = { ...cell, queries, colors, @@ -341,8 +348,8 @@ class CellEditorOverlay extends Component { this.setState({isStaticLegend}) } - private handleSetQuerySource = (source: Source): void => { - const queriesWorkingDraft: QueryConfig[] = this.state.queriesWorkingDraft.map( + private handleSetQuerySource = (source: SourcesModels.Source): void => { + const queriesWorkingDraft: QueriesModels.QueryConfig[] = this.state.queriesWorkingDraft.map( q => ({ ..._.cloneDeep(q), source, @@ -418,8 +425,8 @@ class CellEditorOverlay extends Component { ) const config = data.queries.find(q => q.id === id) - const nextQueries: QueryConfig[] = this.state.queriesWorkingDraft.map( - (q: QueryConfig) => { + const nextQueries: QueriesModels.QueryConfig[] = this.state.queriesWorkingDraft.map( + (q: QueriesModels.QueryConfig) => { if (q.id === id) { const isQuerySupportedByExplorer = !isUsingUserDefinedTempVars @@ -447,18 +454,20 @@ class CellEditorOverlay extends Component { private findSelectedSource = (): string => { const {source} = this.props const sources = this.formattedSources - const currentSource = getDeep( + const currentSource = getDeep( this.state.queriesWorkingDraft, '0.source', null ) if (!currentSource) { - const defaultSource: Source = sources.find(s => s.id === source.id) + const defaultSource: SourcesModels.Source = sources.find( + s => s.id === source.id + ) return (defaultSource && defaultSource.text) || 'No sources' } - const selected: Source = sources.find( + const selected: SourcesModels.Source = sources.find( s => s.links.self === currentSource.links.self ) return (selected && selected.text) || 'No sources' @@ -502,7 +511,7 @@ class CellEditorOverlay extends Component { const {queriesWorkingDraft} = this.state return queriesWorkingDraft.every( - (query: QueryConfig) => + (query: QueriesModels.QueryConfig) => (!!query.measurement && !!query.database && !!query.fields.length) || !!query.rawText ) @@ -522,7 +531,7 @@ class CellEditorOverlay extends Component { return result } - private get initialSource(): Source { + private get initialSource(): SourcesModels.Source { const { cell: {queries}, source, @@ -541,7 +550,7 @@ class CellEditorOverlay extends Component { return source } - private get source(): Source { + private get source(): SourcesModels.Source { const {source, sources} = this.props const query = _.get(this.state.queriesWorkingDraft, 0, {source: null}) diff --git a/ui/src/dashboards/components/DashboardEmpty.tsx b/ui/src/dashboards/components/DashboardEmpty.tsx index 5a450dbfd8..c514699750 100644 --- a/ui/src/dashboards/components/DashboardEmpty.tsx +++ b/ui/src/dashboards/components/DashboardEmpty.tsx @@ -1,5 +1,5 @@ import React, {Component} from 'react' -import {Cell} from 'src/types/dashboard' +import {Cell} from 'src/types/dashboards' import {connect} from 'react-redux' import {bindActionCreators} from 'redux' diff --git a/ui/src/dashboards/components/DashboardHeader.tsx b/ui/src/dashboards/components/DashboardHeader.tsx index 2f06e2dc0e..f27354b9bd 100644 --- a/ui/src/dashboards/components/DashboardHeader.tsx +++ b/ui/src/dashboards/components/DashboardHeader.tsx @@ -10,30 +10,29 @@ import TimeRangeDropdown from 'src/shared/components/TimeRangeDropdown' import GraphTips from 'src/shared/components/GraphTips' import DashboardHeaderEdit from 'src/dashboards/components/DashboardHeaderEdit' import DashboardSwitcher from 'src/dashboards/components/DashboardSwitcher' -import {Dashboard, TimeRange} from 'src/types' -interface DashboardName { - text: string -} +import * as AppActions from 'src/types/actions/app' +import * as DashboardsModels from 'src/types/dashboards' +import * as QueriesModels from 'src/types/queries' interface Props { activeDashboard: string - dashboard: Dashboard + dashboard: DashboardsModels.Dashboard onEditDashboard: () => void - timeRange: TimeRange + timeRange: QueriesModels.TimeRange autoRefresh: number isEditMode?: boolean - handleChooseTimeRange: (timeRange: TimeRange) => void - handleChooseAutoRefresh: () => void + handleChooseTimeRange: (timeRange: QueriesModels.TimeRange) => void + handleChooseAutoRefresh: AppActions.SetAutoRefreshActionCreator onManualRefresh: () => void - handleClickPresentationButton: () => void + handleClickPresentationButton: AppActions.DelayEnablePresentationModeDispatcher onAddCell: () => void onToggleTempVarControls: () => void showTemplateControlBar: boolean - zoomedTimeRange: TimeRange + zoomedTimeRange: QueriesModels.TimeRange onCancel: () => void - onSave: () => void - names: DashboardName[] + onSave: (name: string) => Promise + names: DashboardsModels.DashboardName[] isHidden: boolean } @@ -76,7 +75,6 @@ class DashboardHeader extends Component { handleChooseTimeRange, timeRange: {upper, lower}, zoomedTimeRange: {upper: zoomedUpper, lower: zoomedLower}, - handleClickPresentationButton, } = this.props return ( @@ -99,13 +97,16 @@ class DashboardHeader extends Component { /> ) } + private handleClickPresentationButton = (): void => { + this.props.handleClickPresentationButton() + } private get addCellButton(): JSX.Element { const {dashboard, onAddCell} = this.props diff --git a/ui/src/dashboards/components/DashboardsPageContents.tsx b/ui/src/dashboards/components/DashboardsPageContents.tsx index 780a3dea8a..a8c1fbbb00 100644 --- a/ui/src/dashboards/components/DashboardsPageContents.tsx +++ b/ui/src/dashboards/components/DashboardsPageContents.tsx @@ -10,7 +10,7 @@ import FancyScrollbar from 'src/shared/components/FancyScrollbar' import {ErrorHandling} from 'src/shared/decorators/errors' import { showOverlay as showOverlayAction, - ShowOverlay, + ShowOverlayActionCreator, } from 'src/shared/actions/overlayTechnology' import {OverlayContext} from 'src/shared/components/OverlayTechnology' @@ -27,7 +27,7 @@ interface Props { onExportDashboard: (dashboard: Dashboard) => () => void onImportDashboard: (dashboard: Dashboard) => void notify: (message: Notification) => void - showOverlay: ShowOverlay + showOverlay: ShowOverlayActionCreator dashboardLink: string } diff --git a/ui/src/dashboards/components/GraphOptionsDecimalPlaces.tsx b/ui/src/dashboards/components/GraphOptionsDecimalPlaces.tsx index 75de17b1b8..0a1c8c390d 100644 --- a/ui/src/dashboards/components/GraphOptionsDecimalPlaces.tsx +++ b/ui/src/dashboards/components/GraphOptionsDecimalPlaces.tsx @@ -2,7 +2,7 @@ import React, {PureComponent} from 'react' import {ErrorHandling} from 'src/shared/decorators/errors' import OptIn from 'src/shared/components/OptIn' -import {DecimalPlaces} from 'src/types/dashboard' +import {DecimalPlaces} from 'src/types/dashboards' interface Props extends DecimalPlaces { onDecimalPlacesChange: (decimalPlaces: DecimalPlaces) => void diff --git a/ui/src/dashboards/components/OverlayControls.tsx b/ui/src/dashboards/components/OverlayControls.tsx index a87f865f2b..7907798d06 100644 --- a/ui/src/dashboards/components/OverlayControls.tsx +++ b/ui/src/dashboards/components/OverlayControls.tsx @@ -3,11 +3,9 @@ import classnames from 'classnames' import ConfirmOrCancel from 'src/shared/components/ConfirmOrCancel' import SourceSelector from 'src/dashboards/components/SourceSelector' -import {QueryConfig, Source} from 'src/types' -export interface SourceOption extends Source { - text: string -} +import * as QueriesModels from 'src/types/queries' +import * as SourcesModels from 'src/types/sources' interface Props { onCancel: () => void @@ -17,10 +15,10 @@ interface Props { displayOptions: boolean ) => (event: MouseEvent) => void isSavable: boolean - sources: SourceOption[] - onSetQuerySource: (source: Source) => void + sources: SourcesModels.SourceOption[] + onSetQuerySource: (source: SourcesModels.Source) => void selected: string - queries: QueryConfig[] + queries: QueriesModels.QueryConfig[] } const OverlayControls: SFC = ({ diff --git a/ui/src/dashboards/components/SourceSelector.tsx b/ui/src/dashboards/components/SourceSelector.tsx index d09eca2ee5..5479bde4c5 100644 --- a/ui/src/dashboards/components/SourceSelector.tsx +++ b/ui/src/dashboards/components/SourceSelector.tsx @@ -1,13 +1,15 @@ import React, {SFC} from 'react' + import Dropdown from 'src/shared/components/Dropdown' -import {QueryConfig} from 'src/types' -import {SourceOption} from 'src/dashboards/components/OverlayControls' + +import * as QueriesModels from 'src/types/queries' +import * as SourcesModels from 'src/types/sources' interface Props { - sources: SourceOption[] + sources: SourcesModels.SourceOption[] selected: string - onSetQuerySource: (source: SourceOption) => void - queries: QueryConfig[] + onSetQuerySource: (source: SourcesModels.SourceOption) => void + queries: QueriesModels.QueryConfig[] } const SourceSelector: SFC = ({ diff --git a/ui/src/dashboards/components/TableOptions.tsx b/ui/src/dashboards/components/TableOptions.tsx index 8527929b59..97321aa258 100644 --- a/ui/src/dashboards/components/TableOptions.tsx +++ b/ui/src/dashboards/components/TableOptions.tsx @@ -24,8 +24,8 @@ import { import {DEFAULT_TIME_FIELD} from 'src/dashboards/constants' import {ErrorHandling} from 'src/shared/decorators/errors' -import {DecimalPlaces} from 'src/types/dashboard' -import {QueryConfig} from 'src/types/query' +import {DecimalPlaces} from 'src/types/dashboards' +import {QueryConfig} from 'src/types/queries' interface DropdownOption { text: string diff --git a/ui/src/dashboards/components/Visualization.tsx b/ui/src/dashboards/components/Visualization.tsx index ddbbc13b93..98b9d440ce 100644 --- a/ui/src/dashboards/components/Visualization.tsx +++ b/ui/src/dashboards/components/Visualization.tsx @@ -15,7 +15,7 @@ import { DecimalPlaces, FieldOption, CellType, -} from 'src/types/dashboard' +} from 'src/types/dashboards' import {ColorString, ColorNumber} from 'src/types/colors' interface Props { diff --git a/ui/src/dashboards/constants/cellEditor.ts b/ui/src/dashboards/constants/cellEditor.ts index a22bc262d6..a7f941bd9f 100644 --- a/ui/src/dashboards/constants/cellEditor.ts +++ b/ui/src/dashboards/constants/cellEditor.ts @@ -1,6 +1,6 @@ import {DEFAULT_TABLE_OPTIONS} from 'src/dashboards/constants' import {stringifyColorValues} from 'src/shared/constants/colorOperations' -import {CellType, Axis} from 'src/types/dashboard' +import {CellType, Axis} from 'src/types/dashboards' import {ColorString, ColorNumber} from 'src/types/colors' export const initializeOptions = (cellType: CellType) => { diff --git a/ui/src/dashboards/constants/index.ts b/ui/src/dashboards/constants/index.ts index 99ec7a64a3..e72994dae1 100644 --- a/ui/src/dashboards/constants/index.ts +++ b/ui/src/dashboards/constants/index.ts @@ -3,7 +3,7 @@ import { DEFAULT_FIX_FIRST_COLUMN, } from 'src/shared/constants/tableGraph' import {Cell, QueryConfig} from 'src/types' -import {CellType, Dashboard, DecimalPlaces} from 'src/types/dashboard' +import {CellType, Dashboard, DecimalPlaces} from 'src/types/dashboards' export const UNTITLED_GRAPH: string = 'Untitled Graph' diff --git a/ui/src/dashboards/containers/DashboardPage.js b/ui/src/dashboards/containers/DashboardPage.tsx similarity index 55% rename from ui/src/dashboards/containers/DashboardPage.js rename to ui/src/dashboards/containers/DashboardPage.tsx index 915927f908..107e7fb505 100644 --- a/ui/src/dashboards/containers/DashboardPage.js +++ b/ui/src/dashboards/containers/DashboardPage.tsx @@ -1,58 +1,129 @@ -import React, {Component} from 'react' -import PropTypes from 'prop-types' +// Libraries +import React, {Component, MouseEvent} from 'react' import {connect} from 'react-redux' import {withRouter} from 'react-router' -import {bindActionCreators} from 'redux' - import _ from 'lodash' +// Components import {isUserAuthorized, EDITOR_ROLE} from 'src/auth/Authorized' - +import {ErrorHandling} from 'src/shared/decorators/errors' import CellEditorOverlay from 'src/dashboards/components/CellEditorOverlay' import DashboardHeader from 'src/dashboards/components/DashboardHeader' import Dashboard from 'src/dashboards/components/Dashboard' import ManualRefresh from 'src/shared/components/ManualRefresh' import TemplateControlBar from 'src/tempVars/components/TemplateControlBar' -import {errorThrown as errorThrownAction} from 'shared/actions/errors' -import {notify as notifyAction} from 'shared/actions/notifications' +// Actions +import * as dashboardActions from 'src/dashboards/actions' +import * as annotationActions from 'src/shared/actions/annotations' +import * as cellEditorOverlayActions from 'src/dashboards/actions/cellEditorOverlay' +import * as appActions from 'src/shared/actions/app' +import * as errorActions from 'src/shared/actions/errors' +import * as notifyActions from 'src/shared/actions/notifications' + +// Utils import idNormalizer, {TYPE_ID} from 'src/normalizers/id' import {millisecondTimeRange} from 'src/dashboards/utils/time' - -import * as dashboardActionCreators from 'src/dashboards/actions' -import * as annotationActions from 'shared/actions/annotations' - -import { - showCellEditorOverlay, - hideCellEditorOverlay, -} from 'src/dashboards/actions/cellEditorOverlay' -import {showOverlay} from 'src/shared/actions/overlayTechnology' - import {stripTempVar} from 'src/dashboards/utils/tempVars' +import {getDeep} from 'src/utils/wrappers' -import {dismissEditingAnnotation} from 'src/shared/actions/annotations' - -import { - setAutoRefresh, - templateControlBarVisibilityToggled as templateControlBarVisibilityToggledAction, -} from 'shared/actions/app' -import {presentationButtonDispatcher} from 'shared/dispatchers' +// Constants import { interval, DASHBOARD_LAYOUT_ROW_HEIGHT, TEMP_VAR_DASHBOARD_TIME, TEMP_VAR_UPPER_DASHBOARD_TIME, -} from 'shared/constants' +} from 'src/shared/constants' import {FORMAT_INFLUXQL, defaultTimeRange} from 'src/shared/data/timeRanges' -import {colorsStringSchema, colorsNumberSchema} from 'shared/schemas' -import {ErrorHandling} from 'src/shared/decorators/errors' +// Types +import {WithRouterProps} from 'react-router' +import {ManualRefreshProps} from 'src/shared/components/ManualRefresh' +import {Location} from 'history' +import {InjectedRouter} from 'react-router' +import * as AnnotationsActions from 'src/types/actions/annotations' +import * as AppActions from 'src/types/actions/app' +import * as CellEditorOverlayActions from 'src/types/actions/cellEditorOverlay' +import * as ColorsModels from 'src/types/colors' +import * as DashboardsActions from 'src/types/actions/dashboards' +import * as DashboardsModels from 'src/types/dashboards' +import * as ErrorsActions from 'src/types/actions/errors' +import * as QueriesModels from 'src/types/queries' +import * as SourcesModels from 'src/types/sources' +import * as TempVarsModels from 'src/types/tempVars' +import * as NotificationsActions from 'src/types/actions/notifications' -import {getDeep} from 'src/utils/wrappers' +interface DashboardActions { + setDashTimeV1: DashboardsActions.SetDashTimeV1ActionCreator + updateDashboard: DashboardsActions.UpdateDashboardActionCreator + syncURLQueryParamsFromQueryParamsObject: DashboardsActions.SyncURLQueryFromQueryParamsObjectDispatcher + putDashboard: DashboardsActions.PutDashboardDispatcher + putDashboardByID: DashboardsActions.PutDashboardByIDDispatcher + getDashboardsNamesAsync: DashboardsActions.GetDashboardsNamesDispatcher + getDashboardWithHydratedAndSyncedTempVarsAsync: DashboardsActions.GetDashboardWithHydratedAndSyncedTempVarsAsyncDispatcher + setTimeRange: DashboardsActions.SetTimeRangeActionCreator + addDashboardCellAsync: DashboardsActions.AddDashboardCellDispatcher + editCellQueryStatus: DashboardsActions.EditCellQueryStatusActionCreator + updateDashboardCell: DashboardsActions.UpdateDashboardCellDispatcher + cloneDashboardCellAsync: DashboardsActions.CloneDashboardCellDispatcher + deleteDashboardCellAsync: DashboardsActions.DeleteDashboardCellDispatcher + templateVariableSelected: DashboardsActions.TemplateVariableSelectedActionCreator + syncURLQueryFromTempVars: DashboardsActions.SyncURLQueryFromTempVarsDispatcher + setZoomedTimeRangeAsync: DashboardsActions.SetZoomedTimeRangeDispatcher +} + +interface Props extends DashboardActions, ManualRefreshProps, WithRouterProps { + source: SourcesModels.Source + sources: SourcesModels.Source[] + params: { + sourceID: string + dashboardID: string + } + location: Location + dashboardID: number + dashboard: DashboardsModels.Dashboard + dashboards: DashboardsModels.Dashboard[] + handleChooseAutoRefresh: AppActions.SetAutoRefreshActionCreator + autoRefresh: number + templateControlBarVisibilityToggled: () => AppActions.TemplateControlBarVisibilityToggledActionCreator + timeRange: QueriesModels.TimeRange + zoomedTimeRange: QueriesModels.TimeRange + showTemplateControlBar: boolean + inPresentationMode: boolean + handleClickPresentationButton: AppActions.DelayEnablePresentationModeDispatcher + cellQueryStatus: { + queryID: string + status: object + } + errorThrown: ErrorsActions.ErrorThrownActionCreator + meRole: string + isUsingAuth: boolean + router: InjectedRouter + notify: NotificationsActions.PublishNotificationActionCreator + getAnnotationsAsync: AnnotationsActions.GetAnnotationsDispatcher + handleShowCellEditorOverlay: CellEditorOverlayActions.ShowCellEditorOverlayActionCreator + handleHideCellEditorOverlay: CellEditorOverlayActions.HideCellEditorOverlayActionCreator + handleDismissEditingAnnotation: AnnotationsActions.DismissEditingAnnotationActionCreator + selectedCell: DashboardsModels.Cell + thresholdsListType: string + thresholdsListColors: ColorsModels.ColorNumber[] + gaugeColors: ColorsModels.ColorNumber[] + lineColors: ColorsModels.ColorString[] +} + +interface State { + isEditMode: boolean + selectedCell: DashboardsModels.Cell | null + scrollTop: number + windowHeight: number + dashboardsNames: DashboardsModels.DashboardName[] +} @ErrorHandling -class DashboardPage extends Component { - constructor(props) { +class DashboardPage extends Component { + private intervalID: number + + public constructor(props: Props) { super(props) this.state = { @@ -64,10 +135,9 @@ class DashboardPage extends Component { } } - async componentDidMount() { + public async componentDidMount() { const { - params: {dashboardID}, - dashboardActions: {putDashboardByID}, + dashboardID, source, meRole, isUsingAuth, @@ -80,7 +150,7 @@ class DashboardPage extends Component { getAnnotationsAsync(source.links.annotations, annotationRange) if (autoRefresh) { - this.intervalID = setInterval(() => { + this.intervalID = window.setInterval(() => { getAnnotationsAsync(source.links.annotations, annotationRange) }, autoRefresh) } @@ -93,26 +163,26 @@ class DashboardPage extends Component { // is refactored so as not to require a write operation (a PUT in this case) if (!isUsingAuth || isUserAuthorized(meRole, EDITOR_ROLE)) { // putDashboardByID refreshes & persists influxql generated template variable values. - await putDashboardByID(dashboardID) + await this.props.putDashboardByID(dashboardID) } this.getDashboardsNames() } - componentWillReceiveProps(nextProps) { + public componentWillReceiveProps(nextProps: Props) { const {source, getAnnotationsAsync, timeRange} = this.props if (this.props.autoRefresh !== nextProps.autoRefresh) { clearInterval(this.intervalID) const annotationRange = millisecondTimeRange(timeRange) if (nextProps.autoRefresh) { - this.intervalID = setInterval(() => { + this.intervalID = window.setInterval(() => { getAnnotationsAsync(source.links.annotations, annotationRange) }, nextProps.autoRefresh) } } } - componentDidUpdate(prevProps) { + public componentDidUpdate(prevProps: Props) { const prevPath = getDeep(prevProps.location, 'pathname', null) const thisPath = getDeep(this.props.location, 'pathname', null) @@ -121,211 +191,13 @@ class DashboardPage extends Component { } } - handleWindowResize = () => { - this.setState({windowHeight: window.innerHeight}) - } - - componentWillUnmount() { + public componentWillUnmount() { clearInterval(this.intervalID) - this.intervalID = false window.removeEventListener('resize', this.handleWindowResize, true) this.props.handleDismissEditingAnnotation() } - async getDashboard() { - const { - params: {dashboardID}, - dashboardActions: {getDashboardWithHydratedAndSyncedTempVarsAsync}, - source, - router, - location, - } = this.props - - return await getDashboardWithHydratedAndSyncedTempVarsAsync( - dashboardID, - source, - router, - location - ) - } - - async getDashboardsNames() { - const { - params: {sourceID}, - dashboardActions: {getDashboardsNamesAsync}, - } = this.props - - const dashboardsNames = await getDashboardsNamesAsync(sourceID) - this.setState({dashboardsNames}) - } - - inView = cell => { - const {scrollTop, windowHeight} = this.state - const bufferValue = 600 - const cellTop = cell.y * DASHBOARD_LAYOUT_ROW_HEIGHT - const cellBottom = (cell.y + cell.h) * DASHBOARD_LAYOUT_ROW_HEIGHT - const bufferedWindowBottom = windowHeight + scrollTop + bufferValue - const bufferedWindowTop = scrollTop - bufferValue - const topInView = cellTop < bufferedWindowBottom - const bottomInView = cellBottom > bufferedWindowTop - - return topInView && bottomInView - } - - handleSaveEditedCell = newCell => { - const { - dashboardActions, - dashboard, - handleHideCellEditorOverlay, - } = this.props - dashboardActions - .updateDashboardCell(dashboard, newCell) - .then(handleHideCellEditorOverlay) - } - - handleChooseTimeRange = timeRange => { - const { - dashboard, - dashboardActions, - getAnnotationsAsync, - source, - location, - } = this.props - - dashboardActions.setDashTimeV1(dashboard.id, { - ...timeRange, - format: FORMAT_INFLUXQL, - }) - - dashboardActions.syncURLQueryParamsFromQueryParamsObject(location, { - lower: timeRange.lower, - upper: timeRange.upper, - }) - - const annotationRange = millisecondTimeRange(timeRange) - getAnnotationsAsync(source.links.annotations, annotationRange) - } - - handleUpdatePosition = cells => { - const {dashboardActions, dashboard, meRole, isUsingAuth} = this.props - const newDashboard = {...dashboard, cells} - - // GridLayout invokes onLayoutChange on first load, which bubbles up to - // invoke handleUpdatePosition. If using auth, Viewer is not authorized to - // PUT, so until the need for PUT is removed, this is prevented. - if (!isUsingAuth || isUserAuthorized(meRole, EDITOR_ROLE)) { - dashboardActions.updateDashboard(newDashboard) - dashboardActions.putDashboard(newDashboard) - } - } - - handleAddCell = () => { - const {dashboardActions, dashboard} = this.props - dashboardActions.addDashboardCellAsync(dashboard) - } - - handleCloneCell = cell => { - const {dashboardActions, dashboard} = this.props - dashboardActions.cloneDashboardCellAsync(dashboard, cell) - } - - handleEditDashboard = () => { - this.setState({isEditMode: true}) - } - - handleCancelEditDashboard = () => { - this.setState({isEditMode: false}) - } - - handleRenameDashboard = async name => { - const {dashboardActions, dashboard} = this.props - this.setState({isEditMode: false}) - const newDashboard = {...dashboard, name} - - dashboardActions.updateDashboard(newDashboard) - await dashboardActions.putDashboard(newDashboard) - this.getDashboardsNames() - } - - handleUpdateDashboardCell = newCell => () => { - const {dashboardActions, dashboard} = this.props - dashboardActions.updateDashboardCell(dashboard, newCell) - } - - handleDeleteDashboardCell = cell => { - const {dashboardActions, dashboard} = this.props - dashboardActions.deleteDashboardCellAsync(dashboard, cell) - } - - handleSelectTemplate = templateID => value => { - const { - dashboardActions, - dashboard, - params: {dashboardID}, - location, - } = this.props - - const currentTempVar = dashboard.templates.find( - tempVar => tempVar.id === templateID - ) - const strippedTempVar = stripTempVar(currentTempVar.tempVar) - const isTempVarInURLQuery = !!location.query[strippedTempVar] - - if (isTempVarInURLQuery) { - const updatedQueryParam = { - [strippedTempVar]: value.value, - } - dashboardActions.syncURLQueryParamsFromQueryParamsObject( - location, - updatedQueryParam - ) - } - dashboardActions.templateVariableSelected(dashboard.id, templateID, [value]) - dashboardActions.putDashboardByID(dashboardID) - } - - handleSaveTemplateVariables = async templates => { - const {location, dashboardActions, dashboard} = this.props - - try { - await dashboardActions.putDashboard({ - ...dashboard, - templates, - }) - const deletedTempVars = dashboard.templates.filter( - ({tempVar: oldTempVar}) => - !templates.find(({tempVar: newTempVar}) => oldTempVar === newTempVar) - ) - dashboardActions.syncURLQueryFromTempVars( - location, - templates, - deletedTempVars - ) - } catch (error) { - console.error(error) - } - } - - handleRunQueryFailure = error => { - console.error(error) - this.props.errorThrown(error) - } - - handleToggleTempVarControls = () => { - this.props.templateControlBarVisibilityToggled() - } - - handleZoomedTimeRange = (zoomedLower, zoomedUpper) => { - const {dashboardActions, location} = this.props - const zoomedTimeRange = {lower: zoomedLower, upper: zoomedUpper} - dashboardActions.setZoomedTimeRangeAsync(zoomedTimeRange, location) - } - - setScrollTop = event => { - this.setState({scrollTop: event.target.scrollTop}) - } - - render() { + public render() { const { isUsingAuth, meRole, @@ -337,7 +209,7 @@ class DashboardPage extends Component { zoomedTimeRange: {lower: zoomedLower, upper: zoomedUpper}, showTemplateControlBar, dashboard, - dashboards, + dashboardID, lineColors, gaugeColors, autoRefresh, @@ -347,13 +219,12 @@ class DashboardPage extends Component { cellQueryStatus, thresholdsListType, thresholdsListColors, - dashboardActions, + inPresentationMode, handleChooseAutoRefresh, handleShowCellEditorOverlay, handleHideCellEditorOverlay, handleClickPresentationButton, - params: {sourceID, dashboardID}, } = this.props const {dashboardsNames} = this.state @@ -416,7 +287,7 @@ class DashboardPage extends Component { onSave={this.handleSaveEditedCell} onCancel={handleHideCellEditorOverlay} templates={templatesIncludingDashTime} - editQueryStatus={dashboardActions.editCellQueryStatus} + editQueryStatus={this.props.editCellQueryStatus} thresholdsListType={thresholdsListType} thresholdsListColors={thresholdsListColors} gaugeColors={gaugeColors} @@ -425,9 +296,7 @@ class DashboardPage extends Component { ) : null} @@ -481,96 +347,194 @@ class DashboardPage extends Component { ) } -} -const {arrayOf, bool, func, number, shape, string} = PropTypes + private handleWindowResize = (): void => { + this.setState({windowHeight: window.innerHeight}) + } -DashboardPage.propTypes = { - source: shape({ - links: shape({ - proxy: string, - self: string, - }), - }).isRequired, - sources: arrayOf(shape({})).isRequired, - params: shape({ - sourceID: string.isRequired, - dashboardID: number.isRequired, - }).isRequired, - location: shape({ - pathname: string.isRequired, - query: shape({}), - }).isRequired, - dashboard: shape({}), - dashboardActions: shape({ - putDashboard: func.isRequired, - getDashboardsNamesAsync: func.isRequired, - getDashboardWithHydratedAndSyncedTempVarsAsync: func.isRequired, - setTimeRange: func.isRequired, - addDashboardCellAsync: func.isRequired, - }).isRequired, - dashboards: arrayOf( - shape({ - id: number.isRequired, - cells: arrayOf(shape({})).isRequired, - templates: arrayOf( - shape({ - type: string.isRequired, - tempVar: string.isRequired, - query: shape({ - db: string, - rp: string, - influxql: string, - }), - values: arrayOf( - shape({ - value: string.isRequired, - selected: bool.isRequired, - type: string.isRequired, - }) - ), - }) - ), + private getDashboard = async (): Promise< + DashboardsActions.GetDashboardWithHydratedAndSyncedTempVarsAsyncThunk + > => { + const {dashboardID, source, router, location} = this.props + + return await this.props.getDashboardWithHydratedAndSyncedTempVarsAsync( + dashboardID, + source, + router, + location + ) + } + + private getDashboardsNames = async (): Promise => { + const { + params: {sourceID}, + } = this.props + + // TODO: remove any once react-redux connect is properly typed + const dashboardsNames = (await this.props.getDashboardsNamesAsync( + sourceID + )) as any + + this.setState({dashboardsNames}) + } + + private inView = (cell: DashboardsModels.Cell): boolean => { + const {scrollTop, windowHeight} = this.state + const bufferValue = 600 + const cellTop = cell.y * DASHBOARD_LAYOUT_ROW_HEIGHT + const cellBottom = (cell.y + cell.h) * DASHBOARD_LAYOUT_ROW_HEIGHT + const bufferedWindowBottom = windowHeight + scrollTop + bufferValue + const bufferedWindowTop = scrollTop - bufferValue + const topInView = cellTop < bufferedWindowBottom + const bottomInView = cellBottom > bufferedWindowTop + + return topInView && bottomInView + } + + private handleSaveEditedCell = async ( + newCell: DashboardsModels.Cell + ): Promise => { + const {dashboard, handleHideCellEditorOverlay} = this.props + await this.props.updateDashboardCell(dashboard, newCell) + handleHideCellEditorOverlay() + } + + private handleChooseTimeRange = ( + timeRange: QueriesModels.TimeRange + ): void => { + const { + dashboard, + + getAnnotationsAsync, + source, + location, + } = this.props + + this.props.setDashTimeV1(dashboard.id, { + ...timeRange, + format: FORMAT_INFLUXQL, }) - ), - handleChooseAutoRefresh: func.isRequired, - autoRefresh: number.isRequired, - templateControlBarVisibilityToggled: func.isRequired, - timeRange: shape({ - upper: string, - lower: string, - }), - zoomedTimeRange: shape({ - upper: string, - lower: string, - }), - showTemplateControlBar: bool.isRequired, - inPresentationMode: bool.isRequired, - handleClickPresentationButton: func, - cellQueryStatus: shape({ - queryID: string, - status: shape(), - }).isRequired, - errorThrown: func, - manualRefresh: number.isRequired, - onManualRefresh: func.isRequired, - meRole: string, - isUsingAuth: bool.isRequired, - router: shape().isRequired, - notify: func.isRequired, - getAnnotationsAsync: func.isRequired, - handleShowCellEditorOverlay: func.isRequired, - handleHideCellEditorOverlay: func.isRequired, - handleDismissEditingAnnotation: func.isRequired, - selectedCell: shape({}), - thresholdsListType: string.isRequired, - thresholdsListColors: colorsNumberSchema.isRequired, - gaugeColors: colorsNumberSchema.isRequired, - lineColors: colorsStringSchema.isRequired, - handleShowOverlay: func.isRequired, + + this.props.syncURLQueryParamsFromQueryParamsObject(location, { + lower: timeRange.lower, + upper: timeRange.upper, + }) + + const annotationRange = millisecondTimeRange(timeRange) + getAnnotationsAsync(source.links.annotations, annotationRange) + } + + private handleUpdatePosition = (cells: DashboardsModels.Cell[]): void => { + const {dashboard, meRole, isUsingAuth} = this.props + const newDashboard = {...dashboard, cells} + + // GridLayout invokes onLayoutChange on first load, which bubbles up to + // invoke handleUpdatePosition. If using auth, Viewer is not authorized to + // PUT, so until the need for PUT is removed, this is prevented. + if (!isUsingAuth || isUserAuthorized(meRole, EDITOR_ROLE)) { + this.props.updateDashboard(newDashboard) + this.props.putDashboard(newDashboard) + } + } + + private handleAddCell = (): void => { + const {dashboard} = this.props + this.props.addDashboardCellAsync(dashboard) + } + + private handleCloneCell = (cell: DashboardsModels.Cell): void => { + const {dashboard} = this.props + this.props.cloneDashboardCellAsync(dashboard, cell) + } + + private handleEditDashboard = (): void => { + this.setState({isEditMode: true}) + } + + private handleCancelEditDashboard = (): void => { + this.setState({isEditMode: false}) + } + + private handleRenameDashboard = async (name: string): Promise => { + const {dashboard} = this.props + this.setState({isEditMode: false}) + const newDashboard = {...dashboard, name} + + this.props.updateDashboard(newDashboard) + await this.props.putDashboard(newDashboard) + this.getDashboardsNames() + } + + private handleDeleteDashboardCell = (cell: DashboardsModels.Cell): void => { + const {dashboard} = this.props + this.props.deleteDashboardCellAsync(dashboard, cell) + } + + private handleSelectTemplate = ( + templateID: string + ): ((value: TempVarsModels.TemplateValue) => void) => ( + value: TempVarsModels.TemplateValue + ): void => { + const {dashboard, dashboardID, location} = this.props + + const currentTempVar = dashboard.templates.find( + tempVar => tempVar.id === templateID + ) + const strippedTempVar = stripTempVar(currentTempVar.tempVar) + const isTempVarInURLQuery = !!location.query[strippedTempVar] + + if (isTempVarInURLQuery) { + const updatedQueryParam = { + [strippedTempVar]: value.value, + } + this.props.syncURLQueryParamsFromQueryParamsObject( + location, + updatedQueryParam + ) + } + this.props.templateVariableSelected(dashboard.id, templateID, [value]) + this.props.putDashboardByID(dashboardID) + } + + private handleSaveTemplateVariables = async ( + templates: TempVarsModels.Template[] + ): Promise => { + const {location, dashboard} = this.props + + try { + await this.props.putDashboard({ + ...dashboard, + templates, + }) + const deletedTempVars = dashboard.templates.filter( + ({tempVar: oldTempVar}) => + !templates.find(({tempVar: newTempVar}) => oldTempVar === newTempVar) + ) + this.props.syncURLQueryFromTempVars(location, templates, deletedTempVars) + } catch (error) { + console.error(error) + } + } + + private handleToggleTempVarControls = (): void => { + this.props.templateControlBarVisibilityToggled() + } + + private handleZoomedTimeRange = ( + zoomedTimeRange: QueriesModels.TimeRange + ): void => { + const {location} = this.props + this.props.setZoomedTimeRangeAsync(zoomedTimeRange, location) + } + + private setScrollTop = (e: MouseEvent): void => { + const target = e.target as HTMLElement + + this.setState({scrollTop: target.scrollTop}) + } } -const mapStateToProps = (state, {params: {dashboardID}}) => { +const mstp = (state, {params: {dashboardID}}) => { const { app: { ephemeral: {inPresentationMode}, @@ -606,6 +570,7 @@ const mapStateToProps = (state, {params: {dashboardID}}) => { sources, meRole, dashboard, + dashboardID: Number(dashboardID), timeRange, zoomedTimeRange, dashboards, @@ -622,35 +587,20 @@ const mapStateToProps = (state, {params: {dashboardID}}) => { } } -const mapDispatchToProps = dispatch => ({ - handleChooseAutoRefresh: bindActionCreators(setAutoRefresh, dispatch), - templateControlBarVisibilityToggled: bindActionCreators( - templateControlBarVisibilityToggledAction, - dispatch - ), - handleClickPresentationButton: presentationButtonDispatcher(dispatch), - dashboardActions: bindActionCreators(dashboardActionCreators, dispatch), - errorThrown: bindActionCreators(errorThrownAction, dispatch), - notify: bindActionCreators(notifyAction, dispatch), - getAnnotationsAsync: bindActionCreators( - annotationActions.getAnnotationsAsync, - dispatch - ), - handleShowCellEditorOverlay: bindActionCreators( - showCellEditorOverlay, - dispatch - ), - handleHideCellEditorOverlay: bindActionCreators( - hideCellEditorOverlay, - dispatch - ), - handleDismissEditingAnnotation: bindActionCreators( - dismissEditingAnnotation, - dispatch - ), - handleShowOverlay: bindActionCreators(showOverlay, dispatch), -}) +const mdtp = { + ...dashboardActions, + handleChooseAutoRefresh: appActions.setAutoRefresh, + templateControlBarVisibilityToggled: + appActions.templateControlBarVisibilityToggled, + handleClickPresentationButton: appActions.delayEnablePresentationMode, + errorThrown: errorActions.errorThrown, + notify: notifyActions.notify, + handleShowCellEditorOverlay: cellEditorOverlayActions.showCellEditorOverlay, + handleHideCellEditorOverlay: cellEditorOverlayActions.hideCellEditorOverlay, + getAnnotationsAsync: annotationActions.getAnnotationsAsync, + handleDismissEditingAnnotation: annotationActions.dismissEditingAnnotation, +} -export default connect(mapStateToProps, mapDispatchToProps)( - ManualRefresh(withRouter(DashboardPage)) +export default connect(mstp, mdtp)( + ManualRefresh(withRouter(DashboardPage)) ) diff --git a/ui/src/dashboards/containers/DashboardsPage.tsx b/ui/src/dashboards/containers/DashboardsPage.tsx index f3452b1c29..450b370053 100644 --- a/ui/src/dashboards/containers/DashboardsPage.tsx +++ b/ui/src/dashboards/containers/DashboardsPage.tsx @@ -26,7 +26,7 @@ import { import {Source, Dashboard} from 'src/types' import {Notification} from 'src/types/notifications' -import {DashboardFile} from 'src/types/dashboard' +import {DashboardFile} from 'src/types/dashboards' interface Props { source: Source diff --git a/ui/src/dashboards/graphics/graph.tsx b/ui/src/dashboards/graphics/graph.tsx index 971e0b8dfa..1f235160ed 100644 --- a/ui/src/dashboards/graphics/graph.tsx +++ b/ui/src/dashboards/graphics/graph.tsx @@ -1,6 +1,6 @@ import React, {ReactElement} from 'react' -import {CellType} from 'src/types/dashboard' +import {CellType} from 'src/types/dashboards' type Graphic = ReactElement diff --git a/ui/src/dashboards/reducers/cellEditorOverlay.ts b/ui/src/dashboards/reducers/cellEditorOverlay.ts index c72d744b95..8b6488c721 100644 --- a/ui/src/dashboards/reducers/cellEditorOverlay.ts +++ b/ui/src/dashboards/reducers/cellEditorOverlay.ts @@ -14,9 +14,9 @@ import { } from 'src/shared/constants/graphColorPalettes' import {initializeOptions} from 'src/dashboards/constants/cellEditor' -import {Action} from 'src/dashboards/actions/cellEditorOverlay' +import {Action} from 'src/types/actions/cellEditorOverlay' import {CellType, Cell} from 'src/types' -import {ThresholdType, TableOptions} from 'src/types/dashboard' +import {ThresholdType, TableOptions} from 'src/types/dashboards' import {ThresholdColor, GaugeColor, LineColor} from 'src/types/colors' interface CEOInitialState { diff --git a/ui/src/dashboards/reducers/dashTimeV1.js b/ui/src/dashboards/reducers/dashTimeV1.js index 0f95484dc1..fc1cfd350b 100644 --- a/ui/src/dashboards/reducers/dashTimeV1.js +++ b/ui/src/dashboards/reducers/dashTimeV1.js @@ -6,8 +6,8 @@ const initialState = { const dashTimeV1 = (state = initialState, action) => { switch (action.type) { case 'DELETE_DASHBOARD': { - const {dashboardID} = action.payload - const ranges = state.ranges.filter(r => r.dashboardID !== dashboardID) + const {dashboard} = action.payload + const ranges = state.ranges.filter(r => r.dashboardID !== dashboard.id) return {...state, ranges} } diff --git a/ui/src/dashboards/utils/cellGetters.ts b/ui/src/dashboards/utils/cellGetters.ts index 3a3a72c83d..28dd124bca 100644 --- a/ui/src/dashboards/utils/cellGetters.ts +++ b/ui/src/dashboards/utils/cellGetters.ts @@ -1,5 +1,5 @@ import {NEW_DEFAULT_DASHBOARD_CELL} from 'src/dashboards/constants' -import {Cell, CellType, Dashboard} from 'src/types/dashboard' +import {Cell, CellType, Dashboard} from 'src/types/dashboards' import {NewDefaultCell, UNTITLED_GRAPH} from 'src/dashboards/constants' const getMostCommonValue = (values: number[]): number => { @@ -55,12 +55,11 @@ const getNextAvailablePosition = (dashboard, newCell) => { export const getNewDashboardCell = ( dashboard: Dashboard, - cellType: CellType + cellType: CellType = CellType.Line ): NewDefaultCell => { - const type = cellType || CellType.Line const typedCell = { ...NEW_DEFAULT_DASHBOARD_CELL, - type, + type: cellType, name: UNTITLED_GRAPH, } diff --git a/ui/src/dashboards/utils/tableGraph.ts b/ui/src/dashboards/utils/tableGraph.ts index b84e3acd07..f4e842a1ba 100644 --- a/ui/src/dashboards/utils/tableGraph.ts +++ b/ui/src/dashboards/utils/tableGraph.ts @@ -13,7 +13,7 @@ import { FieldOption, TableOptions, DecimalPlaces, -} from 'src/types/dashboard' +} from 'src/types/dashboards' import {TimeSeriesValue} from 'src/types/series' interface ColumnWidths { diff --git a/ui/src/dashboards/utils/time.ts b/ui/src/dashboards/utils/time.ts index 172aa62282..f89405ca45 100644 --- a/ui/src/dashboards/utils/time.ts +++ b/ui/src/dashboards/utils/time.ts @@ -1,4 +1,4 @@ -import {TimeRange} from 'src/types/query' +import {TimeRange} from 'src/types/queries' import moment from 'moment' import {timeRanges} from 'src/shared/data/timeRanges' diff --git a/ui/src/data_explorer/components/QueryMakerTab.tsx b/ui/src/data_explorer/components/QueryMakerTab.tsx index 539af199cb..235a29a21c 100644 --- a/ui/src/data_explorer/components/QueryMakerTab.tsx +++ b/ui/src/data_explorer/components/QueryMakerTab.tsx @@ -1,7 +1,7 @@ import React, {PureComponent} from 'react' import classnames from 'classnames' import {ErrorHandling} from 'src/shared/decorators/errors' -import {QueryConfig} from 'src/types/query' +import {QueryConfig} from 'src/types/queries' interface Props { isActive: boolean diff --git a/ui/src/flux/components/FluxHeader.tsx b/ui/src/flux/components/FluxHeader.tsx index 6bbdc0ba71..d833ce48cf 100644 --- a/ui/src/flux/components/FluxHeader.tsx +++ b/ui/src/flux/components/FluxHeader.tsx @@ -5,14 +5,14 @@ import FluxOverlay from 'src/flux/components/FluxOverlay' import {OverlayContext} from 'src/shared/components/OverlayTechnology' import PageHeader from 'src/shared/components/PageHeader' import { - showOverlay as showOverlayAction, - ShowOverlay, + showOverlay, + ShowOverlayActionCreator, } from 'src/shared/actions/overlayTechnology' import {Service} from 'src/types' interface Props { - showOverlay: ShowOverlay + showOverlay: ShowOverlayActionCreator service: Service } @@ -36,9 +36,9 @@ class FluxHeader extends PureComponent { } private overlay = () => { - const {showOverlay, service} = this.props + const {service} = this.props - showOverlay( + this.props.showOverlay( {({onDismissOverlay}) => ( { } const mdtp = { - showOverlay: showOverlayAction, + showOverlay, } export default connect(null, mdtp)(FluxHeader) diff --git a/ui/src/flux/containers/CheckServices.tsx b/ui/src/flux/containers/CheckServices.tsx index adc4def462..fe546efed1 100644 --- a/ui/src/flux/containers/CheckServices.tsx +++ b/ui/src/flux/containers/CheckServices.tsx @@ -23,7 +23,7 @@ interface Props { sources: Source[] services: Service[] children: ReactChildren - showOverlay: a.ShowOverlay + showOverlay: a.ShowOverlayActionCreator fetchServicesAsync: b.FetchServicesAsync notify: (message: Notification) => void updateScript: UpdateScript diff --git a/ui/src/hosts/containers/HostPage.js b/ui/src/hosts/containers/HostPage.js index ff92a7074b..6205e81d16 100644 --- a/ui/src/hosts/containers/HostPage.js +++ b/ui/src/hosts/containers/HostPage.js @@ -1,7 +1,6 @@ import React, {Component} from 'react' import PropTypes from 'prop-types' import {connect} from 'react-redux' -import {bindActionCreators} from 'redux' import _ from 'lodash' import classnames from 'classnames' @@ -19,8 +18,7 @@ import { getAllHosts, } from 'src/hosts/apis' -import {setAutoRefresh} from 'shared/actions/app' -import {presentationButtonDispatcher} from 'shared/dispatchers' +import {setAutoRefresh, delayEnablePresentationMode} from 'shared/actions/app' import {ErrorHandling} from 'src/shared/decorators/errors' @ErrorHandling @@ -235,7 +233,7 @@ HostPage.propTypes = { handleClickPresentationButton: func, } -const mapStateToProps = ({ +const mstp = ({ app: { ephemeral: {inPresentationMode}, persisted: {autoRefresh}, @@ -245,11 +243,9 @@ const mapStateToProps = ({ autoRefresh, }) -const mapDispatchToProps = dispatch => ({ - handleChooseAutoRefresh: bindActionCreators(setAutoRefresh, dispatch), - handleClickPresentationButton: presentationButtonDispatcher(dispatch), -}) +const mdtp = { + handleChooseAutoRefresh: setAutoRefresh, + handleClickPresentationButton: delayEnablePresentationMode, +} -export default connect(mapStateToProps, mapDispatchToProps)( - ManualRefresh(HostPage) -) +export default connect(mstp, mdtp)(ManualRefresh(HostPage)) diff --git a/ui/src/index.tsx b/ui/src/index.tsx index 438517a761..e5ffd35083 100644 --- a/ui/src/index.tsx +++ b/ui/src/index.tsx @@ -50,6 +50,8 @@ import 'src/style/chronograf.scss' import {HEARTBEAT_INTERVAL} from 'src/shared/constants' +import * as ErrorsModels from 'src/types/errors' + const errorsQueue = [] const rootNode = getRootNode() @@ -185,7 +187,13 @@ class Root extends PureComponent<{}, State> { if (typeof error === 'object') { dispatch(notify(error)) } else { - dispatch(errorThrown({status: 0, auth: null}, error, 'warning')) + dispatch( + errorThrown( + {status: 0, auth: null}, + error, + ErrorsModels.AlertType.Warning + ) + ) } }) } diff --git a/ui/src/logs/components/LogViewerChart.tsx b/ui/src/logs/components/LogViewerChart.tsx index 02831a0265..f5c4823a0b 100644 --- a/ui/src/logs/components/LogViewerChart.tsx +++ b/ui/src/logs/components/LogViewerChart.tsx @@ -5,7 +5,7 @@ import {DEFAULT_LINE_COLORS} from 'src/shared/constants/graphColorPalettes' import {TimeRange} from 'src/types' interface Props { - onZoom: (lower: string, upper: string) => void + onZoom: (timeRange: TimeRange) => void timeRange: TimeRange data: object[] } diff --git a/ui/src/logs/containers/LogsPage.tsx b/ui/src/logs/containers/LogsPage.tsx index c1c6a8d41b..f672491663 100644 --- a/ui/src/logs/containers/LogsPage.tsx +++ b/ui/src/logs/containers/LogsPage.tsx @@ -262,9 +262,9 @@ class LogsPage extends PureComponent { this.props.setNamespaceAsync(namespace) } - private handleChartZoom = (lower, upper) => { - if (lower) { - this.props.changeZoomAsync({lower, upper}) + private handleChartZoom = (timeRange: TimeRange) => { + if (timeRange.lower) { + this.props.changeZoomAsync(timeRange) this.setState({liveUpdating: true}) } } diff --git a/ui/src/shared/actions/annotations.ts b/ui/src/shared/actions/annotations.ts index 47a8421ff1..83566f251e 100644 --- a/ui/src/shared/actions/annotations.ts +++ b/ui/src/shared/actions/annotations.ts @@ -1,122 +1,66 @@ import * as api from 'src/shared/apis/annotation' -import {AnnotationInterface} from 'src/types' +import {Dispatch} from 'redux' +import * as AnnotationsActions from 'src/types/actions/annotations' +import * as AnnotationsModels from 'src/types/annotations' -export type Action = - | EditingAnnotationAction - | DismissEditingAnnotationAction - | AddingAnnotationAction - | AddingAnnotationSuccessAction - | DismissAddingAnnotationAction - | MouseEnterTempAnnotationAction - | MouseLeaveTempAnnotationAction - | LoadAnnotationsAction - | UpdateAnnotationAction - | DeleteAnnotationAction - | AddAnnotationAction - -export interface EditingAnnotationAction { - type: 'EDITING_ANNOTATION' -} -export const editingAnnotation = (): EditingAnnotationAction => ({ +export const editingAnnotation = (): AnnotationsActions.EditingAnnotationAction => ({ type: 'EDITING_ANNOTATION', }) -export interface DismissEditingAnnotationAction { - type: 'DISMISS_EDITING_ANNOTATION' -} -export const dismissEditingAnnotation = (): DismissEditingAnnotationAction => ({ +export const dismissEditingAnnotation = (): AnnotationsActions.DismissEditingAnnotationAction => ({ type: 'DISMISS_EDITING_ANNOTATION', }) -export interface AddingAnnotationAction { - type: 'ADDING_ANNOTATION' -} -export const addingAnnotation = (): AddingAnnotationAction => ({ +export const addingAnnotation = (): AnnotationsActions.AddingAnnotationAction => ({ type: 'ADDING_ANNOTATION', }) -export interface AddingAnnotationSuccessAction { - type: 'ADDING_ANNOTATION_SUCCESS' -} -export const addingAnnotationSuccess = (): AddingAnnotationSuccessAction => ({ +export const addingAnnotationSuccess = (): AnnotationsActions.AddingAnnotationSuccessAction => ({ type: 'ADDING_ANNOTATION_SUCCESS', }) -export interface DismissAddingAnnotationAction { - type: 'DISMISS_ADDING_ANNOTATION' -} -export const dismissAddingAnnotation = (): DismissAddingAnnotationAction => ({ +export const dismissAddingAnnotation = (): AnnotationsActions.DismissAddingAnnotationAction => ({ type: 'DISMISS_ADDING_ANNOTATION', }) -export interface MouseEnterTempAnnotationAction { - type: 'MOUSEENTER_TEMP_ANNOTATION' -} -export const mouseEnterTempAnnotation = (): MouseEnterTempAnnotationAction => ({ +export const mouseEnterTempAnnotation = (): AnnotationsActions.MouseEnterTempAnnotationAction => ({ type: 'MOUSEENTER_TEMP_ANNOTATION', }) -export interface MouseLeaveTempAnnotationAction { - type: 'MOUSELEAVE_TEMP_ANNOTATION' -} -export const mouseLeaveTempAnnotation = (): MouseLeaveTempAnnotationAction => ({ +export const mouseLeaveTempAnnotation = (): AnnotationsActions.MouseLeaveTempAnnotationAction => ({ type: 'MOUSELEAVE_TEMP_ANNOTATION', }) -export interface LoadAnnotationsAction { - type: 'LOAD_ANNOTATIONS' - payload: { - annotations: AnnotationInterface[] - } -} export const loadAnnotations = ( - annotations: AnnotationInterface[] -): LoadAnnotationsAction => ({ + annotations: AnnotationsModels.AnnotationInterface[] +): AnnotationsActions.LoadAnnotationsAction => ({ type: 'LOAD_ANNOTATIONS', payload: { annotations, }, }) -export interface UpdateAnnotationAction { - type: 'UPDATE_ANNOTATION' - payload: { - annotation: AnnotationInterface - } -} export const updateAnnotation = ( - annotation: AnnotationInterface -): UpdateAnnotationAction => ({ + annotation: AnnotationsModels.AnnotationInterface +): AnnotationsActions.UpdateAnnotationAction => ({ type: 'UPDATE_ANNOTATION', payload: { annotation, }, }) -export interface DeleteAnnotationAction { - type: 'DELETE_ANNOTATION' - payload: { - annotation: AnnotationInterface - } -} export const deleteAnnotation = ( - annotation: AnnotationInterface -): DeleteAnnotationAction => ({ + annotation: AnnotationsModels.AnnotationInterface +): AnnotationsActions.DeleteAnnotationAction => ({ type: 'DELETE_ANNOTATION', payload: { annotation, }, }) -export interface AddAnnotationAction { - type: 'ADD_ANNOTATION' - payload: { - annotation: AnnotationInterface - } -} export const addAnnotation = ( - annotation: AnnotationInterface -): AddAnnotationAction => ({ + annotation: AnnotationsModels.AnnotationInterface +): AnnotationsActions.AddAnnotationAction => ({ type: 'ADD_ANNOTATION', payload: { annotation, @@ -125,7 +69,7 @@ export const addAnnotation = ( export const addAnnotationAsync = ( createUrl: string, - annotation: AnnotationInterface + annotation: AnnotationsModels.AnnotationInterface ) => async dispatch => { dispatch(addAnnotation(annotation)) const savedAnnotation = await api.createAnnotation(createUrl, annotation) @@ -133,28 +77,25 @@ export const addAnnotationAsync = ( dispatch(deleteAnnotation(annotation)) } -export interface AnnotationRange { - since: number - until: number -} - -export const getAnnotationsAsync = ( +export const getAnnotationsAsync: AnnotationsActions.GetAnnotationsDispatcher = ( indexUrl: string, - {since, until}: AnnotationRange -) => async dispatch => { + {since, until}: AnnotationsModels.AnnotationRange +): AnnotationsActions.GetAnnotationsThunk => async ( + dispatch: Dispatch +): Promise => { const annotations = await api.getAnnotations(indexUrl, since, until) dispatch(loadAnnotations(annotations)) } export const deleteAnnotationAsync = ( - annotation: AnnotationInterface + annotation: AnnotationsModels.AnnotationInterface ) => async dispatch => { await api.deleteAnnotation(annotation) dispatch(deleteAnnotation(annotation)) } export const updateAnnotationAsync = ( - annotation: AnnotationInterface + annotation: AnnotationsModels.AnnotationInterface ) => async dispatch => { await api.updateAnnotation(annotation) dispatch(updateAnnotation(annotation)) diff --git a/ui/src/shared/actions/app.js b/ui/src/shared/actions/app.js deleted file mode 100644 index df95c736dc..0000000000 --- a/ui/src/shared/actions/app.js +++ /dev/null @@ -1,34 +0,0 @@ -import {PRESENTATION_MODE_ANIMATION_DELAY} from '../constants' - -// ephemeral state action creators -export const enablePresentationMode = () => ({ - type: 'ENABLE_PRESENTATION_MODE', -}) - -export const disablePresentationMode = () => ({ - type: 'DISABLE_PRESENTATION_MODE', -}) - -export const delayEnablePresentationMode = () => dispatch => { - setTimeout( - () => dispatch(enablePresentationMode()), - PRESENTATION_MODE_ANIMATION_DELAY - ) -} - -// persistent state action creators -export const setAutoRefresh = milliseconds => ({ - type: 'SET_AUTOREFRESH', - payload: { - milliseconds, - }, -}) - -export const templateControlBarVisibilityToggled = () => ({ - type: 'TEMPLATE_CONTROL_BAR_VISIBILITY_TOGGLED', -}) - -export const noop = () => ({ - type: 'NOOP', - payload: {}, -}) diff --git a/ui/src/shared/actions/app.ts b/ui/src/shared/actions/app.ts new file mode 100644 index 0000000000..3619856b5e --- /dev/null +++ b/ui/src/shared/actions/app.ts @@ -0,0 +1,46 @@ +import {PRESENTATION_MODE_ANIMATION_DELAY} from '../constants' + +import {notify} from 'src/shared/actions/notifications' +import {notifyPresentationMode} from 'src/shared/copy/notifications' + +import {Dispatch} from 'redux' + +import * as AppActions from 'src/types/actions/app' + +// ephemeral state action creators + +export const enablePresentationMode = (): AppActions.EnablePresentationModeAction => ({ + type: 'ENABLE_PRESENTATION_MODE', +}) + +export const disablePresentationMode = (): AppActions.DisablePresentationModeAction => ({ + type: 'DISABLE_PRESENTATION_MODE', +}) + +export const delayEnablePresentationMode: AppActions.DelayEnablePresentationModeDispatcher = () => async ( + dispatch: Dispatch +): Promise => + setTimeout(() => { + dispatch(enablePresentationMode()) + notify(notifyPresentationMode()) + }, PRESENTATION_MODE_ANIMATION_DELAY) + +// persistent state action creators + +export const setAutoRefresh: AppActions.SetAutoRefreshActionCreator = ( + milliseconds: number +): AppActions.SetAutoRefreshAction => ({ + type: 'SET_AUTOREFRESH', + payload: { + milliseconds, + }, +}) + +export const templateControlBarVisibilityToggled = (): AppActions.TemplateControlBarVisibilityToggledAction => ({ + type: 'TEMPLATE_CONTROL_BAR_VISIBILITY_TOGGLED', +}) + +export const noop = (): AppActions.NoopAction => ({ + type: 'NOOP', + payload: {}, +}) diff --git a/ui/src/shared/actions/errors.js b/ui/src/shared/actions/errors.js deleted file mode 100644 index 7e19a45377..0000000000 --- a/ui/src/shared/actions/errors.js +++ /dev/null @@ -1,6 +0,0 @@ -export const errorThrown = (error, altText, alertType) => ({ - type: 'ERROR_THROWN', - error, - altText, - alertType, -}) diff --git a/ui/src/shared/actions/errors.ts b/ui/src/shared/actions/errors.ts new file mode 100644 index 0000000000..00ce9524e1 --- /dev/null +++ b/ui/src/shared/actions/errors.ts @@ -0,0 +1,13 @@ +import * as ErrorsActions from 'src/types/actions/errors' +import * as ErrorsModels from 'src/types/errors' + +export const errorThrown = ( + error: ErrorsModels.ErrorDescription, + altText?: string, + alertType?: ErrorsModels.AlertType +): ErrorsActions.ErrorThrownAction => ({ + type: 'ERROR_THROWN', + error, + altText, + alertType, +}) diff --git a/ui/src/shared/actions/notifications.ts b/ui/src/shared/actions/notifications.ts index 9c8958f85a..8df5946676 100644 --- a/ui/src/shared/actions/notifications.ts +++ b/ui/src/shared/actions/notifications.ts @@ -1,33 +1,15 @@ -import {Notification} from 'src/types' +import * as NotificationsActions from 'src/types/actions/notifications' +import * as NotificationsModels from 'src/types/notifications' -export type Action = ActionPublishNotification | ActionDismissNotification - -// Publish notification -export type PublishNotification = (n: Notification) => ActionPublishNotification -export interface ActionPublishNotification { - type: 'PUBLISH_NOTIFICATION' - payload: { - notification: Notification - } -} - -export const notify = ( - notification: Notification -): ActionPublishNotification => ({ +export const notify: NotificationsActions.PublishNotificationActionCreator = ( + notification: NotificationsModels.Notification +): NotificationsActions.PublishNotificationAction => ({ type: 'PUBLISH_NOTIFICATION', payload: {notification}, }) - -// Dismiss notification -export type DismissNotification = (id: string) => ActionDismissNotification -export interface ActionDismissNotification { - type: 'DISMISS_NOTIFICATION' - payload: { - id: string - } -} - -export const dismissNotification = (id: string): ActionDismissNotification => ({ +export const dismissNotification = ( + id: string +): NotificationsActions.DismissNotificationAction => ({ type: 'DISMISS_NOTIFICATION', payload: {id}, }) diff --git a/ui/src/shared/actions/overlayTechnology.ts b/ui/src/shared/actions/overlayTechnology.ts index ec19ed4424..400dd7f9b1 100644 --- a/ui/src/shared/actions/overlayTechnology.ts +++ b/ui/src/shared/actions/overlayTechnology.ts @@ -8,12 +8,12 @@ interface Options { transitionTime?: number } -export type ShowOverlay = ( +export type ShowOverlayActionCreator = ( OverlayNode: OverlayNodeType, options: Options -) => ActionOverlayNode +) => ShowOverlayAction -export interface ActionOverlayNode { +interface ShowOverlayAction { type: 'SHOW_OVERLAY' payload: { OverlayNode @@ -24,7 +24,7 @@ export interface ActionOverlayNode { export const showOverlay = ( OverlayNode: OverlayNodeType, options: Options -) => ({ +): ShowOverlayAction => ({ type: 'SHOW_OVERLAY', payload: {OverlayNode, options}, }) diff --git a/ui/src/shared/apis/databases.ts b/ui/src/shared/apis/databases.ts index 3bcf8dd2a6..68e6bd163e 100644 --- a/ui/src/shared/apis/databases.ts +++ b/ui/src/shared/apis/databases.ts @@ -4,7 +4,7 @@ import {showDatabases, showRetentionPolicies} from 'src/shared/apis/metaQuery' import showDatabasesParser from 'src/shared/parsing/showDatabases' import showRetentionPoliciesParser from 'src/shared/parsing/showRetentionPolicies' -import {Namespace} from 'src/types/query' +import {Namespace} from 'src/types/queries' export const getDatabasesWithRetentionPolicies = async ( proxy: string diff --git a/ui/src/shared/components/Annotations.tsx b/ui/src/shared/components/Annotations.tsx index b68c96e762..8284e5e4a5 100644 --- a/ui/src/shared/components/Annotations.tsx +++ b/ui/src/shared/components/Annotations.tsx @@ -18,7 +18,7 @@ import {visibleAnnotations} from 'src/shared/annotations/helpers' import {ErrorHandling} from 'src/shared/decorators/errors' import {AnnotationInterface, DygraphClass, Source} from 'src/types' -import {UpdateAnnotationAction} from 'src/shared/actions/annotations' +import {UpdateAnnotationAction} from 'src/types/actions/annotations' interface Props { dWidth: number diff --git a/ui/src/shared/components/AutoRefresh.tsx b/ui/src/shared/components/AutoRefresh.tsx index beccf8c2a3..0f639bc4f7 100644 --- a/ui/src/shared/components/AutoRefresh.tsx +++ b/ui/src/shared/components/AutoRefresh.tsx @@ -56,7 +56,7 @@ const AutoRefresh = ( inView: true, } - private intervalID: NodeJS.Timer | null + private intervalID: number constructor(props: Props) { super(props) @@ -199,7 +199,7 @@ const AutoRefresh = ( this.executeQueries() if (autoRefresh) { - this.intervalID = setInterval(this.executeQueries, autoRefresh) + this.intervalID = window.setInterval(this.executeQueries, autoRefresh) } } diff --git a/ui/src/shared/components/CustomTimeIndicator.tsx b/ui/src/shared/components/CustomTimeIndicator.tsx index 34d1d942d6..2a84039431 100644 --- a/ui/src/shared/components/CustomTimeIndicator.tsx +++ b/ui/src/shared/components/CustomTimeIndicator.tsx @@ -2,7 +2,7 @@ import React, {SFC} from 'react' import _ from 'lodash' import {TEMP_VAR_DASHBOARD_TIME} from 'src/shared/constants' -import {QueryConfig} from 'src/types/query' +import {QueryConfig} from 'src/types/queries' interface Query { config: QueryConfig diff --git a/ui/src/shared/components/DatabaseList.tsx b/ui/src/shared/components/DatabaseList.tsx index 8b5d1128de..824eaec0ec 100644 --- a/ui/src/shared/components/DatabaseList.tsx +++ b/ui/src/shared/components/DatabaseList.tsx @@ -4,7 +4,7 @@ import PropTypes from 'prop-types' import _ from 'lodash' import {QueryConfig, Source} from 'src/types' -import {Namespace} from 'src/types/query' +import {Namespace} from 'src/types/queries' import DatabaseListItem from 'src/shared/components/DatabaseListItem' import FancyScrollbar from 'src/shared/components/FancyScrollbar' diff --git a/ui/src/shared/components/DatabaseListItem.tsx b/ui/src/shared/components/DatabaseListItem.tsx index 22db6de542..2cce0fd7e0 100644 --- a/ui/src/shared/components/DatabaseListItem.tsx +++ b/ui/src/shared/components/DatabaseListItem.tsx @@ -2,7 +2,7 @@ import React, {SFC} from 'react' import classnames from 'classnames' -import {Namespace} from 'src/types/query' +import {Namespace} from 'src/types/queries' export interface DatabaseListItemProps { isActive: boolean diff --git a/ui/src/shared/components/Dygraph.tsx b/ui/src/shared/components/Dygraph.tsx index 271d3cd687..6e0f01bd13 100644 --- a/ui/src/shared/components/Dygraph.tsx +++ b/ui/src/shared/components/Dygraph.tsx @@ -62,7 +62,7 @@ interface Props { isBarGraph?: boolean staticLegend?: boolean setResolution?: (w: number) => void - onZoom?: (u: number | string, l: number | string) => void + onZoom?: (timeRange: TimeRange) => void mode?: string } @@ -354,10 +354,13 @@ class Dygraph extends Component { const {onZoom} = this.props if (this.dygraph.isZoomed() === false) { - return onZoom(null, null) + return onZoom({lower: null, upper: null}) } - onZoom(this.formatTimeRange(lower), this.formatTimeRange(upper)) + onZoom({ + lower: this.formatTimeRange(lower), + upper: this.formatTimeRange(upper), + }) } private handleDraw = () => { diff --git a/ui/src/shared/components/LayoutCellMenu.tsx b/ui/src/shared/components/LayoutCellMenu.tsx index 8253ad04e5..8f6535cddc 100644 --- a/ui/src/shared/components/LayoutCellMenu.tsx +++ b/ui/src/shared/components/LayoutCellMenu.tsx @@ -11,8 +11,8 @@ import CustomTimeIndicator from 'src/shared/components/CustomTimeIndicator' import Authorized, {EDITOR_ROLE} from 'src/auth/Authorized' import {EDITING} from 'src/shared/annotations/helpers' import {cellSupportsAnnotations} from 'src/shared/constants/index' -import {Cell} from 'src/types/dashboard' -import {QueryConfig} from 'src/types/query' +import {Cell} from 'src/types/dashboards' +import {QueryConfig} from 'src/types/queries' import { addingAnnotation, diff --git a/ui/src/shared/components/ManualRefresh.js b/ui/src/shared/components/ManualRefresh.js deleted file mode 100644 index d3edcd1016..0000000000 --- a/ui/src/shared/components/ManualRefresh.js +++ /dev/null @@ -1,29 +0,0 @@ -import React, {Component} from 'react' - -const ManualRefresh = WrappedComponent => - class extends Component { - constructor(props) { - super(props) - this.state = { - manualRefresh: Date.now(), - } - } - - handleManualRefresh = () => { - this.setState({ - manualRefresh: Date.now(), - }) - } - - render() { - return ( - - ) - } - } - -export default ManualRefresh diff --git a/ui/src/shared/components/ManualRefresh.tsx b/ui/src/shared/components/ManualRefresh.tsx new file mode 100644 index 0000000000..9cc83b9918 --- /dev/null +++ b/ui/src/shared/components/ManualRefresh.tsx @@ -0,0 +1,41 @@ +import React, {Component, ComponentClass} from 'react' + +export interface ManualRefreshProps { + manualRefresh: number + onManualRefresh: () => void +} + +interface ManualRefreshState { + manualRefresh: number +} + +function ManualRefresh

( + WrappedComponent: ComponentClass

+): ComponentClass

{ + return class extends Component

{ + public constructor(props: P & ManualRefreshProps) { + super(props) + this.state = { + manualRefresh: Date.now(), + } + } + + public render() { + return ( + + ) + } + + private handleManualRefresh = (): void => { + this.setState({ + manualRefresh: Date.now(), + }) + } + } +} + +export default ManualRefresh diff --git a/ui/src/shared/components/QueryTabList.tsx b/ui/src/shared/components/QueryTabList.tsx index 1e3ee9cae8..fe5594e9b6 100644 --- a/ui/src/shared/components/QueryTabList.tsx +++ b/ui/src/shared/components/QueryTabList.tsx @@ -1,7 +1,7 @@ import React, {PureComponent} from 'react' import QueryMakerTab from 'src/data_explorer/components/QueryMakerTab' import buildInfluxQLQuery from 'src/utils/influxql' -import {QueryConfig, TimeRange} from 'src/types/query' +import {QueryConfig, TimeRange} from 'src/types/queries' interface Props { queries: QueryConfig[] diff --git a/ui/src/shared/components/SingleStat.tsx b/ui/src/shared/components/SingleStat.tsx index 1b89456539..cb64f54005 100644 --- a/ui/src/shared/components/SingleStat.tsx +++ b/ui/src/shared/components/SingleStat.tsx @@ -7,7 +7,7 @@ import {SMALL_CELL_HEIGHT} from 'src/shared/graphs/helpers' import {DYGRAPH_CONTAINER_V_MARGIN} from 'src/shared/constants' import {generateThresholdsListHexs} from 'src/shared/constants/colorOperations' import {ColorNumber} from 'src/types/colors' -import {CellType} from 'src/types/dashboard' +import {CellType} from 'src/types/dashboards' import {Data} from 'src/types/dygraphs' import {ErrorHandling} from 'src/shared/decorators/errors' diff --git a/ui/src/shared/components/TableGraph.tsx b/ui/src/shared/components/TableGraph.tsx index 4b2a2c48c6..6d2af48bcd 100644 --- a/ui/src/shared/components/TableGraph.tsx +++ b/ui/src/shared/components/TableGraph.tsx @@ -36,7 +36,7 @@ import { FieldOption, DecimalPlaces, Sort, -} from 'src/types/dashboard' +} from 'src/types/dashboards' interface Label { label: string diff --git a/ui/src/shared/components/WidgetCell.tsx b/ui/src/shared/components/WidgetCell.tsx index 259dbdfa24..fc14c4166e 100644 --- a/ui/src/shared/components/WidgetCell.tsx +++ b/ui/src/shared/components/WidgetCell.tsx @@ -4,9 +4,9 @@ import AlertsApp from 'src/alerts/containers/AlertsApp' import NewsFeed from 'src/status/components/NewsFeed' import GettingStarted from 'src/status/components/GettingStarted' -import {Cell} from 'src/types/dashboard' +import {Cell} from 'src/types/dashboards' import {Source} from 'src/types/sources' -import {TimeRange} from 'src/types/query' +import {TimeRange} from 'src/types/queries' import {RECENT_ALERTS_LIMIT} from 'src/status/constants' interface Props { diff --git a/ui/src/shared/constants/colorOperations.ts b/ui/src/shared/constants/colorOperations.ts index 0c011709a4..6e7780c150 100644 --- a/ui/src/shared/constants/colorOperations.ts +++ b/ui/src/shared/constants/colorOperations.ts @@ -7,7 +7,7 @@ import { THRESHOLD_TYPE_TEXT, } from 'src/shared/constants/thresholds' -import {CellType} from 'src/types/dashboard' +import {CellType} from 'src/types/dashboards' const getLegibleTextColor = bgColorHex => { const darkText = '#292933' diff --git a/ui/src/shared/constants/index.tsx b/ui/src/shared/constants/index.tsx index 216ed85f15..10f1931b91 100644 --- a/ui/src/shared/constants/index.tsx +++ b/ui/src/shared/constants/index.tsx @@ -1,7 +1,7 @@ import _ from 'lodash' import {TemplateValueType, TemplateType} from 'src/types' -import {CellType} from 'src/types/dashboard' +import {CellType} from 'src/types/dashboards' export const NO_CELL = 'none' diff --git a/ui/src/shared/data/timeRanges.ts b/ui/src/shared/data/timeRanges.ts index 341f156ef9..87c3945969 100644 --- a/ui/src/shared/data/timeRanges.ts +++ b/ui/src/shared/data/timeRanges.ts @@ -1,10 +1,4 @@ -import {TimeRange} from 'src/types/query' -interface TimeRangeOption extends TimeRange { - defaultGroupBy: string - seconds: number - inputValue: string - menuOption: string -} +import {TimeRangeOption} from 'src/types/queries' const nowMinus30d = 'now() - 30d' diff --git a/ui/src/shared/dispatchers/index.js b/ui/src/shared/dispatchers/index.js deleted file mode 100644 index 2ff6c7741d..0000000000 --- a/ui/src/shared/dispatchers/index.js +++ /dev/null @@ -1,8 +0,0 @@ -import {notify} from 'shared/actions/notifications' -import {delayEnablePresentationMode} from 'shared/actions/app' -import {notifyPresentationMode} from 'shared/copy/notifications' - -export const presentationButtonDispatcher = dispatch => () => { - dispatch(delayEnablePresentationMode()) - dispatch(notify(notifyPresentationMode())) -} diff --git a/ui/src/shared/reducers/annotations.ts b/ui/src/shared/reducers/annotations.ts index f1c3ebb657..b8c0b29b23 100644 --- a/ui/src/shared/reducers/annotations.ts +++ b/ui/src/shared/reducers/annotations.ts @@ -1,6 +1,6 @@ import {ADDING, EDITING, TEMP_ANNOTATION} from 'src/shared/annotations/helpers' -import {Action} from 'src/shared/actions/annotations' +import {Action} from 'src/types/actions/annotations' import {AnnotationInterface} from 'src/types' export interface AnnotationState { diff --git a/ui/src/shared/reducers/notifications.ts b/ui/src/shared/reducers/notifications.ts index cb9f6fd92f..8c9d938d40 100644 --- a/ui/src/shared/reducers/notifications.ts +++ b/ui/src/shared/reducers/notifications.ts @@ -1,5 +1,5 @@ import uuid from 'uuid' -import {Action} from 'src/shared/actions/notifications' +import {Action} from 'src/types/actions/notifications' import {Notification} from 'src/types' export const initialState: Notification[] = [] diff --git a/ui/src/sources/containers/SourcePage.tsx b/ui/src/sources/containers/SourcePage.tsx index 602dbd80c7..e76c1fd5d3 100644 --- a/ui/src/sources/containers/SourcePage.tsx +++ b/ui/src/sources/containers/SourcePage.tsx @@ -9,10 +9,7 @@ import { AddSource, UpdateSource, } from 'src/shared/actions/sources' -import { - notify as notifyAction, - PublishNotification, -} from 'src/shared/actions/notifications' +import {notify as notifyAction} from 'src/shared/actions/notifications' import {connect} from 'react-redux' import Notifications from 'src/shared/components/Notifications' @@ -20,7 +17,6 @@ import SourceForm from 'src/sources/components/SourceForm' import FancyScrollbar from 'src/shared/components/FancyScrollbar' import PageHeader from 'src/shared/components/PageHeader' import {DEFAULT_SOURCE} from 'src/shared/constants' -import {Source} from 'src/types' const INITIAL_PATH = '/sources/new' @@ -33,8 +29,11 @@ import { } from 'src/shared/copy/notifications' import {ErrorHandling} from 'src/shared/decorators/errors' +import * as SourcesModels from 'src/types/sources' +import * as NotificationsActions from 'src/types/actions/notifications' + interface Props extends WithRouterProps { - notify: PublishNotification + notify: NotificationsActions.PublishNotificationActionCreator addSource: AddSource updateSource: UpdateSource } @@ -42,7 +41,7 @@ interface Props extends WithRouterProps { interface State { isCreated: boolean isLoading: boolean - source: Partial + source: Partial editMode: boolean isInitialSource: boolean } diff --git a/ui/src/status/fixtures.ts b/ui/src/status/fixtures.ts index 95c44b5aa6..116b07d2c2 100644 --- a/ui/src/status/fixtures.ts +++ b/ui/src/status/fixtures.ts @@ -3,7 +3,7 @@ import {TEMP_VAR_DASHBOARD_TIME} from 'src/shared/constants' import {NEW_DEFAULT_DASHBOARD_CELL} from 'src/dashboards/constants/index' import {DEFAULT_AXIS} from 'src/dashboards/constants/cellEditor' import {Cell, CellQuery, Axes} from 'src/types' -import {CellType} from 'src/types/dashboard' +import {CellType} from 'src/types/dashboards' const emptyQuery: CellQuery = { query: '', diff --git a/ui/src/tempVars/components/TemplateControlBar.tsx b/ui/src/tempVars/components/TemplateControlBar.tsx index 64a3388894..ffa068ac3d 100644 --- a/ui/src/tempVars/components/TemplateControlBar.tsx +++ b/ui/src/tempVars/components/TemplateControlBar.tsx @@ -16,7 +16,6 @@ interface Props { source: Source onSelectTemplate: (id: string) => void onSaveTemplates: (templates: Template[]) => void - onCreateTemplateVariable: () => void } interface State { diff --git a/ui/src/tempVars/constants/index.ts b/ui/src/tempVars/constants/index.ts index d5fa36e058..4f3e469105 100644 --- a/ui/src/tempVars/constants/index.ts +++ b/ui/src/tempVars/constants/index.ts @@ -1,6 +1,6 @@ import uuid from 'uuid' -import {TimeRange} from 'src/types/query' +import {TimeRange} from 'src/types/queries' import {TEMP_VAR_DASHBOARD_TIME} from 'src/shared/constants' import {Template, TemplateType, TemplateValueType} from 'src/types' diff --git a/ui/src/types/actions/annotations.ts b/ui/src/types/actions/annotations.ts new file mode 100644 index 0000000000..12f99f0546 --- /dev/null +++ b/ui/src/types/actions/annotations.ts @@ -0,0 +1,82 @@ +import {Dispatch} from 'redux' +import * as AnnotationData from 'src/types/annotations' + +export type Action = + | EditingAnnotationAction + | DismissEditingAnnotationAction + | AddingAnnotationAction + | AddingAnnotationSuccessAction + | DismissAddingAnnotationAction + | MouseEnterTempAnnotationAction + | MouseLeaveTempAnnotationAction + | LoadAnnotationsAction + | UpdateAnnotationAction + | DeleteAnnotationAction + | AddAnnotationAction + +export interface EditingAnnotationAction { + type: 'EDITING_ANNOTATION' +} + +export type DismissEditingAnnotationActionCreator = () => DismissEditingAnnotationAction + +export interface DismissEditingAnnotationAction { + type: 'DISMISS_EDITING_ANNOTATION' +} + +export interface AddingAnnotationAction { + type: 'ADDING_ANNOTATION' +} + +export interface AddingAnnotationSuccessAction { + type: 'ADDING_ANNOTATION_SUCCESS' +} + +export interface DismissAddingAnnotationAction { + type: 'DISMISS_ADDING_ANNOTATION' +} + +export interface MouseEnterTempAnnotationAction { + type: 'MOUSEENTER_TEMP_ANNOTATION' +} + +export interface MouseLeaveTempAnnotationAction { + type: 'MOUSELEAVE_TEMP_ANNOTATION' +} + +export interface LoadAnnotationsAction { + type: 'LOAD_ANNOTATIONS' + payload: { + annotations: AnnotationData.AnnotationInterface[] + } +} + +export interface UpdateAnnotationAction { + type: 'UPDATE_ANNOTATION' + payload: { + annotation: AnnotationData.AnnotationInterface + } +} + +export interface DeleteAnnotationAction { + type: 'DELETE_ANNOTATION' + payload: { + annotation: AnnotationData.AnnotationInterface + } +} + +export interface AddAnnotationAction { + type: 'ADD_ANNOTATION' + payload: { + annotation: AnnotationData.AnnotationInterface + } +} + +export type GetAnnotationsDispatcher = ( + indexUrl: string, + annotationRange: AnnotationData.AnnotationRange +) => GetAnnotationsThunk + +export type GetAnnotationsThunk = ( + dispatch: Dispatch +) => Promise diff --git a/ui/src/types/actions/app.ts b/ui/src/types/actions/app.ts new file mode 100644 index 0000000000..f1f8837a5d --- /dev/null +++ b/ui/src/types/actions/app.ts @@ -0,0 +1,39 @@ +import {Dispatch} from 'redux' + +export type EnablePresentationModeActionCreator = () => EnablePresentationModeAction + +export interface EnablePresentationModeAction { + type: 'ENABLE_PRESENTATION_MODE' +} + +export interface DisablePresentationModeAction { + type: 'DISABLE_PRESENTATION_MODE' +} + +export type DelayEnablePresentationModeDispatcher = () => DelayEnablePresentationModeThunk + +export type DelayEnablePresentationModeThunk = ( + dispatch: Dispatch +) => Promise + +export type SetAutoRefreshActionCreator = ( + milliseconds: number +) => SetAutoRefreshAction + +export interface SetAutoRefreshAction { + type: 'SET_AUTOREFRESH' + payload: { + milliseconds: number + } +} + +export type TemplateControlBarVisibilityToggledActionCreator = () => TemplateControlBarVisibilityToggledAction + +export interface TemplateControlBarVisibilityToggledAction { + type: 'TEMPLATE_CONTROL_BAR_VISIBILITY_TOGGLED' +} + +export interface NoopAction { + type: 'NOOP' + payload: object +} diff --git a/ui/src/types/actions/cellEditorOverlay.ts b/ui/src/types/actions/cellEditorOverlay.ts new file mode 100644 index 0000000000..779e454977 --- /dev/null +++ b/ui/src/types/actions/cellEditorOverlay.ts @@ -0,0 +1,111 @@ +import * as ColorsModels from 'src/types/colors' +import * as DashboardsModels from 'src/types/dashboards' + +export type Action = + | ShowCellEditorOverlayAction + | HideCellEditorOverlayAction + | ChangeCellTypeAction + | RenameCellAction + | UpdateThresholdsListColorsAction + | UpdateThresholdsListTypeAction + | UpdateGaugeColorsAction + | UpdateAxesAction + | UpdateTableOptionsAction + | UpdateLineColorsAction + | ChangeTimeFormatAction + | ChangeDecimalPlacesAction + | UpdateFieldOptionsAction + +export type ShowCellEditorOverlayActionCreator = ( + cell: DashboardsModels.Cell +) => ShowCellEditorOverlayAction + +export interface ShowCellEditorOverlayAction { + type: 'SHOW_CELL_EDITOR_OVERLAY' + payload: { + cell: DashboardsModels.Cell + } +} + +export type HideCellEditorOverlayActionCreator = () => HideCellEditorOverlayAction + +export interface HideCellEditorOverlayAction { + type: 'HIDE_CELL_EDITOR_OVERLAY' +} + +export interface ChangeCellTypeAction { + type: 'CHANGE_CELL_TYPE' + payload: { + cellType: DashboardsModels.CellType + } +} + +export interface RenameCellAction { + type: 'RENAME_CELL' + payload: { + cellName: string + } +} + +export interface UpdateThresholdsListColorsAction { + type: 'UPDATE_THRESHOLDS_LIST_COLORS' + payload: { + thresholdsListColors: ColorsModels.ColorNumber[] + } +} + +export interface UpdateThresholdsListTypeAction { + type: 'UPDATE_THRESHOLDS_LIST_TYPE' + payload: { + thresholdsListType: DashboardsModels.ThresholdType + } +} + +export interface UpdateGaugeColorsAction { + type: 'UPDATE_GAUGE_COLORS' + payload: { + gaugeColors: ColorsModels.ColorNumber[] + } +} + +export interface UpdateAxesAction { + type: 'UPDATE_AXES' + payload: { + axes: DashboardsModels.Axes + } +} + +export interface UpdateTableOptionsAction { + type: 'UPDATE_TABLE_OPTIONS' + payload: { + tableOptions: DashboardsModels.TableOptions + } +} + +export interface UpdateLineColorsAction { + type: 'UPDATE_LINE_COLORS' + payload: { + lineColors: ColorsModels.ColorString[] + } +} + +export interface ChangeTimeFormatAction { + type: 'CHANGE_TIME_FORMAT' + payload: { + timeFormat: string + } +} + +export interface ChangeDecimalPlacesAction { + type: 'CHANGE_DECIMAL_PLACES' + payload: { + decimalPlaces: DashboardsModels.DecimalPlaces + } +} + +export interface UpdateFieldOptionsAction { + type: 'UPDATE_FIELD_OPTIONS' + payload: { + fieldOptions: DashboardsModels.FieldOption[] + } +} diff --git a/ui/src/types/actions/dashboards.ts b/ui/src/types/actions/dashboards.ts new file mode 100644 index 0000000000..d9168ac72e --- /dev/null +++ b/ui/src/types/actions/dashboards.ts @@ -0,0 +1,397 @@ +import {Dispatch} from 'redux' +import {InjectedRouter} from 'react-router' +import {LocationAction} from 'react-router-redux' +import {Source} from 'src/types' +import {Location} from 'history' +import * as DashboardsModels from 'src/types/dashboards' +import * as DashboardsReducers from 'src/types/reducers/dashboards' +import * as ErrorsActions from 'src/types/actions/errors' +import * as QueriesModels from 'src/types/queries' +import * as TempVarsModels from 'src/types/tempVars' +import * as NotificationsActions from 'src/types/actions/notifications' + + +export type LoadDashboardsActionCreator = ( + dashboards: DashboardsModels.Dashboard[], + dashboardID?: number +) => LoadDashboardsAction + +export interface LoadDashboardsAction { + type: 'LOAD_DASHBOARDS' + payload: { + dashboards: DashboardsModels.Dashboard[] + dashboardID: number + } +} + +export type LoadDashboardActionCreator = ( + dashboard: DashboardsModels.Dashboard +) => LoadDashboardAction + +export interface LoadDashboardAction { + type: 'LOAD_DASHBOARD' + payload: { + dashboard: DashboardsModels.Dashboard + } +} + +export interface SetDashTimeV1Action { + type: 'SET_DASHBOARD_TIME_V1' + payload: { + dashboardID: number + timeRange: QueriesModels.TimeRange + } +} + +export type SetDashTimeV1ActionCreator = ( + dashboardID: number, + timeRange: QueriesModels.TimeRange +) => SetDashTimeV1Action + +export interface RetainRangesDashTimeV1Action { + type: 'RETAIN_RANGES_DASHBOARD_TIME_V1' + payload: { + dashboardIDs: string[] + } +} + +export type RetainRangesDashTimeV1ActionCreator = ( + dashboardIDs: string[] +) => RetainRangesDashTimeV1Action + +export type SetTimeRangeActionCreator = ( + timeRange: QueriesModels.TimeRange +) => SetTimeRangeAction + +export interface SetTimeRangeAction { + type: 'SET_DASHBOARD_TIME_RANGE' + payload: { + timeRange: QueriesModels.TimeRange + } +} + +export type SetZoomedTimeRangeDispatcher = ( + zoomedTimeRange: QueriesModels.TimeRange, + location: Location +) => SetZoomedTimeRangeThunk + +export type SetZoomedTimeRangeThunk = ( + dispatch: Dispatch< + | SetZoomedTimeRangeActionCreator + | SyncURLQueryFromQueryParamsObjectDispatcher + > +) => Promise + +export type SetZoomedTimeRangeActionCreator = ( + zoomedTimeRange: QueriesModels.TimeRange +) => SetZoomedTimeRangeAction + +export interface SetZoomedTimeRangeAction { + type: 'SET_DASHBOARD_ZOOMED_TIME_RANGE' + payload: { + zoomedTimeRange: QueriesModels.TimeRange + } +} + +export interface UpdateDashboardAction { + type: 'UPDATE_DASHBOARD' + payload: { + dashboard: DashboardsModels.Dashboard + } +} + +export type UpdateDashboardActionCreator = ( + dashboard: DashboardsModels.Dashboard +) => UpdateDashboardAction + +export type CreateDashboardActionCreator = ( + dashboard: DashboardsModels.Dashboard +) => CreateDashboardAction + +export interface CreateDashboardAction { + type: 'CREATE_DASHBOARD' + payload: { + dashboard: DashboardsModels.Dashboard + } +} + +export type DeleteDashboardActionCreator = ( + dashboard: DashboardsModels.Dashboard +) => DeleteDashboardAction + +export interface DeleteDashboardAction { + type: 'DELETE_DASHBOARD' + payload: { + dashboard: DashboardsModels.Dashboard + } +} + +export type DeleteDashboardFailedActionCreator = ( + dashboard: DashboardsModels.Dashboard +) => DeleteDashboardFailedAction + +export interface DeleteDashboardFailedAction { + type: 'DELETE_DASHBOARD_FAILED' + payload: { + dashboard: DashboardsModels.Dashboard + } +} + +export type SyncDashboardCellActionCreator = ( + dashboard: DashboardsModels.Dashboard, + cell: DashboardsModels.Cell +) => SyncDashboardCellAction + +export interface SyncDashboardCellAction { + type: 'SYNC_DASHBOARD_CELL' + payload: { + dashboard: DashboardsModels.Dashboard + cell: DashboardsModels.Cell + } +} + +export type AddDashboardCellDispatcher = ( + dashboard: DashboardsModels.Dashboard, + cellType?: DashboardsModels.CellType +) => AddDashboardCellThunk + +export type AddDashboardCellThunk = ( + dispatch: Dispatch< + | AddDashboardCellAction + | NotificationsActions.PublishNotificationActionCreator + | ErrorsActions.ErrorThrownActionCreator + > +) => Promise + +export type AddDashboardCellActionCreator = ( + dashboard: DashboardsModels.Dashboard, + cell: DashboardsModels.Cell +) => AddDashboardCellAction + +export interface AddDashboardCellAction { + type: 'ADD_DASHBOARD_CELL' + payload: { + dashboard: DashboardsModels.Dashboard + cell: DashboardsModels.Cell + } +} + +export type CloneDashboardCellDispatcher = ( + dashboard: DashboardsModels.Dashboard, + cell: DashboardsModels.Cell +) => CloneDashboardCellThunk + +export type CloneDashboardCellThunk = ( + dispatch: Dispatch< + | AddDashboardCellAction + | NotificationsActions.PublishNotificationActionCreator + | ErrorsActions.ErrorThrownActionCreator + > +) => Promise + +export type DeleteDashboardCellDispatcher = ( + dashboard: DashboardsModels.Dashboard, + cell: DashboardsModels.Cell +) => DeleteDashboardCellThunk + +export type DeleteDashboardCellThunk = ( + dispatch: Dispatch< + | DeleteDashboardCellActionCreator + | NotificationsActions.PublishNotificationActionCreator + | ErrorsActions.ErrorThrownActionCreator + > +) => Promise + +export type DeleteDashboardCellActionCreator = ( + dashboard: DashboardsModels.Dashboard, + cell: DashboardsModels.Cell +) => DeleteDashboardCellAction + +export interface DeleteDashboardCellAction { + type: 'DELETE_DASHBOARD_CELL' + payload: { + dashboard: DashboardsModels.Dashboard + cell: DashboardsModels.Cell + } +} + +export type EditCellQueryStatusActionCreator = ( + queryID: string, + status: string +) => EditCellQueryStatusAction + +export interface EditCellQueryStatusAction { + type: 'EDIT_CELL_QUERY_STATUS' + payload: { + queryID: string + status: string + } +} + +export type TemplateVariableSelectedActionCreator = ( + dashboardID: number, + templateID: string, + values: any[] +) => TemplateVariableSelectedAction + +export interface TemplateVariableSelectedAction { + type: 'TEMPLATE_VARIABLE_SELECTED' + payload: { + dashboardID: number + templateID: string + values: any[] + } +} + +export type TemplateVariablesSelectedByNameActionCreator = ( + dashboardID: number, + queryParams: TempVarsModels.URLQueryParams +) => TemplateVariablesSelectedByNameAction + +export interface TemplateVariablesSelectedByNameAction { + type: 'TEMPLATE_VARIABLES_SELECTED_BY_NAME' + payload: { + dashboardID: number + queryParams: TempVarsModels.URLQueryParams + } +} + +export type EditTemplateVariableValuesActionCreator = ( + dashboardID: number, + templateID: string, + values: any[] +) => EditTemplateVariableValuesAction + +export interface EditTemplateVariableValuesAction { + type: 'EDIT_TEMPLATE_VARIABLE_VALUES' + payload: { + dashboardID: number + templateID: string + values: any[] + } +} + +export type SetHoverTimeActionCreator = ( + hoverTime: string +) => SetHoverTimeAction + +export interface SetHoverTimeAction { + type: 'SET_HOVER_TIME' + payload: { + hoverTime: string + } +} + +export type SetActiveCellActionCreator = ( + activeCellID: string +) => SetActiveCellAction + +export interface SetActiveCellAction { + type: 'SET_ACTIVE_CELL' + payload: { + activeCellID: string + } +} + +export type GetDashboardsDispatcher = () => GetDashboardsThunk + +export type GetDashboardsThunk = ( + dispatch: Dispatch +) => Promise + +export type GetDashboardsNamesDispatcher = ( + sourceID: string +) => GetDashboardsNamesThunk + +export type GetDashboardsNamesThunk = ( + dispatch: Dispatch +) => Promise + +export type PutDashboardDispatcher = ( + dashboard: DashboardsModels.Dashboard +) => PutDashboardThunk + +export type PutDashboardThunk = ( + dispatch: Dispatch< + UpdateDashboardAction | ErrorsActions.ErrorThrownActionCreator + > +) => Promise + +export type PutDashboardByIDDispatcher = ( + dashboardID: number +) => PutDashboardByIDThunk + +export type PutDashboardByIDThunk = ( + dispatch: Dispatch, + getState: () => DashboardsReducers.Dashboards +) => Promise + +export type DeleteDashboardDispatcher = ( + dashboard: DashboardsModels.Dashboard +) => DeleteDashboardThunk + +export type DeleteDashboardThunk = ( + dispatch: Dispatch< + | DeleteDashboardActionCreator + | NotificationsActions.PublishNotificationActionCreator + | ErrorsActions.ErrorThrownActionCreator + | DeleteDashboardFailedActionCreator + > +) => Promise + +export type UpdateDashboardCellDispatcher = ( + dashboard: DashboardsModels.Dashboard, + cell: DashboardsModels.Cell +) => UpdateDashboardCellThunk + +export type UpdateDashboardCellThunk = ( + dispatch: Dispatch +) => Promise + +export type SyncURLQueryFromQueryParamsObjectDispatcher = ( + location: Location, + updatedURLQueryParams: TempVarsModels.URLQueryParams, + deletedURLQueryParams?: TempVarsModels.URLQueryParams +) => SyncURLQueryFromQueryParamsObjectActionCreator + +export type SyncURLQueryFromTempVarsDispatcher = ( + location: Location, + tempVars: TempVarsModels.Template[], + deletedTempVars: TempVarsModels.Template[], + urlQueryParamsTimeRanges?: TempVarsModels.URLQueryParams +) => SyncURLQueryFromQueryParamsObjectActionCreator + +export type SyncURLQueryFromQueryParamsObjectActionCreator = ( + dispatch: Dispatch +) => void + +export type SyncDashboardTempVarsFromURLQueryParamsDispatcher = ( + dispatch: Dispatch< + | NotificationsActions.PublishNotificationActionCreator + | TemplateVariableSelectedAction + >, + getState: () => DashboardsReducers.Dashboards & DashboardsReducers.Auth +) => void + +export type SyncDashboardTimeRangeFromURLQueryParamsDispatcher = ( + dispatch: Dispatch, + getState: () => DashboardsReducers.Dashboards & DashboardsReducers.DashTimeV1 +) => void + +export type SyncDashboardFromURLQueryParamsDispatcher = ( + dispatch: Dispatch< + | SyncDashboardTempVarsFromURLQueryParamsDispatcher + | SyncDashboardTimeRangeFromURLQueryParamsDispatcher + > +) => void + +export type GetDashboardWithHydratedAndSyncedTempVarsAsyncDispatcher = ( + dashboardID: number, + source: Source, + router: InjectedRouter, + location: Location +) => GetDashboardWithHydratedAndSyncedTempVarsAsyncThunk + +export type GetDashboardWithHydratedAndSyncedTempVarsAsyncThunk = ( + dispatch: Dispatch +) => Promise diff --git a/ui/src/types/actions/errors.ts b/ui/src/types/actions/errors.ts new file mode 100644 index 0000000000..715b229259 --- /dev/null +++ b/ui/src/types/actions/errors.ts @@ -0,0 +1,14 @@ +import * as ErrorData from 'src/types/errors' + +export type ErrorThrownActionCreator = ( + error: ErrorData.ErrorDescription, + altText?: string, + alertType?: ErrorData.AlertType +) => ErrorThrownAction + +export interface ErrorThrownAction { + type: 'ERROR_THROWN' + error: ErrorData.ErrorDescription + altText?: string + alertType?: ErrorData.AlertType +} diff --git a/ui/src/types/actions/notifications.ts b/ui/src/types/actions/notifications.ts new file mode 100644 index 0000000000..e43d25ad12 --- /dev/null +++ b/ui/src/types/actions/notifications.ts @@ -0,0 +1,23 @@ +import {Notification} from 'src/types' + +export type Action = PublishNotificationAction | DismissNotificationAction + +export type PublishNotificationActionCreator = ( + n: Notification +) => PublishNotificationAction + +export interface PublishNotificationAction { + type: 'PUBLISH_NOTIFICATION' + payload: { + notification: Notification + } +} + +export type DismissNotification = (id: string) => DismissNotificationAction + +export interface DismissNotificationAction { + type: 'DISMISS_NOTIFICATION' + payload: { + id: string + } +} diff --git a/ui/src/types/annotations.ts b/ui/src/types/annotations.ts index e35bb06285..595a641814 100644 --- a/ui/src/types/annotations.ts +++ b/ui/src/types/annotations.ts @@ -6,3 +6,8 @@ export interface AnnotationInterface { type: string links: {self: string} } + +export interface AnnotationRange { + since: number + until: number +} diff --git a/ui/src/types/apis/dashboards.ts b/ui/src/types/apis/dashboards.ts new file mode 100644 index 0000000000..af470c7dd9 --- /dev/null +++ b/ui/src/types/apis/dashboards.ts @@ -0,0 +1,5 @@ +import {Dashboard} from 'src/types/dashboards' + +export interface DashboardsResponse { + dashboards: Dashboard[] +} diff --git a/ui/src/types/dashboard.ts b/ui/src/types/dashboards.ts similarity index 100% rename from ui/src/types/dashboard.ts rename to ui/src/types/dashboards.ts diff --git a/ui/src/types/errors.ts b/ui/src/types/errors.ts new file mode 100644 index 0000000000..718355f3f8 --- /dev/null +++ b/ui/src/types/errors.ts @@ -0,0 +1,13 @@ +export interface ErrorDescription { + status: number + auth: { + links: { + me: string + } + } +} + +export enum AlertType { + Info = 'info', + Warning = 'warning', +} diff --git a/ui/src/types/index.ts b/ui/src/types/index.ts index 19b89d98b7..15fdda9ba8 100644 --- a/ui/src/types/index.ts +++ b/ui/src/types/index.ts @@ -1,7 +1,7 @@ import {LayoutCell, LayoutQuery} from './layouts' import {Service, NewService} from './services' import {AuthLinks, Organization, Role, User, Me} from './auth' -import {Cell, CellQuery, Legend, Axes, Dashboard, CellType} from './dashboard' +import {Cell, CellQuery, Legend, Axes, Dashboard, CellType} from './dashboards' import { Template, TemplateQuery, @@ -27,7 +27,7 @@ import { Tag, Tags, TagValues, -} from './query' +} from './queries' import {AlertRule, Kapacitor, Task, RuleValues} from './kapacitor' import {NewSource, Source, SourceLinks} from './sources' import {DropdownAction, DropdownItem, Constructable} from './shared' diff --git a/ui/src/types/query.ts b/ui/src/types/queries.ts similarity index 88% rename from ui/src/types/query.ts rename to ui/src/types/queries.ts index df3590cf55..ecc1bf8c46 100644 --- a/ui/src/types/query.ts +++ b/ui/src/types/queries.ts @@ -87,6 +87,7 @@ export interface TimeRange { lower: string upper?: string | null seconds?: number + format?: string } export interface DurationRange { @@ -99,3 +100,12 @@ export interface TimeShift { unit: string quantity: string } + +export interface TimeRangeOption extends TimeRange { + defaultGroupBy: string + seconds: number + inputValue: string + menuOption: string +} + +export type DashTimeV1Range = TimeRangeOption & {dashboardID: number} diff --git a/ui/src/types/reducers/auth.ts b/ui/src/types/reducers/auth.ts new file mode 100644 index 0000000000..5dd128de88 --- /dev/null +++ b/ui/src/types/reducers/auth.ts @@ -0,0 +1,8 @@ +import * as AuthModels from 'src/types/auth' + +export interface Auth { + auth: { + isUsingAuth: boolean + me: AuthModels.Me + } +} diff --git a/ui/src/types/reducers/dashboards.ts b/ui/src/types/reducers/dashboards.ts new file mode 100644 index 0000000000..6c67a5d6e4 --- /dev/null +++ b/ui/src/types/reducers/dashboards.ts @@ -0,0 +1,15 @@ +import {Dashboard} from 'src/types' +import {Me} from 'src/types/auth' +import {DashTimeV1Range} from 'src/types/queries' + +export interface Dashboards { + dashboardUI: {dashboards: Dashboard[]} +} + +export interface Auth { + auth: {isUsingAuth: boolean; me: Me} +} + +export interface DashTimeV1 { + dashTimeV1: {ranges: DashTimeV1Range[]} +} diff --git a/ui/src/types/sources.ts b/ui/src/types/sources.ts index 2ba7fb6c40..b3c90c59c0 100644 --- a/ui/src/types/sources.ts +++ b/ui/src/types/sources.ts @@ -37,3 +37,7 @@ export interface SourceLinks { health: string services: string } + +export interface SourceOption extends Source { + text: string +} diff --git a/ui/src/utils/ajax.ts b/ui/src/utils/ajax.ts index df98a7e0f4..37d178fcd8 100644 --- a/ui/src/utils/ajax.ts +++ b/ui/src/utils/ajax.ts @@ -72,7 +72,7 @@ function generateResponseWithLinks( } interface RequestParams { - url: string | string[] + url?: string | string[] resource?: string | null id?: string | null method?: string diff --git a/ui/test/dashboards/components/CellEditorOverlay.test.tsx b/ui/test/dashboards/components/CellEditorOverlay.test.tsx index 698042f49d..c8fd70ea1d 100644 --- a/ui/test/dashboards/components/CellEditorOverlay.test.tsx +++ b/ui/test/dashboards/components/CellEditorOverlay.test.tsx @@ -37,7 +37,7 @@ const setup = (override = {}) => { thresholdsListColors, gaugeColors, lineColors, - editQueryStatus: () => {}, + editQueryStatus: () => null, onCancel: () => {}, onSave: () => {}, notify: () => {}, diff --git a/ui/test/fixtures/index.ts b/ui/test/fixtures/index.ts index 234fea24ee..99160d126a 100644 --- a/ui/test/fixtures/index.ts +++ b/ui/test/fixtures/index.ts @@ -15,9 +15,9 @@ import { TableOptions, FieldOption, DecimalPlaces, -} from 'src/types/dashboard' + CellType, +} from 'src/types/dashboards' import {LineColor, ColorNumber} from 'src/types/colors' -import {CellType} from 'src/types/dashboard' export const sourceLinks: SourceLinks = { services: '/chronograf/v1/sources/4', diff --git a/ui/test/shared/reducers/app.test.js b/ui/test/shared/reducers/app.test.js index 77c8f41670..e3e3890085 100644 --- a/ui/test/shared/reducers/app.test.js +++ b/ui/test/shared/reducers/app.test.js @@ -2,7 +2,6 @@ import appReducer from 'shared/reducers/app' import { enablePresentationMode, disablePresentationMode, - // delayEnablePresentationMode, setAutoRefresh, templateControlBarVisibilityToggled, } from 'shared/actions/app'