Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cb 4629 end user preferences #2546

Merged
merged 20 commits into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.jkiss.dbeaver.model.connection.DBPConnectionConfiguration;
import org.jkiss.dbeaver.model.connection.DBPDriver;
import org.jkiss.dbeaver.model.net.DBWNetworkProfile;
import org.jkiss.dbeaver.model.preferences.DBPPreferenceStore;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.secret.DBSSecretController;
import org.jkiss.dbeaver.model.struct.DBSObjectFilter;
Expand Down Expand Up @@ -322,6 +323,12 @@ public Set<DBPDataSourceFolder> getTemporaryFolders() {
return dataSourceRegistry.getTemporaryFolders();
}

@NotNull
@Override
public DBPPreferenceStore getPreferenceStore() {
return dataSourceRegistry.getPreferenceStore();
}

@Override
public boolean loadDataSources(
@NotNull List<DBPDataSourceConfigurationStorage> storages,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,25 @@
import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
import org.jkiss.dbeaver.model.app.DBPWorkspace;
import org.jkiss.dbeaver.model.auth.SMSessionContext;
import org.jkiss.dbeaver.model.preferences.DBPPreferenceStore;
import org.jkiss.dbeaver.model.rm.RMController;
import org.jkiss.dbeaver.model.rm.RMProject;
import org.jkiss.dbeaver.registry.rm.DataSourceRegistryRM;
import org.jkiss.dbeaver.runtime.DBWorkbench;

public abstract class WebProjectImpl extends BaseWebProjectImpl {
private static final Log log = Log.getLog(WebProjectImpl.class);

private final DBPPreferenceStore preferenceStore;
public WebProjectImpl(
@NotNull DBPWorkspace workspace,
@NotNull RMController resourceController,
@NotNull SMSessionContext sessionContext,
@NotNull RMProject project,
@NotNull DataSourceFilter dataSourceFilter
@NotNull DataSourceFilter dataSourceFilter,
DBPPreferenceStore preferenceStore
alexander-skoblikov marked this conversation as resolved.
Show resolved Hide resolved
) {
super(workspace, resourceController, sessionContext, project, dataSourceFilter);
this.preferenceStore = preferenceStore;
}

@Nullable
Expand Down Expand Up @@ -70,7 +73,7 @@ public boolean isUseSecretStorage() {
@Override
protected DBPDataSourceRegistry createDataSourceRegistry() {
return new WebDataSourceRegistryProxy(
new DataSourceRegistryRM(this, getResourceController()),
new DataSourceRegistryRM(this, getResourceController(), preferenceStore),
dataSourceFilter
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,19 @@ public class WebSessionProjectImpl extends WebProjectImpl {

private final WebSession webSession;

public WebSessionProjectImpl(@NotNull WebSession webSession, @NotNull RMProject project, @NotNull DataSourceFilter dataSourceFilter) {
super(webSession.getWorkspace(), webSession.getRmController(), webSession.getSessionContext(), project, dataSourceFilter);
public WebSessionProjectImpl(
@NotNull WebSession webSession,
@NotNull RMProject project,
@NotNull DataSourceFilter dataSourceFilter
) {
super(
webSession.getWorkspace(),
webSession.getRmController(),
webSession.getSessionContext(),
project,
dataSourceFilter,
webSession.getUserPreferenceStore()
);
this.webSession = webSession;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
import org.jkiss.dbeaver.model.meta.Association;
import org.jkiss.dbeaver.model.meta.Property;
import org.jkiss.dbeaver.model.navigator.DBNModel;
import org.jkiss.dbeaver.model.preferences.DBPPreferenceStore;
import org.jkiss.dbeaver.model.rm.RMController;
import org.jkiss.dbeaver.model.rm.RMProject;
import org.jkiss.dbeaver.model.rm.RMProjectType;
Expand Down Expand Up @@ -1108,6 +1109,11 @@ public DBFFileSystemManager getFileSystemManager(String projectId) throws DBExce
return project.getFileSystemManager();
}

@NotNull
public DBPPreferenceStore getUserPreferenceStore() {
return getUserContext().getPreferenceStore();
}

private class SessionProgressMonitor extends BaseProgressMonitor {
@Override
public void beginTask(String name, int totalWork) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2024 DBeaver Corp and others
*
* Licensed 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.
*/
package io.cloudbeaver.model.session;

import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.model.impl.preferences.AbstractUserPreferenceStore;
import org.jkiss.dbeaver.model.preferences.DBPPreferenceStore;

import java.io.IOException;
import java.util.Map;

public class WebSessionPreferenceStore extends AbstractUserPreferenceStore {
public WebSessionPreferenceStore(
@NotNull DBPPreferenceStore parentStore
) {
super(parentStore);
}

// to avoid redundant sm api call
public void updatePreferenceValues(@NotNull Map<String, Object> newValues) {

Check warning on line 34 in server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSessionPreferenceStore.java

View check run for this annotation

Jenkins-CI-integration / CheckStyle Java Report

server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSessionPreferenceStore.java#L34

Missing a Javadoc comment.
userPreferences.putAll(newValues);
}

@Override
protected void setUserPreference(String name, Object value) {
throw new RuntimeException("Not implemented");
}

@Override
public String getDefaultString(String name) {
return parentStore.getDefaultString(name);
}

@Override
public boolean isDefault(String name) {
return !userPreferences.containsKey(name) && parentStore.isDefault(name);
}

@Override
public boolean needsSaving() {
return false;
}

@Override
public void setToDefault(String name) {
throw new RuntimeException("Not implemented");
}

@Override
public void save() throws IOException {
throw new RuntimeException("Not implemented");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,10 @@
import org.jkiss.dbeaver.model.security.SMAdminController;
import org.jkiss.dbeaver.model.security.SMController;
import org.jkiss.dbeaver.model.security.user.SMAuthPermissions;
import org.jkiss.dbeaver.runtime.DBWorkbench;
import org.jkiss.utils.CommonUtils;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;

/**
Expand All @@ -66,13 +64,15 @@ public class WebUserContext implements SMCredentialsProvider {
private RMController rmController;
private DBFileController fileController;
private Set<String> accessibleProjectIds = new HashSet<>();
private final WebSessionPreferenceStore preferenceStore;

public WebUserContext(WebApplication application, DBPWorkspace workspace) throws DBException {
this.application = application;
this.workspace = workspace;
this.securityController = application.createSecurityController(this);
this.rmController = application.createResourceController(this, workspace);
this.fileController = application.createFileController(this);
this.preferenceStore = new WebSessionPreferenceStore(DBWorkbench.getPlatform().getPreferenceStore());
setUserPermissions(getDefaultPermissions());
}

Expand Down Expand Up @@ -117,6 +117,11 @@ public synchronized boolean refresh(
setUserPermissions(smAuthPermissions.getPermissions());
this.adminSecurityController = application.getAdminSecurityController(this);
if (isSessionChanged) {
if (smAuthPermissions.getUserId() != null) {
this.preferenceStore.updateAllUserPreferences(securityController.getCurrentUserParameters());
} else {
this.preferenceStore.updateAllUserPreferences(Map.of());
}
this.smSessionId = smAuthPermissions.getSessionId();
setUser(smAuthPermissions.getUserId() == null ? null : new WebUser(securityController.getCurrentUser()));
refreshAccessibleProjects();
Expand Down Expand Up @@ -251,4 +256,8 @@ public Set<String> getAccessibleProjectIds() {
private void setRefreshToken(@Nullable String refreshToken) {
this.refreshToken = refreshToken;
}

public WebSessionPreferenceStore getPreferenceStore() {
return preferenceStore;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import org.jkiss.utils.CommonUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

Expand Down Expand Up @@ -264,6 +265,9 @@ private static boolean setPreference(
try {
String serializedValue = value == null ? null : value.toString();
webSession.getSecurityController().setCurrentUserParameter(name, serializedValue);
var params = new HashMap<String, Object>();
params.put(name, value);
webSession.getUserContext().getPreferenceStore().updatePreferenceValues(params);
return true;
} catch (DBException e) {
throw new DBWebException("Error setting user parameter", e);
Expand All @@ -278,10 +282,13 @@ public WebUserInfo setUserConfigurationParameters(
if (webSession.getUser() == null) {
throw new DBWebException("Preferences cannot be changed for anonymous user");
}
for (Map.Entry<String, Object> parameter : parameters.entrySet()) {
setPreference(webSession, parameter.getKey(), parameter.getValue());
try {
webSession.getSecurityController().setCurrentUserParameters(parameters);
webSession.getUserContext().getPreferenceStore().updatePreferenceValues(parameters);
return new WebUserInfo(webSession, webSession.getUser());
} catch (DBException e) {
throw new DBWebException("Error setting user parameters", e);
}
return new WebUserInfo(webSession, webSession.getUser());
}

}
13 changes: 13 additions & 0 deletions webapp/packages/core-settings-user/src/UserSettingsService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { UserInfoResource } from '@cloudbeaver/core-authentication';
import { injectable } from '@cloudbeaver/core-di';
import { SettingsSource } from '@cloudbeaver/core-settings';
import { StorageService } from '@cloudbeaver/core-storage';
import { isNull } from '@cloudbeaver/core-utils';

@injectable()
export class UserSettingsService extends SettingsSource {
Expand Down Expand Up @@ -80,6 +81,13 @@ export class UserSettingsService extends SettingsSource {
super.clear();
}

restoreDefaults() {
this.resetChanges();
for (const key of this.getSource().keys()) {
this.setValue(key, null);
}
}

protected getSnapshot() {
return Object.fromEntries(this.getSource());
}
Expand All @@ -99,6 +107,11 @@ export class UserSettingsService extends SettingsSource {

if (this.lastConfig && typeof this.lastConfig === 'object') {
for (const [key, value] of Object.entries(this.lastConfig)) {
if (isNull(value)) {
console.warn(`User settings value is null for key: ${key}. Setting will be ignored.`);
continue;
}

this.settings.set(key, value);
this.localSettings.set(key, value);
}
Expand Down
5 changes: 3 additions & 2 deletions webapp/packages/core-settings/src/SettingsResolverSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import { computed, makeObservable, observable } from 'mobx';

import { type ISyncExecutor, SyncExecutor } from '@cloudbeaver/core-executor';
import { isNotNullDefined } from '@cloudbeaver/core-utils';

import type { ISettingsResolverSource } from './ISettingsResolverSource';
import type { ISettingChangeData, ISettingsSource } from './ISettingsSource';
Expand Down Expand Up @@ -102,11 +103,11 @@ export class SettingsResolverSource implements ISettingsResolverSource {
}

getEditedValue(key: any): any {
return this.sources.find(r => r.has(key))?.getEditedValue(key);
return this.sources.find(r => r.has(key) && isNotNullDefined(r.getEditedValue(key)))?.getEditedValue(key);
}

getValue(key: any): any {
return this.sources.find(r => r.has(key))?.getValue(key);
return this.sources.find(r => r.has(key) && isNotNullDefined(r.getValue(key)))?.getValue(key);
}

setValue(key: any, value: any): void {
Expand Down
3 changes: 2 additions & 1 deletion webapp/packages/core-settings/src/SettingsSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ export abstract class SettingsSource implements ISettingsSource {
}

setValue(key: any, value: any): void {
if (this.getValue(key) === value) {
const currentValue = this.getValue(key);
if (currentValue === value || (!isNotNullDefined(currentValue) && value === null)) {
this.changes.delete(key);
} else {
this.changes.set(key, value);
Expand Down
2 changes: 1 addition & 1 deletion webapp/packages/core-ui/src/Tabs/TabsState.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export const TabsState = observer(function TabsState<T = Record<string, any>>({
const [openExecutor] = useState(() => new Executor<ITabData<T>>());

const state = useTabState({
selectedId: selectedId || currentTabId,
selectedId: selectedId || currentTabId || container?.selectedId,
orientation,
manual,
});
Expand Down
10 changes: 3 additions & 7 deletions webapp/packages/plugin-devtools/src/PluginBootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/
import { App, Bootstrap, DIService, injectable, IServiceConstructor } from '@cloudbeaver/core-di';
import { CachedResource } from '@cloudbeaver/core-resource';
import { PermissionsService, EAdminPermission } from '@cloudbeaver/core-root';
import { EAdminPermission, PermissionsService } from '@cloudbeaver/core-root';
import { ActionService, DATA_CONTEXT_MENU, DATA_CONTEXT_SUBMENU_ITEM, MenuBaseItem, MenuService } from '@cloudbeaver/core-view';
import { TOP_NAV_BAR_SETTINGS_MENU } from '@cloudbeaver/plugin-settings-menu';
import { MENU_USER_PROFILE } from '@cloudbeaver/plugin-user-profile';
Expand Down Expand Up @@ -41,12 +41,8 @@ export class PluginBootstrap extends Bootstrap {

register(): void {
this.menuService.addCreator({
isApplicable: context => {
if (!this.permissionsService.has(EAdminPermission.admin)) {
return false;
}
return context.get(DATA_CONTEXT_MENU) === TOP_NAV_BAR_SETTINGS_MENU;
},
menus: [TOP_NAV_BAR_SETTINGS_MENU],
isApplicable: () => this.permissionsService.has(EAdminPermission.admin),
getItems: (context, items) => [ACTION_DEVTOOLS, ...items],
});

Expand Down
6 changes: 1 addition & 5 deletions webapp/packages/plugin-localization/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,7 @@
"update-ts-references": "rimraf --glob dist && typescript-resolve-references"
},
"dependencies": {
"@cloudbeaver/core-di": "~0.1.0",
"@cloudbeaver/core-localization": "~0.1.0",
"@cloudbeaver/core-root": "~0.1.0",
"@cloudbeaver/core-view": "~0.1.0",
"@cloudbeaver/plugin-settings-menu": "~0.1.0"
"@cloudbeaver/core-di": "~0.1.0"
},
"peerDependencies": {},
"devDependencies": {
Expand Down
10 changes: 0 additions & 10 deletions webapp/packages/plugin-localization/src/LOCALIZATION_MENU.ts

This file was deleted.

Loading
Loading