mirror of
https://github.com/getredash/redash.git
synced 2026-03-24 11:00:27 -04:00
Allow unregistering settings tabs (#5000)
This commit is contained in:
@@ -4,10 +4,8 @@ import PageHeader from "@/components/PageHeader";
|
||||
import location from "@/services/location";
|
||||
import settingsMenu from "@/services/settingsMenu";
|
||||
|
||||
function wrapSettingsTab(options, WrappedComponent) {
|
||||
if (options) {
|
||||
settingsMenu.add(options);
|
||||
}
|
||||
function wrapSettingsTab(id, options, WrappedComponent) {
|
||||
settingsMenu.add(id, options);
|
||||
|
||||
return function SettingsTab(props) {
|
||||
const activeItem = settingsMenu.getActiveItem(location.path);
|
||||
|
||||
@@ -145,6 +145,7 @@ class DataSourcesList extends React.Component {
|
||||
}
|
||||
|
||||
const DataSourcesListPage = wrapSettingsTab(
|
||||
"DataSources.List",
|
||||
{
|
||||
permission: "admin",
|
||||
title: "Data Sources",
|
||||
|
||||
@@ -136,7 +136,7 @@ class EditDataSource extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
const EditDataSourcePage = wrapSettingsTab(null, EditDataSource);
|
||||
const EditDataSourcePage = wrapSettingsTab("DataSources.Edit", null, EditDataSource);
|
||||
|
||||
export default routeWithUserSession({
|
||||
path: "/data_sources/:dataSourceId([0-9]+)",
|
||||
|
||||
@@ -128,6 +128,7 @@ class DestinationsList extends React.Component {
|
||||
}
|
||||
|
||||
const DestinationsListPage = wrapSettingsTab(
|
||||
"AlertDestinations.List",
|
||||
{
|
||||
permission: "admin",
|
||||
title: "Alert Destinations",
|
||||
|
||||
@@ -103,7 +103,7 @@ class EditDestination extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
const EditDestinationPage = wrapSettingsTab(null, EditDestination);
|
||||
const EditDestinationPage = wrapSettingsTab("AlertDestinations.Edit", null, EditDestination);
|
||||
|
||||
export default routeWithUserSession({
|
||||
path: "/destinations/:destinationId([0-9]+)",
|
||||
|
||||
@@ -224,6 +224,7 @@ class GroupDataSources extends React.Component {
|
||||
}
|
||||
|
||||
const GroupDataSourcesPage = wrapSettingsTab(
|
||||
"Groups.DataSources",
|
||||
null,
|
||||
itemsList(
|
||||
GroupDataSources,
|
||||
|
||||
@@ -187,6 +187,7 @@ class GroupMembers extends React.Component {
|
||||
}
|
||||
|
||||
const GroupMembersPage = wrapSettingsTab(
|
||||
"Groups.Members",
|
||||
null,
|
||||
itemsList(
|
||||
GroupMembers,
|
||||
|
||||
@@ -124,6 +124,7 @@ class GroupsList extends React.Component {
|
||||
}
|
||||
|
||||
const GroupsListPage = wrapSettingsTab(
|
||||
"Groups.List",
|
||||
{
|
||||
permission: "list_users",
|
||||
title: "Groups",
|
||||
|
||||
@@ -188,6 +188,7 @@ class QuerySnippetsList extends React.Component {
|
||||
}
|
||||
|
||||
const QuerySnippetsListPage = wrapSettingsTab(
|
||||
"QuerySnippets.List",
|
||||
{
|
||||
permission: "create_query",
|
||||
title: "Query Snippets",
|
||||
|
||||
@@ -98,6 +98,7 @@ OrganizationSettings.defaultProps = {
|
||||
};
|
||||
|
||||
const OrganizationSettingsPage = wrapSettingsTab(
|
||||
"Settings.Organization",
|
||||
{
|
||||
permission: "admin",
|
||||
title: "Settings",
|
||||
|
||||
@@ -68,6 +68,7 @@ UserProfile.defaultProps = {
|
||||
};
|
||||
|
||||
const UserProfilePage = wrapSettingsTab(
|
||||
"Users.Account",
|
||||
{
|
||||
title: "Account",
|
||||
path: "users/me",
|
||||
|
||||
@@ -248,6 +248,7 @@ class UsersList extends React.Component {
|
||||
}
|
||||
|
||||
const UsersListPage = wrapSettingsTab(
|
||||
"Users.List",
|
||||
{
|
||||
permission: "list_users",
|
||||
title: "Users",
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import { isFunction, extend, omit, sortBy, find, filter } from "lodash";
|
||||
import { isString, isObject, isFunction, extend, omit, sortBy, find, filter } from "lodash";
|
||||
import { stripBase } from "@/components/ApplicationArea/Router";
|
||||
import { currentUser } from "@/services/auth";
|
||||
|
||||
class SettingsMenuItem {
|
||||
constructor(menuItem) {
|
||||
extend(this, { pathPrefix: `/${menuItem.path}` }, omit(menuItem, ["isActive"]));
|
||||
extend(this, { pathPrefix: `/${menuItem.path}` }, omit(menuItem, ["isActive", "isAvailable"]));
|
||||
if (isFunction(menuItem.isActive)) {
|
||||
this.isActive = menuItem.isActive;
|
||||
}
|
||||
if (isFunction(menuItem.isAvailable)) {
|
||||
this.isAvailable = menuItem.isAvailable;
|
||||
}
|
||||
}
|
||||
|
||||
isActive(path) {
|
||||
@@ -20,13 +23,22 @@ class SettingsMenuItem {
|
||||
}
|
||||
|
||||
class SettingsMenu {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
items = [];
|
||||
|
||||
add(id, item) {
|
||||
id = isString(id) ? id : null;
|
||||
this.remove(id);
|
||||
if (isObject(item)) {
|
||||
this.items.push(new SettingsMenuItem({ ...item, id }));
|
||||
this.items = sortBy(this.items, "order");
|
||||
}
|
||||
}
|
||||
|
||||
add(item) {
|
||||
this.items.push(new SettingsMenuItem(item));
|
||||
this.items = sortBy(this.items, "order");
|
||||
remove(id) {
|
||||
if (isString(id)) {
|
||||
this.items = filter(this.items, item => item.id !== id);
|
||||
// removing item does not change order of other items, so no need to sort
|
||||
}
|
||||
}
|
||||
|
||||
getAvailableItems() {
|
||||
|
||||
@@ -11,8 +11,8 @@ const usersItem = {
|
||||
path: "users",
|
||||
};
|
||||
|
||||
settingsMenu.add(dataSourcesItem);
|
||||
settingsMenu.add(usersItem);
|
||||
settingsMenu.add(null, dataSourcesItem);
|
||||
settingsMenu.add(null, usersItem);
|
||||
|
||||
describe("SettingsMenu", () => {
|
||||
describe("isActive", () => {
|
||||
|
||||
Reference in New Issue
Block a user