mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-09-24 16:04:36 +08:00
Merge remote-tracking branch 'origin/devel' into CB-2344-projects-administration
This commit is contained in:
@@ -108,7 +108,7 @@ extend type Query {
|
||||
listRoles(roleId: ID): [AdminRoleInfo!]!
|
||||
listPermissions: [AdminPermissionInfo!]!
|
||||
|
||||
createUser(userId: ID!): AdminUserInfo!
|
||||
createUser(userId: ID!, enabled: Boolean!): AdminUserInfo!
|
||||
deleteUser(userId: ID!): Boolean
|
||||
|
||||
createRole(roleId: ID!, roleName: String, description: String): AdminRoleInfo!
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ public interface DBWServiceAdmin extends DBWService {
|
||||
|
||||
@WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN)
|
||||
@NotNull
|
||||
AdminUserInfo createUser(@NotNull WebSession webSession, String userName) throws DBWebException;
|
||||
AdminUserInfo createUser(@NotNull WebSession webSession, String userName, @NotNull Boolean enabled) throws DBWebException;
|
||||
|
||||
@WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN)
|
||||
boolean deleteUser(@NotNull WebSession webSession, String userName) throws DBWebException;
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ public class WebServiceBindingAdmin extends WebServiceBindingBase<DBWServiceAdmi
|
||||
.dataFetcher("listPermissions",
|
||||
env -> getService(env).listPermissions(getWebSession(env)))
|
||||
.dataFetcher("createUser",
|
||||
env -> getService(env).createUser(getWebSession(env), env.getArgument("userId")))
|
||||
env -> getService(env).createUser(getWebSession(env), env.getArgument("userId"), env.getArgument("enabled")))
|
||||
.dataFetcher("deleteUser",
|
||||
env -> getService(env).deleteUser(getWebSession(env), env.getArgument("userId")))
|
||||
.dataFetcher("createRole",
|
||||
|
||||
+2
-2
@@ -134,7 +134,7 @@ public class WebServiceAdmin implements DBWServiceAdmin {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public AdminUserInfo createUser(@NotNull WebSession webSession, String userName) throws DBWebException {
|
||||
public AdminUserInfo createUser(@NotNull WebSession webSession, String userName, @NotNull Boolean enabled) throws DBWebException {
|
||||
if (userName.isEmpty()) {
|
||||
throw new DBWebException("Empty user name");
|
||||
}
|
||||
@@ -142,7 +142,7 @@ public class WebServiceAdmin implements DBWServiceAdmin {
|
||||
|
||||
try {
|
||||
var securityController = webSession.getAdminSecurityController();
|
||||
securityController.createUser(userName, Map.of());
|
||||
securityController.createUser(userName, Map.of(), enabled);
|
||||
var smUser = securityController.getUserById(userName);
|
||||
return new AdminUserInfo(webSession, new WebUser(smUser));
|
||||
} catch (Exception e) {
|
||||
|
||||
+3
-3
@@ -107,7 +107,7 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen
|
||||
// Users
|
||||
|
||||
@Override
|
||||
public void createUser(String userId, Map<String, String> metaParameters) throws DBException {
|
||||
public void createUser(String userId, Map<String, String> metaParameters, boolean enabled) throws DBException {
|
||||
if (isSubjectExists(userId)) {
|
||||
throw new DBCException("User or role '" + userId + "' already exists");
|
||||
}
|
||||
@@ -116,7 +116,7 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen
|
||||
createAuthSubject(dbCon, userId, SUBJECT_USER);
|
||||
try (PreparedStatement dbStat = dbCon.prepareStatement("INSERT INTO CB_USER(USER_ID,IS_ACTIVE,CREATE_TIME) VALUES(?,?,?)")) {
|
||||
dbStat.setString(1, userId);
|
||||
dbStat.setString(2, CHAR_BOOL_TRUE);
|
||||
dbStat.setString(2, enabled ? CHAR_BOOL_TRUE : CHAR_BOOL_FALSE);
|
||||
dbStat.setTimestamp(3, new Timestamp(System.currentTimeMillis()));
|
||||
dbStat.execute();
|
||||
}
|
||||
@@ -1360,7 +1360,7 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen
|
||||
userId = userIdFromCredentials;
|
||||
if (!isSubjectExists(userId)) {
|
||||
var newUser = new SMUser(userId);
|
||||
createUser(newUser.getUserId(), newUser.getMetaParameters());
|
||||
createUser(newUser.getUserId(), newUser.getMetaParameters(), true);
|
||||
String defaultRoleName = WebAppUtils.getWebApplication().getAppConfiguration().getDefaultUserRole();
|
||||
if (!CommonUtils.isEmpty(defaultRoleName)) {
|
||||
setUserRoles(userId, new String[]{defaultRoleName}, userId);
|
||||
|
||||
+1
-1
@@ -246,7 +246,7 @@ public class CBDatabase {
|
||||
|
||||
if (adminUser == null) {
|
||||
adminUser = new SMUser(adminName);
|
||||
adminSecurityController.createUser(adminUser.getUserId(), adminUser.getMetaParameters());
|
||||
adminSecurityController.createUser(adminUser.getUserId(), adminUser.getMetaParameters(), true);
|
||||
}
|
||||
|
||||
if (!CommonUtils.isEmpty(adminPassword)) {
|
||||
|
||||
@@ -98,13 +98,14 @@ export class UsersResource extends CachedMapResource<string, AdminUser, UserReso
|
||||
}: UserCreateOptions): Promise<AdminUser> {
|
||||
const { user } = await this.graphQLService.sdk.createUser({
|
||||
userId,
|
||||
enabled,
|
||||
...this.getDefaultIncludes(),
|
||||
...this.getIncludesMap(userId),
|
||||
});
|
||||
|
||||
try {
|
||||
await this.updateCredentials(userId, credentials);
|
||||
await this.enableUser(userId, enabled, true);
|
||||
|
||||
for (const roleId of roles) {
|
||||
await this.grantRole(userId, roleId, true);
|
||||
}
|
||||
|
||||
@@ -6,15 +6,16 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
import { computed } from 'mobx';
|
||||
import { computed, toJS } from 'mobx';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import styled from 'reshadow';
|
||||
|
||||
import { useTranslate } from '@cloudbeaver/core-localization';
|
||||
import { useStyles } from '@cloudbeaver/core-theming';
|
||||
|
||||
import { Button } from '../Button';
|
||||
import { ShadowInput } from '../FormControls/ShadowInput';
|
||||
import { useObjectRef } from '../useObjectRef';
|
||||
import type { IProperty } from './IProperty';
|
||||
import { PropertyItem } from './PropertyItem';
|
||||
@@ -31,6 +32,7 @@ interface Props {
|
||||
onAdd?: () => void;
|
||||
onRemove?: (property: IProperty) => void;
|
||||
className?: string;
|
||||
filterable?: boolean;
|
||||
}
|
||||
|
||||
export const PropertiesTable = observer<Props>(function PropertiesTable(props) {
|
||||
@@ -38,8 +40,13 @@ export const PropertiesTable = observer<Props>(function PropertiesTable(props) {
|
||||
const translate = useTranslate();
|
||||
const propsRef = useObjectRef({ ...props });
|
||||
|
||||
const sortedProperties = useMemo(() => computed(() => propsRef.properties.slice().sort(
|
||||
(a, b) => (a?.displayName ?? '').localeCompare(b?.displayName ?? ''))), [propsRef.properties]);
|
||||
const [filterValue, setFilterValue] = useState('');
|
||||
|
||||
const sortedProperties = useMemo(() => computed(() => propsRef.properties
|
||||
.slice()
|
||||
.sort((a, b) => (a.displayName ?? '').localeCompare(b.displayName ?? ''))
|
||||
.filter(p => p.key.toLocaleLowerCase().includes(filterValue.toLocaleLowerCase()))
|
||||
), [propsRef.properties, filterValue]);
|
||||
|
||||
const changeName = useCallback((id: string, key: string) => {
|
||||
const { properties, propertiesState, onKeyChange } = propsRef;
|
||||
@@ -109,7 +116,16 @@ export const PropertiesTable = observer<Props>(function PropertiesTable(props) {
|
||||
<properties className={className}>
|
||||
<properties-header>
|
||||
<properties-header-name>
|
||||
{translate('block_properties_table_name')}
|
||||
<div>
|
||||
{translate('block_properties_table_name')}
|
||||
</div>
|
||||
{props.filterable ? (
|
||||
<ShadowInput
|
||||
value={filterValue}
|
||||
placeholder={translate('block_properties_table_filter_name')}
|
||||
onChange={setFilterValue}
|
||||
/>
|
||||
) : null}
|
||||
</properties-header-name>
|
||||
<properties-header-value>
|
||||
{translate('block_properties_table_value')}
|
||||
|
||||
@@ -139,7 +139,12 @@ export const PropertyItem = observer<Props>(function PropertyItem({
|
||||
const handleRemove = useCallback(() => onRemove(property.id), [property]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (keyInputRef.current && isDeletable && property.new) {
|
||||
if (
|
||||
keyInputRef.current
|
||||
&& isDeletable
|
||||
&& property.new
|
||||
&& !(document.activeElement instanceof HTMLInputElement)
|
||||
) {
|
||||
keyInputRef.current.focus();
|
||||
}
|
||||
}, [property]);
|
||||
|
||||
@@ -19,6 +19,7 @@ export const PROPERTIES_TABLE_STYLES = css`
|
||||
box-sizing: border-box;
|
||||
display: inline-flex;
|
||||
border-bottom: solid 1px;
|
||||
align-items: center;
|
||||
}
|
||||
properties-header-name, properties-header-value {
|
||||
composes: theme-typography--caption from global;
|
||||
@@ -30,6 +31,8 @@ export const PROPERTIES_TABLE_STYLES = css`
|
||||
properties-header-name {
|
||||
flex: 0 0 auto;
|
||||
width: 300px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
properties-header-add {
|
||||
flex: 0 0 auto;
|
||||
@@ -54,6 +57,14 @@ export const PROPERTIES_TABLE_STYLES = css`
|
||||
height: 24px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
ShadowInput {
|
||||
composes: theme-background-surface from global;
|
||||
box-sizing: border-box;
|
||||
height: 24px;
|
||||
flex: 1;
|
||||
margin-left: 8px;
|
||||
}
|
||||
`;
|
||||
|
||||
export const PROPERTIES_TABLE_ADD_STYLES = css`
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export default [
|
||||
['block_properties_table_name', 'Name'],
|
||||
['block_properties_table_value', 'Value'],
|
||||
['block_properties_table_filter_name', 'Filter'],
|
||||
['block_properties_table_add', 'Add property'],
|
||||
['combobox_no_results_placeholder', 'No results'],
|
||||
];
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export default [
|
||||
['block_properties_table_name', 'Название'],
|
||||
['block_properties_table_value', 'Значение'],
|
||||
['block_properties_table_filter_name', 'Фильтр'],
|
||||
['block_properties_table_add', 'Добавить параметр'],
|
||||
['combobox_no_results_placeholder', 'Нет совпадений'],
|
||||
];
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
query createUser($userId: ID!, $includeMetaParameters: Boolean!, $customIncludeOriginDetails: Boolean!) {
|
||||
user: createUser(userId: $userId) {
|
||||
query createUser($userId: ID!, $enabled: Boolean!, $includeMetaParameters: Boolean!, $customIncludeOriginDetails: Boolean!) {
|
||||
user: createUser(userId: $userId, enabled: $enabled) {
|
||||
...AdminUserInfo
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -961,6 +961,7 @@ export interface QueryCreateRoleArgs {
|
||||
|
||||
|
||||
export interface QueryCreateUserArgs {
|
||||
enabled: Scalars['Boolean'];
|
||||
userId: Scalars['ID'];
|
||||
}
|
||||
|
||||
@@ -1704,6 +1705,7 @@ export type SaveUserMetaParametersQuery = { setUserMetaParameterValues: boolean
|
||||
|
||||
export type CreateUserQueryVariables = Exact<{
|
||||
userId: Scalars['ID'];
|
||||
enabled: Scalars['Boolean'];
|
||||
includeMetaParameters: Scalars['Boolean'];
|
||||
customIncludeOriginDetails: Scalars['Boolean'];
|
||||
}>;
|
||||
@@ -3147,8 +3149,8 @@ export const SaveUserMetaParametersDocument = `
|
||||
}
|
||||
`;
|
||||
export const CreateUserDocument = `
|
||||
query createUser($userId: ID!, $includeMetaParameters: Boolean!, $customIncludeOriginDetails: Boolean!) {
|
||||
user: createUser(userId: $userId) {
|
||||
query createUser($userId: ID!, $enabled: Boolean!, $includeMetaParameters: Boolean!, $customIncludeOriginDetails: Boolean!) {
|
||||
user: createUser(userId: $userId, enabled: $enabled) {
|
||||
...AdminUserInfo
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -105,6 +105,7 @@ export const DriverProperties: TabContainerPanelComponent<IConnectionFormProps>
|
||||
properties={joinedProperties.get()}
|
||||
propertiesState={formState.config.properties}
|
||||
readOnly={formState.readonly}
|
||||
filterable
|
||||
onAdd={state.add}
|
||||
onRemove={state.remove}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user