diff --git a/docs/installation.rst b/docs/installation.rst index 329debc8a..3e2934a37 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -911,6 +911,12 @@ To allow scheduled queries, add the following to your `config.py`: 'container': 'end_date', }, ], + # link to the scheduler; this example links to an Airflow pipeline + # that uses the query id and the output table as its name + 'linkback': ( + 'https://airflow.example.com/admin/airflow/tree?' + 'dag_id=query_${id}_${extra_json.schedule_info.output_table}' + ), }, } diff --git a/superset/assets/spec/javascripts/showSavedQuery/utils_spec.jsx b/superset/assets/spec/javascripts/showSavedQuery/utils_spec.jsx new file mode 100644 index 000000000..d198a4918 --- /dev/null +++ b/superset/assets/spec/javascripts/showSavedQuery/utils_spec.jsx @@ -0,0 +1,65 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { getNestedValue, interpolate } from '../../../src/showSavedQuery/utils'; + +describe('getNestedValue', () => { + it('is a function', () => { + expect(typeof getNestedValue).toBe('function'); + }); + + it('works with simple ids', () => { + const obj = { a: '1' }; + const id = 'a'; + expect(getNestedValue(obj, id)).toEqual('1'); + }); + + it('works with complex ids', () => { + const obj = { a: { b: '1' } }; + const id = 'a.b'; + expect(getNestedValue(obj, id)).toEqual('1'); + }); + + it('works with other separators', () => { + const obj = { a: { b: { c: '1' } } }; + const id = 'a__b__c'; + const separator = '__'; + expect(getNestedValue(obj, id, separator)).toEqual('1'); + }); +}); + + +describe('interpolate', () => { + it('is a function', () => { + expect(typeof interpolate).toBe('function'); + }); + + it('works with simple ids', () => { + const obj = { a: '1' }; + // eslint-disable-next-line no-template-curly-in-string + const str = 'value: ${a}'; + expect(interpolate(str, obj)).toEqual('value: 1'); + }); + + it('works with complex ids', () => { + const obj = { a: { b: '1' } }; + // eslint-disable-next-line no-template-curly-in-string + const str = 'value: ${a.b}'; + expect(interpolate(str, obj)).toEqual('value: 1'); + }); +}); diff --git a/superset/assets/src/showSavedQuery/index.css b/superset/assets/src/showSavedQuery/index.css new file mode 100644 index 000000000..026dd784f --- /dev/null +++ b/superset/assets/src/showSavedQuery/index.css @@ -0,0 +1,20 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +.btn-add { display: none; } +.linkback { padding: 0 10px 20px 2px; } diff --git a/superset/assets/src/showSavedQuery/index.jsx b/superset/assets/src/showSavedQuery/index.jsx index cd384fe5b..c64626cb6 100644 --- a/superset/assets/src/showSavedQuery/index.jsx +++ b/superset/assets/src/showSavedQuery/index.jsx @@ -19,25 +19,39 @@ import React from 'react'; import ReactDom from 'react-dom'; import Form from 'react-jsonschema-form'; +import { interpolate } from 'src/showSavedQuery/utils'; +import './index.css'; const scheduleInfoContainer = document.getElementById('schedule-info'); const bootstrapData = JSON.parse(scheduleInfoContainer.getAttribute('data-bootstrap')); -const schemas = bootstrapData.common.feature_flags.SCHEDULED_QUERIES; -const scheduleInfo = bootstrapData.common.extra_json.schedule_info; +const config = bootstrapData.common.feature_flags.SCHEDULED_QUERIES; +const query = bootstrapData.common.query; +const scheduleInfo = query.extra_json.schedule_info; +const linkback = config.linkback + ? interpolate(config.linkback, query) + : null; -if (scheduleInfo && schemas) { +if (scheduleInfo && config) { // hide instructions when showing schedule info - schemas.JSONSCHEMA.description = ''; + config.JSONSCHEMA.description = ''; ReactDom.render( -
, +