mirror of
https://github.com/getredash/redash.git
synced 2025-12-25 01:03:20 -05:00
Hide shcema browser when it's not relevant
This commit is contained in:
@@ -72,8 +72,10 @@ function queryEditor(QuerySnippet) {
|
||||
|
||||
$scope.$watch('schema', (newSchema, oldSchema) => {
|
||||
if (newSchema !== oldSchema) {
|
||||
const tokensCount =
|
||||
newSchema.reduce((totalLength, table) => totalLength + table.columns.length, 0);
|
||||
if (newSchema === undefined) {
|
||||
return;
|
||||
}
|
||||
const tokensCount = newSchema.reduce((totalLength, table) => totalLength + table.columns.length, 0);
|
||||
// If there are too many tokens we disable live autocomplete,
|
||||
// as it makes typing slower.
|
||||
if (tokensCount > 5000) {
|
||||
@@ -92,7 +94,6 @@ function queryEditor(QuerySnippet) {
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
const schemaCompleter = {
|
||||
getCompletions(state, session, pos, prefix, callback) {
|
||||
if (prefix.length === 0 || !$scope.schema) {
|
||||
@@ -112,19 +113,17 @@ function queryEditor(QuerySnippet) {
|
||||
});
|
||||
});
|
||||
|
||||
$scope.schema.keywords = map(keywords, (v, k) =>
|
||||
({
|
||||
name: k,
|
||||
value: k,
|
||||
score: 0,
|
||||
meta: v,
|
||||
}));
|
||||
$scope.schema.keywords = map(keywords, (v, k) => ({
|
||||
name: k,
|
||||
value: k,
|
||||
score: 0,
|
||||
meta: v,
|
||||
}));
|
||||
}
|
||||
callback(null, $scope.schema.keywords);
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
window.ace.acequire(['ace/ext/language_tools'], (langTools) => {
|
||||
langTools.addCompleter(schemaCompleter);
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="schema-container">
|
||||
<div class="schema-container" ng-if="$ctrl.schema">
|
||||
<div class="schema-control">
|
||||
<input type="text" placeholder="Search schema..." class="form-control" ng-model="$ctrl.schemaFilter" ng-disabled="$ctrl.isEmpty()">
|
||||
<button class="btn btn-default"
|
||||
|
||||
@@ -1,10 +1,25 @@
|
||||
import { pick, any, some, find, min, isObject } from 'underscore';
|
||||
import { SCHEMA_NOT_SUPPORTED, SCHEMA_LOAD_ERROR } from '@/services/data-source';
|
||||
import template from './query.html';
|
||||
|
||||
function QueryViewCtrl(
|
||||
$scope, Events, $route, $routeParams, $location, $window, $q,
|
||||
KeyboardShortcuts, Title, AlertDialog, Notifications, clientConfig, toastr, $uibModal,
|
||||
currentUser, Query, DataSource,
|
||||
$scope,
|
||||
Events,
|
||||
$route,
|
||||
$routeParams,
|
||||
$location,
|
||||
$window,
|
||||
$q,
|
||||
KeyboardShortcuts,
|
||||
Title,
|
||||
AlertDialog,
|
||||
Notifications,
|
||||
clientConfig,
|
||||
toastr,
|
||||
$uibModal,
|
||||
currentUser,
|
||||
Query,
|
||||
DataSource,
|
||||
) {
|
||||
function getQueryResult(maxAge) {
|
||||
if (maxAge === undefined) {
|
||||
@@ -31,8 +46,7 @@ function QueryViewCtrl(
|
||||
|
||||
// If we had an invalid value in localStorage (e.g. nothing, deleted source),
|
||||
// then use the first data source
|
||||
const isValidDataSourceId = !isNaN(dataSourceId) && some($scope.dataSources, ds =>
|
||||
ds.id === dataSourceId);
|
||||
const isValidDataSourceId = !isNaN(dataSourceId) && some($scope.dataSources, ds => ds.id === dataSourceId);
|
||||
|
||||
if (!isValidDataSourceId) {
|
||||
dataSourceId = $scope.dataSources[0].id;
|
||||
@@ -46,16 +60,16 @@ function QueryViewCtrl(
|
||||
// TODO: is it possible this will be called before dataSource is set?
|
||||
$scope.schema = [];
|
||||
$scope.dataSource.getSchema(refresh).then((data) => {
|
||||
data = data.data;
|
||||
const hasPrevSchema = refresh ? ($scope.schema && ($scope.schema.length > 0)) : false;
|
||||
const hasSchema = data && (data.length > 0);
|
||||
|
||||
if (hasSchema) {
|
||||
$scope.schema = data;
|
||||
data.forEach((table) => {
|
||||
if (data.schema) {
|
||||
$scope.schema = data.schema;
|
||||
$scope.schema.forEach((table) => {
|
||||
table.collapsed = true;
|
||||
});
|
||||
} else if (hasPrevSchema) {
|
||||
} else if (data.error.code === SCHEMA_NOT_SUPPORTED) {
|
||||
$scope.schema = undefined;
|
||||
} else if (data.error.code === SCHEMA_LOAD_ERROR) {
|
||||
toastr.error('Schema refresh failed. Please try again later.');
|
||||
} else {
|
||||
toastr.error('Schema refresh failed. Please try again later.');
|
||||
}
|
||||
});
|
||||
@@ -65,8 +79,10 @@ function QueryViewCtrl(
|
||||
|
||||
function updateDataSources(dataSources) {
|
||||
// Filter out data sources the user can't query (or used by current query):
|
||||
$scope.dataSources = dataSources.filter(dataSource =>
|
||||
!dataSource.view_only || dataSource.id === $scope.query.data_source_id);
|
||||
function canUseDataSource(dataSource) {
|
||||
return !dataSource.view_only || dataSource.id === $scope.query.data_source_id;
|
||||
}
|
||||
$scope.dataSources = dataSources.filter(canUseDataSource);
|
||||
|
||||
if ($scope.dataSources.length === 0) {
|
||||
$scope.noDataSources = true;
|
||||
@@ -123,7 +139,7 @@ function QueryViewCtrl(
|
||||
}
|
||||
$scope.queryExecuting = false;
|
||||
|
||||
$scope.isQueryOwner = (currentUser.id === $scope.query.user.id) || currentUser.hasPermission('admin');
|
||||
$scope.isQueryOwner = currentUser.id === $scope.query.user.id || currentUser.hasPermission('admin');
|
||||
$scope.canEdit = currentUser.canEdit($scope.query) || $scope.query.can_edit;
|
||||
$scope.canViewSource = currentUser.hasPermission('view_source');
|
||||
|
||||
@@ -167,25 +183,47 @@ function QueryViewCtrl(
|
||||
request.id = $scope.query.id;
|
||||
request.version = $scope.query.version;
|
||||
} else {
|
||||
request = pick($scope.query, ['schedule', 'query', 'id', 'description', 'name', 'data_source_id', 'options', 'latest_query_data_id', 'version', 'is_draft']);
|
||||
request = pick($scope.query, [
|
||||
'schedule',
|
||||
'query',
|
||||
'id',
|
||||
'description',
|
||||
'name',
|
||||
'data_source_id',
|
||||
'options',
|
||||
'latest_query_data_id',
|
||||
'version',
|
||||
'is_draft',
|
||||
]);
|
||||
}
|
||||
|
||||
const options = Object.assign({}, {
|
||||
successMessage: 'Query saved',
|
||||
errorMessage: 'Query could not be saved',
|
||||
}, customOptions);
|
||||
const options = Object.assign(
|
||||
{},
|
||||
{
|
||||
successMessage: 'Query saved',
|
||||
errorMessage: 'Query could not be saved',
|
||||
},
|
||||
customOptions,
|
||||
);
|
||||
|
||||
return Query.save(request, (updatedQuery) => {
|
||||
toastr.success(options.successMessage);
|
||||
$scope.query.version = updatedQuery.version;
|
||||
}, (error) => {
|
||||
if (error.status === 409) {
|
||||
toastr.error('It seems like the query has been modified by another user. ' +
|
||||
'Please copy/backup your changes and reload this page.', { autoDismiss: false });
|
||||
} else {
|
||||
toastr.error(options.errorMessage);
|
||||
}
|
||||
}).$promise;
|
||||
return Query.save(
|
||||
request,
|
||||
(updatedQuery) => {
|
||||
toastr.success(options.successMessage);
|
||||
$scope.query.version = updatedQuery.version;
|
||||
},
|
||||
(error) => {
|
||||
if (error.status === 409) {
|
||||
toastr.error(
|
||||
'It seems like the query has been modified by another user. ' +
|
||||
'Please copy/backup your changes and reload this page.',
|
||||
{ autoDismiss: false },
|
||||
);
|
||||
} else {
|
||||
toastr.error(options.errorMessage);
|
||||
}
|
||||
},
|
||||
).$promise;
|
||||
};
|
||||
|
||||
// toastr.success('It seems like the query has been modified by another user. ' +
|
||||
@@ -220,16 +258,21 @@ function QueryViewCtrl(
|
||||
|
||||
$scope.archiveQuery = () => {
|
||||
function archive() {
|
||||
Query.delete({ id: $scope.query.id }, () => {
|
||||
$scope.query.is_archived = true;
|
||||
$scope.query.schedule = null;
|
||||
}, () => {
|
||||
toastr.error('Query could not be archived.');
|
||||
});
|
||||
Query.delete(
|
||||
{ id: $scope.query.id },
|
||||
() => {
|
||||
$scope.query.is_archived = true;
|
||||
$scope.query.schedule = null;
|
||||
},
|
||||
() => {
|
||||
toastr.error('Query could not be archived.');
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
const title = 'Archive Query';
|
||||
const message = 'Are you sure you want to archive this query?<br/> All alerts and dashboard widgets created with its visualizations will be deleted.';
|
||||
const message =
|
||||
'Are you sure you want to archive this query?<br/> All alerts and dashboard widgets created with its visualizations will be deleted.';
|
||||
const confirm = { class: 'btn-warning', title: 'Archive' };
|
||||
|
||||
AlertDialog.open(title, message, confirm).then(archive);
|
||||
|
||||
@@ -1,31 +1,47 @@
|
||||
function DataSource($resource, $http) {
|
||||
const actions = {
|
||||
get: { method: 'GET', cache: false, isArray: false },
|
||||
query: { method: 'GET', cache: false, isArray: true },
|
||||
test: {
|
||||
method: 'POST', cache: false, isArray: false, url: 'api/data_sources/:id/test',
|
||||
},
|
||||
// getSchema: {
|
||||
// method: 'GET', cache: false, isArray: true, url: 'api/data_sources/:id/schema',
|
||||
// },
|
||||
};
|
||||
export const SCHEMA_NOT_SUPPORTED = 1;
|
||||
export const SCHEMA_LOAD_ERROR = 2;
|
||||
|
||||
const DataSourceResource = $resource('api/data_sources/:id', { id: '@id' }, actions);
|
||||
|
||||
DataSourceResource.prototype.getSchema = function getSchema(refresh = false) {
|
||||
function DataSource($q, $resource, $http) {
|
||||
function fetchSchema(dataSourceId, refresh = false) {
|
||||
const params = {};
|
||||
|
||||
if (refresh) {
|
||||
params.refresh = true;
|
||||
}
|
||||
|
||||
return $http.get(`api/data_sources/${this.id}/schema`, { params });
|
||||
return $http.get(`api/data_sources/${dataSourceId}/schema`, { params });
|
||||
}
|
||||
|
||||
const actions = {
|
||||
get: { method: 'GET', cache: false, isArray: false },
|
||||
query: { method: 'GET', cache: false, isArray: true },
|
||||
test: {
|
||||
method: 'POST',
|
||||
cache: false,
|
||||
isArray: false,
|
||||
url: 'api/data_sources/:id/test',
|
||||
},
|
||||
};
|
||||
|
||||
const DataSourceResource = $resource('api/data_sources/:id', { id: '@id' }, actions);
|
||||
|
||||
DataSourceResource.prototype.getSchema = function getSchema(refresh = false) {
|
||||
if (this._schema === undefined || refresh) {
|
||||
return fetchSchema(this.id, refresh).then((response) => {
|
||||
const data = response.data;
|
||||
|
||||
this._schema = data;
|
||||
|
||||
return data;
|
||||
});
|
||||
}
|
||||
|
||||
return $q.resolve(this._schema);
|
||||
};
|
||||
|
||||
return DataSourceResource;
|
||||
}
|
||||
|
||||
|
||||
export default function init(ngModule) {
|
||||
ngModule.factory('DataSource', DataSource);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user