mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-10-24 01:23:21 +08:00
chore: rework administration styles & table selection behavior
CB-232
This commit is contained in:
@@ -24,13 +24,20 @@ type ExpandProps = {
|
||||
type Props = React.PropsWithChildren<{
|
||||
item: any;
|
||||
expandElement?: React.FunctionComponent<ExpandProps>;
|
||||
selectDisabled?: boolean;
|
||||
className?: string;
|
||||
onClick?: () => void;
|
||||
onDoubleClick?: () => void;
|
||||
}>
|
||||
|
||||
export const TableItem = observer(function TableItem({
|
||||
item, expandElement, children, className, onClick, onDoubleClick,
|
||||
item,
|
||||
expandElement,
|
||||
selectDisabled = false,
|
||||
children,
|
||||
className,
|
||||
onClick,
|
||||
onDoubleClick,
|
||||
}: Props) {
|
||||
const context = useContext(TableContext);
|
||||
if (!context) {
|
||||
@@ -39,24 +46,27 @@ export const TableItem = observer(function TableItem({
|
||||
|
||||
const itemContext = useMemo<ITableItemContext>(() => ({
|
||||
item,
|
||||
selectDisabled,
|
||||
isSelected: () => !!context.selectedItems.get(item),
|
||||
isExpanded: () => !!context.expandedItems.get(item),
|
||||
}), [item]);
|
||||
}), [item, selectDisabled]);
|
||||
|
||||
const handleClick = useCallback(
|
||||
(e: React.MouseEvent<HTMLTableRowElement>) => {
|
||||
const isSelected = context.selectedItems.get(item);
|
||||
if (!e.ctrlKey) {
|
||||
context.clearSelection();
|
||||
}
|
||||
if (!selectDisabled) {
|
||||
const isSelected = context.selectedItems.get(item);
|
||||
if (!e.ctrlKey) {
|
||||
context.clearSelection();
|
||||
}
|
||||
|
||||
context.setItemSelect(item, !isSelected);
|
||||
context.setItemSelect(item, !isSelected);
|
||||
}
|
||||
|
||||
if (onClick) {
|
||||
onClick();
|
||||
}
|
||||
},
|
||||
[context, item, onClick]
|
||||
[context, item, selectDisabled, onClick]
|
||||
);
|
||||
const handleDoubleClick = useCallback((e: React.MouseEvent<HTMLTableRowElement>) => {
|
||||
if (onDoubleClick) {
|
||||
|
||||
@@ -10,6 +10,7 @@ import { createContext } from 'react';
|
||||
|
||||
export interface ITableItemContext {
|
||||
item: any;
|
||||
selectDisabled: boolean;
|
||||
isSelected(): boolean;
|
||||
isExpanded(): boolean;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,6 @@ export const TableItemSelect = observer(function TableItemSelect({ disabled, cla
|
||||
}, [tableContext, context]);
|
||||
|
||||
return styled(useStyles())(
|
||||
<input type='checkbox' checked={context.isSelected()} onClick={handleClick} className={className} disabled={disabled}/>
|
||||
<input type='checkbox' checked={context.isSelected()} onClick={handleClick} className={className} disabled={context.selectDisabled || disabled}/>
|
||||
);
|
||||
});
|
||||
|
||||
+44
-61
@@ -32,16 +32,12 @@ const styles = composes(
|
||||
composes: theme-ripple theme-background-secondary theme-text-on-secondary from global;
|
||||
}
|
||||
|
||||
TabList {
|
||||
composes: theme-border-color-background from global;
|
||||
}
|
||||
|
||||
ErrorMessage {
|
||||
composes: theme-background-secondary from global;
|
||||
}
|
||||
|
||||
SubmittingForm {
|
||||
composes: theme-background-secondary from global;
|
||||
content-box {
|
||||
composes: theme-background-secondary theme-border-color-background from global;
|
||||
}
|
||||
|
||||
GrantedSubjects {
|
||||
@@ -49,18 +45,14 @@ const styles = composes(
|
||||
}
|
||||
`,
|
||||
css`
|
||||
custom-connection {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
content-box {
|
||||
margin: 0 24px;
|
||||
margin-bottom: 16px;
|
||||
border: solid 1px;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
CommonDialogWrapper {
|
||||
max-height: 500px;
|
||||
min-height: 500px;
|
||||
}
|
||||
|
||||
SubmittingForm, BaseTabPanel {
|
||||
SubmittingForm {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -73,7 +65,6 @@ const styles = composes(
|
||||
width: 100%;
|
||||
padding-left: 24px;
|
||||
outline: none;
|
||||
border-bottom: solid 1px;
|
||||
}
|
||||
|
||||
Tab {
|
||||
@@ -96,21 +87,11 @@ const styles = composes(
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
connection-form[|new] {
|
||||
border-left: solid 3px;
|
||||
}
|
||||
|
||||
SubmittingForm, Loader {
|
||||
min-height: 320px;
|
||||
max-height: 500px;
|
||||
}
|
||||
|
||||
IconButton {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
Button:not(:first-child) {
|
||||
margin-right: 24px;
|
||||
}
|
||||
@@ -169,42 +150,44 @@ export const ConnectionEdit = observer(function ConnectionEdit({
|
||||
{translate(controller.isNew ? 'ui_processing_create' : 'ui_processing_save')}
|
||||
</Button>
|
||||
</TabList>
|
||||
{controller.isLoading
|
||||
? <Loader />
|
||||
: (
|
||||
<SubmittingForm onSubmit={controller.onSaveConnection}>
|
||||
<TabPanel tabId='options'>
|
||||
<ConnectionForm controller={controller} />
|
||||
</TabPanel>
|
||||
{controller.driver && (
|
||||
<TabPanel tabId='driver_properties'>
|
||||
<DriverProperties
|
||||
driver={controller.driver}
|
||||
state={controller.config.properties!}
|
||||
loadProperties={loadProperties}
|
||||
<content-box as="div">
|
||||
{controller.isLoading
|
||||
? <Loader />
|
||||
: (
|
||||
<SubmittingForm onSubmit={controller.onSaveConnection}>
|
||||
<TabPanel tabId='options'>
|
||||
<ConnectionForm controller={controller} />
|
||||
</TabPanel>
|
||||
{controller.driver && (
|
||||
<TabPanel tabId='driver_properties'>
|
||||
<DriverProperties
|
||||
driver={controller.driver}
|
||||
state={controller.config.properties!}
|
||||
loadProperties={loadProperties}
|
||||
/>
|
||||
</TabPanel>
|
||||
)}
|
||||
<TabPanel tabId='access'>
|
||||
<GrantedSubjects
|
||||
grantedSubjects={controller.grantedSubjects}
|
||||
users={controller.users}
|
||||
roles={controller.roles}
|
||||
selectedSubjects={controller.selectedSubjects}
|
||||
disabled={controller.isLoading || controller.isSaving}
|
||||
onChange={controller.handleAccessChange}
|
||||
/>
|
||||
</TabPanel>
|
||||
)}
|
||||
<TabPanel tabId='access'>
|
||||
<GrantedSubjects
|
||||
grantedSubjects={controller.grantedSubjects}
|
||||
users={controller.users}
|
||||
roles={controller.roles}
|
||||
selectedSubjects={controller.selectedSubjects}
|
||||
disabled={controller.isLoading}
|
||||
onChange={controller.handleAccessChange}
|
||||
/>
|
||||
</TabPanel>
|
||||
</SubmittingForm>
|
||||
)
|
||||
}
|
||||
{controller.error.responseMessage && (
|
||||
<ErrorMessage
|
||||
text={controller.error.responseMessage}
|
||||
hasDetails={controller.error.hasDetails}
|
||||
onShowDetails={controller.onShowDetails}
|
||||
/>
|
||||
)}
|
||||
</SubmittingForm>
|
||||
)
|
||||
}
|
||||
{controller.error.responseMessage && (
|
||||
<ErrorMessage
|
||||
text={controller.error.responseMessage}
|
||||
hasDetails={controller.error.hasDetails}
|
||||
onShowDetails={controller.onShowDetails}
|
||||
/>
|
||||
)}
|
||||
</content-box>
|
||||
</TabsState>
|
||||
);
|
||||
});
|
||||
|
||||
+4
-8
@@ -67,10 +67,8 @@ export const GrantedSubjects = observer(function GrantedSubjects({
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{roles.map(role => (
|
||||
<TableItem key={role.roleId} item={role.roleId}>
|
||||
<TableColumnValue centerContent flex>
|
||||
<TableItemSelect disabled={disabled}/>
|
||||
</TableColumnValue>
|
||||
<TableItem key={role.roleId} item={role.roleId} selectDisabled={disabled}>
|
||||
<TableColumnValue centerContent flex><TableItemSelect /></TableColumnValue>
|
||||
<TableColumnValue>{role.roleName}</TableColumnValue>
|
||||
<TableColumnValue></TableColumnValue>
|
||||
<TableColumnValue></TableColumnValue>
|
||||
@@ -81,10 +79,8 @@ export const GrantedSubjects = observer(function GrantedSubjects({
|
||||
const isRoleProvided = connectionPermission?.subjectType === AdminSubjectType.Role;
|
||||
|
||||
return (
|
||||
<TableItem key={user.userId} item={user.userId}>
|
||||
<TableColumnValue centerContent flex>
|
||||
<TableItemSelect disabled={disabled || isRoleProvided}/>
|
||||
</TableColumnValue>
|
||||
<TableItem key={user.userId} item={user.userId} selectDisabled={disabled || isRoleProvided}>
|
||||
<TableColumnValue centerContent flex><TableItemSelect /></TableColumnValue>
|
||||
<TableColumnValue>{user.userId}</TableColumnValue>
|
||||
<TableColumnValue>{isRoleProvided && user.grantedRoles.join(',')}</TableColumnValue>
|
||||
<TableColumnValue></TableColumnValue>
|
||||
|
||||
+2
-4
@@ -76,10 +76,8 @@ export const GrantedConnections = observer(function GrantedConnections({
|
||||
const isRoleProvided = connectionPermission?.subjectType === AdminSubjectType.Role;
|
||||
|
||||
return (
|
||||
<TableItem key={connection.id} item={connection.id}>
|
||||
<TableColumnValue centerContent flex>
|
||||
<TableItemSelect disabled={disabled || isRoleProvided}/>
|
||||
</TableColumnValue>
|
||||
<TableItem key={connection.id} item={connection.id} selectDisabled={disabled || isRoleProvided}>
|
||||
<TableColumnValue centerContent flex><TableItemSelect /></TableColumnValue>
|
||||
<TableColumnValue><StaticImage icon={driver?.icon} /></TableColumnValue>
|
||||
<TableColumnValue>{connection.name}</TableColumnValue>
|
||||
<TableColumnValue>{isRoleProvided && connectionPermission?.subjectId}</TableColumnValue>
|
||||
|
||||
+95
-112
@@ -34,35 +34,27 @@ const styles = composes(
|
||||
composes: theme-ripple theme-background-secondary theme-text-on-secondary from global;
|
||||
}
|
||||
|
||||
TabList {
|
||||
composes: theme-border-color-background from global;
|
||||
}
|
||||
|
||||
ErrorMessage {
|
||||
composes: theme-background-secondary from global;
|
||||
}
|
||||
|
||||
content-box {
|
||||
composes: theme-background-secondary theme-border-color-background from global;
|
||||
}
|
||||
|
||||
GrantedConnections {
|
||||
composes: theme-background-surface from global;
|
||||
}
|
||||
|
||||
SubmittingForm, Loader {
|
||||
composes: theme-background-secondary from global;
|
||||
}
|
||||
`,
|
||||
css`
|
||||
custom-connection {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
content-box {
|
||||
margin: 0 24px;
|
||||
margin-bottom: 16px;
|
||||
border: solid 1px;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
CommonDialogWrapper {
|
||||
max-height: 500px;
|
||||
min-height: 500px;
|
||||
}
|
||||
|
||||
SubmittingForm, BaseTabPanel {
|
||||
SubmittingForm {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -75,7 +67,6 @@ const styles = composes(
|
||||
width: 100%;
|
||||
padding-left: 24px;
|
||||
outline: none;
|
||||
border-bottom: solid 1px;
|
||||
}
|
||||
|
||||
Tab {
|
||||
@@ -98,21 +89,11 @@ const styles = composes(
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
connection-form[|new] {
|
||||
border-left: solid 3px;
|
||||
}
|
||||
|
||||
SubmittingForm, Loader {
|
||||
min-height: 320px;
|
||||
max-height: 500px;
|
||||
}
|
||||
|
||||
IconButton {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
Button:not(:first-child) {
|
||||
margin-right: 24px;
|
||||
}
|
||||
@@ -190,93 +171,95 @@ export const UserEdit = observer(function UserEdit({
|
||||
{translate(controller.isNew ? 'ui_processing_create' : 'ui_processing_save')}
|
||||
</Button>
|
||||
</TabList>
|
||||
{controller.isLoading
|
||||
? <Loader />
|
||||
: (
|
||||
<SubmittingForm onSubmit={controller.save} ref={focusedRef as React.RefObject<HTMLFormElement>}>
|
||||
<TabPanel tabId='info'>
|
||||
<layout-grid as="div">
|
||||
<layout-grid-inner as="div">
|
||||
<layout-grid-cell as='div' {...use({ 'span-tablet': 12, 'span-desktop': 5 })}>
|
||||
<group as="div">
|
||||
<InputGroup>{translate('authentication_user_credentials')}</InputGroup>
|
||||
</group>
|
||||
<group as="div">
|
||||
<InputField
|
||||
type='text'
|
||||
name='login'
|
||||
value={controller.credentials.login}
|
||||
onChange={handleLoginChange}
|
||||
disabled={!controller.isNew || controller.isSaving}
|
||||
mod='surface'
|
||||
>
|
||||
{translate('authentication_user_name')}
|
||||
</InputField>
|
||||
</group>
|
||||
<group as="div">
|
||||
<InputField
|
||||
type='password'
|
||||
name='password'
|
||||
value={controller.credentials.password}
|
||||
onChange={handlePasswordChange}
|
||||
disabled={controller.isSaving}
|
||||
mod='surface'
|
||||
>
|
||||
{translate('authentication_user_password')}
|
||||
</InputField>
|
||||
</group>
|
||||
<group as="div">
|
||||
<InputField
|
||||
type='password'
|
||||
name='password_repeat'
|
||||
value={controller.credentials.passwordRepeat}
|
||||
onChange={handlePasswordRepeatChange}
|
||||
disabled={controller.isSaving}
|
||||
mod='surface'
|
||||
>
|
||||
{translate('authentication_user_password_repeat')}
|
||||
</InputField>
|
||||
</group>
|
||||
</layout-grid-cell>
|
||||
<layout-grid-cell as='div' {...use({ 'span-tablet': 12, 'span-desktop': 5 })}>
|
||||
<group as="div">
|
||||
<InputGroup>{translate('authentication_user_role')}</InputGroup>
|
||||
</group>
|
||||
{controller.roles.map((role, i) => (
|
||||
<group as="div" key={role.roleId}>
|
||||
<Checkbox
|
||||
value={role.roleId}
|
||||
name='role'
|
||||
checkboxLabel={role.roleName || role.roleId}
|
||||
onChange={checked => handleRoleChange(role.roleId, checked)}
|
||||
checked={controller.credentials.roles.get(role.roleId)}
|
||||
<content-box as='div'>
|
||||
{controller.isLoading
|
||||
? <Loader />
|
||||
: (
|
||||
<SubmittingForm onSubmit={controller.save} ref={focusedRef as React.RefObject<HTMLFormElement>}>
|
||||
<TabPanel tabId='info'>
|
||||
<layout-grid as="div">
|
||||
<layout-grid-inner as="div">
|
||||
<layout-grid-cell as='div' {...use({ 'span-tablet': 12, 'span-desktop': 5 })}>
|
||||
<group as="div">
|
||||
<InputGroup>{translate('authentication_user_credentials')}</InputGroup>
|
||||
</group>
|
||||
<group as="div">
|
||||
<InputField
|
||||
type='text'
|
||||
name='login'
|
||||
value={controller.credentials.login}
|
||||
onChange={handleLoginChange}
|
||||
disabled={!controller.isNew || controller.isSaving}
|
||||
mod='surface'
|
||||
>
|
||||
{translate('authentication_user_name')}
|
||||
</InputField>
|
||||
</group>
|
||||
<group as="div">
|
||||
<InputField
|
||||
type='password'
|
||||
name='password'
|
||||
value={controller.credentials.password}
|
||||
onChange={handlePasswordChange}
|
||||
disabled={controller.isSaving}
|
||||
mod='surface'
|
||||
/>
|
||||
>
|
||||
{translate('authentication_user_password')}
|
||||
</InputField>
|
||||
</group>
|
||||
))}
|
||||
</layout-grid-cell>
|
||||
</layout-grid-inner>
|
||||
</layout-grid>
|
||||
</TabPanel>
|
||||
<TabPanel tabId='connections_access'>
|
||||
<GrantedConnections
|
||||
grantedConnections={controller.grantedConnections}
|
||||
connections={controller.connections}
|
||||
selectedConnection={controller.selectedConnections}
|
||||
disabled={controller.isLoading}
|
||||
onChange={controller.handleConnectionsAccessChange}
|
||||
/>
|
||||
</TabPanel>
|
||||
</SubmittingForm>
|
||||
<group as="div">
|
||||
<InputField
|
||||
type='password'
|
||||
name='password_repeat'
|
||||
value={controller.credentials.passwordRepeat}
|
||||
onChange={handlePasswordRepeatChange}
|
||||
disabled={controller.isSaving}
|
||||
mod='surface'
|
||||
>
|
||||
{translate('authentication_user_password_repeat')}
|
||||
</InputField>
|
||||
</group>
|
||||
</layout-grid-cell>
|
||||
<layout-grid-cell as='div' {...use({ 'span-tablet': 12, 'span-desktop': 5 })}>
|
||||
<group as="div">
|
||||
<InputGroup>{translate('authentication_user_role')}</InputGroup>
|
||||
</group>
|
||||
{controller.roles.map((role, i) => (
|
||||
<group as="div" key={role.roleId}>
|
||||
<Checkbox
|
||||
value={role.roleId}
|
||||
name='role'
|
||||
checkboxLabel={role.roleName || role.roleId}
|
||||
onChange={checked => handleRoleChange(role.roleId, checked)}
|
||||
checked={controller.credentials.roles.get(role.roleId)}
|
||||
disabled={controller.isSaving}
|
||||
mod='surface'
|
||||
/>
|
||||
</group>
|
||||
))}
|
||||
</layout-grid-cell>
|
||||
</layout-grid-inner>
|
||||
</layout-grid>
|
||||
</TabPanel>
|
||||
<TabPanel tabId='connections_access'>
|
||||
<GrantedConnections
|
||||
grantedConnections={controller.grantedConnections}
|
||||
connections={controller.connections}
|
||||
selectedConnection={controller.selectedConnections}
|
||||
disabled={controller.isLoading}
|
||||
onChange={controller.handleConnectionsAccessChange}
|
||||
/>
|
||||
</TabPanel>
|
||||
</SubmittingForm>
|
||||
)}
|
||||
{controller.error.responseMessage && (
|
||||
<ErrorMessage
|
||||
text={controller.error.responseMessage}
|
||||
hasDetails={controller.error.hasDetails}
|
||||
onShowDetails={controller.showDetails}
|
||||
/>
|
||||
)}
|
||||
{controller.error.responseMessage && (
|
||||
<ErrorMessage
|
||||
text={controller.error.responseMessage}
|
||||
hasDetails={controller.error.hasDetails}
|
||||
onShowDetails={controller.showDetails}
|
||||
/>
|
||||
)}
|
||||
</content-box>
|
||||
</TabsState>
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user