diff --git a/http/cur_swagger.yml b/http/cur_swagger.yml index 3c3268cb48..4bb983bc64 100644 --- a/http/cur_swagger.yml +++ b/http/cur_swagger.yml @@ -43,6 +43,59 @@ paths: application/json: schema: $ref: "#/components/schemas/Routes" + /protos: + get: + tags: + - Protos + summary: List of available protos (templates of tasks/dashboards/etc) + parameters: + - $ref: '#/components/parameters/TraceSpan' + responses: + '200': + description: List of protos + content: + application/json: + schema: + $ref: "#/components/schemas/Protos" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /protos/{protoID}/dashboards: + post: + tags: + - Protos + summary: Create instance of a proto dashboard + parameters: + - $ref: '#/components/parameters/TraceSpan' + - in: path + name: protoID + schema: + type: string + required: true + description: ID of proto + requestBody: + description: organization that the dashboard will be created as + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/CreateProtoResourcesRequest" + responses: + '201': + description: List of dashboards that was created + content: + application/json: + schema: + $ref: "#/components/schemas/Dashboards" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" /setup: get: tags: @@ -6102,4 +6155,37 @@ components: type: object description: Key/Value pairs associated with this label. Keys can be removed by sending an update with an empty value. example: {"color": "#ffb3b3", "description": "this is a description"} - \ No newline at end of file + CreateProtoResourcesRequest: + properties: + orgID: + type: string + Proto: + properties: + links: + readOnly: true + type: object + properties: + dashboard: + type: string + format: uri + id: + readOnly: true + type: string + name: + readOnly: true + type: string + description: user-facing name of the proto + dashboards: + type: array + items: + $ref: "#/components/schemas/Dashboard" + views: + type: object + additionalProperties: + $ref: "#/components/schemas/View" + Protos: + properties: + protos: + type: array + items: + $ref: "#/components/schemas/Proto" \ No newline at end of file diff --git a/ui/src/api/api.ts b/ui/src/api/api.ts index a25a371f69..ac987c7ce5 100644 --- a/ui/src/api/api.ts +++ b/ui/src/api/api.ts @@ -594,6 +594,20 @@ export interface CreateCell { usingView?: string; } +/** + * + * @export + * @interface CreateProtoResourcesRequest + */ +export interface CreateProtoResourcesRequest { + /** + * + * @type {string} + * @memberof CreateProtoResourcesRequest + */ + orgID?: string; +} + /** * * @export @@ -1990,6 +2004,72 @@ export namespace PermissionResource { } } +/** + * + * @export + * @interface Proto + */ +export interface Proto { + /** + * + * @type {ProtoLinks} + * @memberof Proto + */ + links?: ProtoLinks; + /** + * + * @type {string} + * @memberof Proto + */ + id?: string; + /** + * user-facing name of the proto + * @type {string} + * @memberof Proto + */ + name?: string; + /** + * + * @type {Array} + * @memberof Proto + */ + dashboards?: Array; + /** + * + * @type {{ [key: string]: View; }} + * @memberof Proto + */ + views?: { [key: string]: View; }; +} + +/** + * + * @export + * @interface ProtoLinks + */ +export interface ProtoLinks { + /** + * + * @type {string} + * @memberof ProtoLinks + */ + dashboard?: string; +} + +/** + * + * @export + * @interface Protos + */ +export interface Protos { + /** + * + * @type {Array} + * @memberof Protos + */ + protos?: Array; +} + /** * query influx with specified return formatting. The spec and query fields are mutually exclusive. * @export @@ -10286,6 +10366,199 @@ export class OrganizationsApi extends BaseAPI { } +/** + * ProtosApi - axios parameter creator + * @export + */ +export const ProtosApiAxiosParamCreator = function (configuration?: Configuration) { + return { + /** + * + * @summary List of available protos (templates of tasks/dashboards/etc) + * @param {string} [zapTraceSpan] OpenTracing span context + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + protosGet(zapTraceSpan?: string, options: any = {}): RequestArgs { + const localVarPath = `/protos`; + const localVarUrlObj = url.parse(localVarPath, true); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + const localVarRequestOptions = Object.assign({ method: 'GET' }, baseOptions, options); + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + if (zapTraceSpan !== undefined && zapTraceSpan !== null) { + localVarHeaderParameter['Zap-Trace-Span'] = String(zapTraceSpan); + } + + localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); + // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 + delete localVarUrlObj.search; + localVarRequestOptions.headers = Object.assign({}, localVarHeaderParameter, options.headers); + + return { + url: url.format(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @summary Create instance of a proto dashboard + * @param {string} protoID ID of proto + * @param {CreateProtoResourcesRequest} createProtoResourcesRequest organization that the dashboard will be created as + * @param {string} [zapTraceSpan] OpenTracing span context + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + protosProtoIDDashboardsPost(protoID: string, createProtoResourcesRequest: CreateProtoResourcesRequest, zapTraceSpan?: string, options: any = {}): RequestArgs { + // verify required parameter 'protoID' is not null or undefined + if (protoID === null || protoID === undefined) { + throw new RequiredError('protoID','Required parameter protoID was null or undefined when calling protosProtoIDDashboardsPost.'); + } + // verify required parameter 'createProtoResourcesRequest' is not null or undefined + if (createProtoResourcesRequest === null || createProtoResourcesRequest === undefined) { + throw new RequiredError('createProtoResourcesRequest','Required parameter createProtoResourcesRequest was null or undefined when calling protosProtoIDDashboardsPost.'); + } + const localVarPath = `/protos/{protoID}/dashboards` + .replace(`{${"protoID"}}`, encodeURIComponent(String(protoID))); + const localVarUrlObj = url.parse(localVarPath, true); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + const localVarRequestOptions = Object.assign({ method: 'POST' }, baseOptions, options); + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + if (zapTraceSpan !== undefined && zapTraceSpan !== null) { + localVarHeaderParameter['Zap-Trace-Span'] = String(zapTraceSpan); + } + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); + // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 + delete localVarUrlObj.search; + localVarRequestOptions.headers = Object.assign({}, localVarHeaderParameter, options.headers); + const needsSerialization = ("CreateProtoResourcesRequest" !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json'; + localVarRequestOptions.data = needsSerialization ? JSON.stringify(createProtoResourcesRequest || {}) : (createProtoResourcesRequest || ""); + + return { + url: url.format(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + } +}; + +/** + * ProtosApi - functional programming interface + * @export + */ +export const ProtosApiFp = function(configuration?: Configuration) { + return { + /** + * + * @summary List of available protos (templates of tasks/dashboards/etc) + * @param {string} [zapTraceSpan] OpenTracing span context + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + protosGet(zapTraceSpan?: string, options?: any): (axios?: AxiosInstance, basePath?: string) => AxiosPromise { + const localVarAxiosArgs = ProtosApiAxiosParamCreator(configuration).protosGet(zapTraceSpan, options); + return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => { + const axiosRequestArgs = Object.assign(localVarAxiosArgs.options, {url: basePath + localVarAxiosArgs.url}) + return axios.request(axiosRequestArgs); + }; + }, + /** + * + * @summary Create instance of a proto dashboard + * @param {string} protoID ID of proto + * @param {CreateProtoResourcesRequest} createProtoResourcesRequest organization that the dashboard will be created as + * @param {string} [zapTraceSpan] OpenTracing span context + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + protosProtoIDDashboardsPost(protoID: string, createProtoResourcesRequest: CreateProtoResourcesRequest, zapTraceSpan?: string, options?: any): (axios?: AxiosInstance, basePath?: string) => AxiosPromise { + const localVarAxiosArgs = ProtosApiAxiosParamCreator(configuration).protosProtoIDDashboardsPost(protoID, createProtoResourcesRequest, zapTraceSpan, options); + return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => { + const axiosRequestArgs = Object.assign(localVarAxiosArgs.options, {url: basePath + localVarAxiosArgs.url}) + return axios.request(axiosRequestArgs); + }; + }, + } +}; + +/** + * ProtosApi - factory interface + * @export + */ +export const ProtosApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) { + return { + /** + * + * @summary List of available protos (templates of tasks/dashboards/etc) + * @param {string} [zapTraceSpan] OpenTracing span context + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + protosGet(zapTraceSpan?: string, options?: any) { + return ProtosApiFp(configuration).protosGet(zapTraceSpan, options)(axios, basePath); + }, + /** + * + * @summary Create instance of a proto dashboard + * @param {string} protoID ID of proto + * @param {CreateProtoResourcesRequest} createProtoResourcesRequest organization that the dashboard will be created as + * @param {string} [zapTraceSpan] OpenTracing span context + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + protosProtoIDDashboardsPost(protoID: string, createProtoResourcesRequest: CreateProtoResourcesRequest, zapTraceSpan?: string, options?: any) { + return ProtosApiFp(configuration).protosProtoIDDashboardsPost(protoID, createProtoResourcesRequest, zapTraceSpan, options)(axios, basePath); + }, + }; +}; + +/** + * ProtosApi - object-oriented interface + * @export + * @class ProtosApi + * @extends {BaseAPI} + */ +export class ProtosApi extends BaseAPI { + /** + * + * @summary List of available protos (templates of tasks/dashboards/etc) + * @param {string} [zapTraceSpan] OpenTracing span context + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ProtosApi + */ + public protosGet(zapTraceSpan?: string, options?: any) { + return ProtosApiFp(this.configuration).protosGet(zapTraceSpan, options)(this.axios, this.basePath); + } + + /** + * + * @summary Create instance of a proto dashboard + * @param {string} protoID ID of proto + * @param {CreateProtoResourcesRequest} createProtoResourcesRequest organization that the dashboard will be created as + * @param {string} [zapTraceSpan] OpenTracing span context + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ProtosApi + */ + public protosProtoIDDashboardsPost(protoID: string, createProtoResourcesRequest: CreateProtoResourcesRequest, zapTraceSpan?: string, options?: any) { + return ProtosApiFp(this.configuration).protosProtoIDDashboardsPost(protoID, createProtoResourcesRequest, zapTraceSpan, options)(this.axios, this.basePath); + } + +} + /** * QueryApi - axios parameter creator * @export diff --git a/ui/src/dashboards/apis/v2/index.ts b/ui/src/dashboards/apis/v2/index.ts index ba75ed2901..8a19f90bfe 100644 --- a/ui/src/dashboards/apis/v2/index.ts +++ b/ui/src/dashboards/apis/v2/index.ts @@ -19,7 +19,7 @@ import { updateDashboardLinks, } from 'src/dashboards/utils/dashboardSwitcherLinks' -const addDashboardIDToCells = ( +export const addDashboardIDToCells = ( cells: CellTypeAPI[], dashboardID: string ): Cell[] => { diff --git a/ui/src/protos/actions/index.ts b/ui/src/protos/actions/index.ts new file mode 100644 index 0000000000..fcded27e8b --- /dev/null +++ b/ui/src/protos/actions/index.ts @@ -0,0 +1,65 @@ +// Libraries +import {Dispatch} from 'redux' + +// APIs +import { + getProtos as getProtosAJAX, + createDashFromProto as createDashFromProtoAJAX, +} from 'src/protos/apis/' + +// Utils +import {addDashboardIDToCells} from 'src/dashboards/apis/v2/' + +// Actions +import {loadDashboard} from 'src/dashboards/actions/v2/' + +// Types +import {Proto, Dashboard} from 'src/api' + +export enum ActionTypes { + LoadProto = 'LOAD_PROTO', +} + +export type Action = LoadProtoAction + +interface LoadProtoAction { + type: ActionTypes.LoadProto + payload: { + proto: Proto + } +} + +export const loadProto = (proto: Proto): LoadProtoAction => ({ + type: ActionTypes.LoadProto, + payload: {proto}, +}) + +export const getProtos = () => async (dispatch: Dispatch) => { + try { + const {protos} = await getProtosAJAX() + protos.forEach(p => { + dispatch(loadProto(p)) + }) + } catch (error) { + console.error(error) + } +} + +export const createDashFromProto = ( + protoID: string, + orgID: string +) => async dispatch => { + try { + const {dashboards} = await createDashFromProtoAJAX(protoID, orgID) + + dashboards.forEach((d: Dashboard) => { + const updatedDashboard = { + ...d, + cells: addDashboardIDToCells(d.cells, d.id), + } + dispatch(loadDashboard(updatedDashboard)) + }) + } catch (error) { + console.error(error) + } +} diff --git a/ui/src/protos/apis/index.ts b/ui/src/protos/apis/index.ts new file mode 100644 index 0000000000..6d723ce2cc --- /dev/null +++ b/ui/src/protos/apis/index.ts @@ -0,0 +1,20 @@ +// API funcs +import {protosAPI} from 'src/utils/api' + +// types +import {Protos, Dashboards} from 'src/api' + +export const getProtos = async (): Promise => { + const {data} = await protosAPI.protosGet() + + return data +} + +export const createDashFromProto = async ( + protoID: string, + orgID: string +): Promise => { + const {data} = await protosAPI.protosProtoIDDashboardsPost(protoID, {orgID}) + // might want to map dashboard[] to more one more useful to FE. + return data +} diff --git a/ui/src/protos/reducers/index.ts b/ui/src/protos/reducers/index.ts new file mode 100644 index 0000000000..616f7eeb12 --- /dev/null +++ b/ui/src/protos/reducers/index.ts @@ -0,0 +1,27 @@ +// Types +import {Action} from 'src/protos/actions/' +import {Proto} from 'src/api' + +export interface ProtosState { + [protoName: string]: Proto +} + +const protosReducer = (state: ProtosState = {}, action: Action) => { + switch (action.type) { + case 'LOAD_PROTO': { + const { + proto, + proto: {name}, + } = action.payload + + return { + ...state, + [name]: {...proto}, + } + } + } + + return state +} + +export default protosReducer diff --git a/ui/src/store/configureStore.ts b/ui/src/store/configureStore.ts index a55256328f..2bb3584797 100644 --- a/ui/src/store/configureStore.ts +++ b/ui/src/store/configureStore.ts @@ -22,6 +22,7 @@ import orgsReducer from 'src/organizations/reducers/orgs' import onboardingReducer from 'src/onboarding/reducers' import noteEditorReducer from 'src/dashboards/reducers/v2/notes' import dataLoadingReducer from 'src/dataLoaders/reducers' +import protosReducer from 'src/protos/reducers' // Types import {LocalStorage} from 'src/types/localStorage' @@ -47,6 +48,7 @@ const rootReducer = combineReducers({ onboarding: onboardingReducer, noteEditor: noteEditorReducer, dataLoading: dataLoadingReducer, + protos: protosReducer, }) const composeEnhancers = diff --git a/ui/src/types/v2/index.ts b/ui/src/types/v2/index.ts index f6fcbfe878..dc4f562dd8 100644 --- a/ui/src/types/v2/index.ts +++ b/ui/src/types/v2/index.ts @@ -37,6 +37,7 @@ import {SourcesState} from 'src/sources/reducers' import {NoteEditorState} from 'src/dashboards/reducers/v2/notes' import {DataLoadingState} from 'src/dataLoaders/reducers' import {OnboardingState} from 'src/onboarding/reducers' +import {ProtosState} from 'src/protos/reducers' export interface AppState { VERSION: string @@ -57,6 +58,7 @@ export interface AppState { onboarding: OnboardingState noteEditor: NoteEditorState dataLoading: DataLoadingState + protos: ProtosState } export type GetState = () => AppState diff --git a/ui/src/utils/api.ts b/ui/src/utils/api.ts index 164c12cb13..554b3101d8 100644 --- a/ui/src/utils/api.ts +++ b/ui/src/utils/api.ts @@ -14,6 +14,7 @@ import { QueryApi, SetupApi, ScraperTargetsApi, + ProtosApi, } from 'src/api' const basePath = '/api/v2' @@ -33,3 +34,4 @@ export const orgsAPI = new OrganizationsApi({basePath}) export const queryAPI = new QueryApi({basePath}) export const setupAPI = new SetupApi({basePath}) export const scraperTargetsApi = new ScraperTargetsApi({basePath}) +export const protosAPI = new ProtosApi({basePath})