You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@answer.apache.org by sh...@apache.org on 2024/01/26 02:46:08 UTC
(incubator-answer) branch test updated: fix: admin theme primary-color add reset btn
This is an automated email from the ASF dual-hosted git repository.
shuai pushed a commit to branch test
in repository https://gitbox.apache.org/repos/asf/incubator-answer.git
The following commit(s) were added to refs/heads/test by this push:
new 0bac1c14 fix: admin theme primary-color add reset btn
0bac1c14 is described below
commit 0bac1c1436882239713018d15045c920ec4bcc4f
Author: shuai <li...@sifou.com>
AuthorDate: Fri Jan 26 10:45:57 2024 +0800
fix: admin theme primary-color add reset btn
---
i18n/en_US.yaml | 1 +
ui/src/components/SchemaForm/components/Button.tsx | 50 +++++++++++-
ui/src/components/SchemaForm/components/Input.tsx | 2 +-
.../SchemaForm/components/InputGroup.tsx | 90 ++++++++++++++++++++++
ui/src/components/SchemaForm/components/index.ts | 2 +
ui/src/components/SchemaForm/index.tsx | 28 +++++++
ui/src/components/SchemaForm/types.ts | 18 ++++-
ui/src/pages/Admin/Themes/index.tsx | 18 +++++
8 files changed, 203 insertions(+), 6 deletions(-)
diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml
index 2ea52dcb..e155edff 100644
--- a/i18n/en_US.yaml
+++ b/i18n/en_US.yaml
@@ -1157,6 +1157,7 @@ ui:
dark: Dark
system_setting: System setting
default: Default
+ reset: Reset
search:
title: Search Results
keywords: Keywords
diff --git a/ui/src/components/SchemaForm/components/Button.tsx b/ui/src/components/SchemaForm/components/Button.tsx
index 38bad913..0371992f 100644
--- a/ui/src/components/SchemaForm/components/Button.tsx
+++ b/ui/src/components/SchemaForm/components/Button.tsx
@@ -17,31 +17,43 @@
* under the License.
*/
-import React, { FC, useLayoutEffect, useState } from 'react';
+import { FC, useEffect, useState } from 'react';
import { Button, ButtonProps, Spinner } from 'react-bootstrap';
import { request } from '@/utils';
import type { UIAction, FormKit } from '../types';
import { useToast } from '@/hooks';
+import { Icon } from '@/components';
interface Props {
fieldName: string;
text: string;
action: UIAction | undefined;
+ actionType?: 'submit' | 'click';
+ clickCallback?: () => void;
formKit: FormKit;
readOnly: boolean;
variant?: ButtonProps['variant'];
size?: ButtonProps['size'];
+ iconName?: string;
+ nowrap?: boolean;
+ title?: string;
}
const Index: FC<Props> = ({
fieldName,
action,
+ actionType = 'submit',
formKit,
text = '',
readOnly = false,
variant = 'primary',
size,
+ iconName = '',
+ nowrap = false,
+ clickCallback,
+ title,
}) => {
+ console.log('Button.tsx: action:', title);
const Toast = useToast();
const [isLoading, setLoading] = useState(false);
const handleToast = (msg, type: 'success' | 'danger' = 'success') => {
@@ -62,6 +74,12 @@ const Index: FC<Props> = ({
}
};
const handleAction = () => {
+ if (actionType === 'click') {
+ if (typeof clickCallback === 'function') {
+ clickCallback();
+ }
+ return;
+ }
if (!action) {
return;
}
@@ -87,13 +105,39 @@ const Index: FC<Props> = ({
setLoading(false);
});
};
- useLayoutEffect(() => {
+ useEffect(() => {
if (action?.loading?.state === 'pending') {
setLoading(true);
}
}, []);
const loadingText = action?.loading?.text || text;
const disabled = isLoading || readOnly;
+ if (nowrap) {
+ return (
+ <Button
+ name={fieldName}
+ onClick={handleAction}
+ disabled={disabled}
+ size={size}
+ title={title}
+ variant={variant}>
+ {isLoading ? (
+ <>
+ <Spinner
+ className="align-middle me-2"
+ animation="border"
+ size="sm"
+ variant={variant}
+ />
+ {loadingText}
+ </>
+ ) : (
+ text
+ )}
+ {iconName && <Icon name={iconName} />}
+ </Button>
+ );
+ }
return (
<div className="d-flex">
@@ -102,6 +146,7 @@ const Index: FC<Props> = ({
onClick={handleAction}
disabled={disabled}
size={size}
+ title={title}
variant={variant}>
{isLoading ? (
<>
@@ -116,6 +161,7 @@ const Index: FC<Props> = ({
) : (
text
)}
+ {iconName && <Icon name={iconName} />}
</Button>
</div>
);
diff --git a/ui/src/components/SchemaForm/components/Input.tsx b/ui/src/components/SchemaForm/components/Input.tsx
index 97229d13..1a3fe319 100644
--- a/ui/src/components/SchemaForm/components/Input.tsx
+++ b/ui/src/components/SchemaForm/components/Input.tsx
@@ -63,7 +63,7 @@ const Index: FC<Props> = ({
onChange={handleChange}
disabled={readOnly}
isInvalid={fieldObject?.isInvalid}
- style={type === 'color' ? { width: '6rem' } : {}}
+ style={type === 'color' ? { width: '100px', flex: 'none' } : {}}
/>
);
};
diff --git a/ui/src/components/SchemaForm/components/InputGroup.tsx b/ui/src/components/SchemaForm/components/InputGroup.tsx
new file mode 100644
index 00000000..88cb0388
--- /dev/null
+++ b/ui/src/components/SchemaForm/components/InputGroup.tsx
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+import { FC } from 'react';
+import { InputGroup } from 'react-bootstrap';
+
+import type { FormKit, InputGroupOptions } from '../types';
+
+import Button from './Button';
+
+interface Props {
+ formKitWithContext: FormKit;
+ uiOpt: InputGroupOptions;
+ prefixText?: string;
+ suffixText?: string;
+ children: React.ReactNode;
+}
+
+const InputGroupBtn = ({
+ formKitWithContext,
+ uiOpt,
+}: {
+ formKitWithContext: FormKit;
+ uiOpt:
+ | InputGroupOptions['prefixBtnOptions']
+ | InputGroupOptions['suffixBtnOptions'];
+}) => {
+ return (
+ <Button
+ fieldName="1"
+ text={String(uiOpt?.text)}
+ iconName={uiOpt?.iconName ? uiOpt?.iconName : ''}
+ action={uiOpt?.action ? uiOpt?.action : undefined}
+ actionType="click"
+ clickCallback={uiOpt?.clickCallback ? uiOpt?.clickCallback : undefined}
+ formKit={formKitWithContext}
+ variant={uiOpt?.variant ? uiOpt.variant : undefined}
+ size={uiOpt?.size ? uiOpt?.size : undefined}
+ title={uiOpt?.title ? uiOpt?.title : ''}
+ nowrap
+ readOnly={false}
+ />
+ );
+};
+
+const Index: FC<Props> = ({
+ formKitWithContext,
+ uiOpt,
+ prefixText = null,
+ suffixText = null,
+ children,
+}) => {
+ return (
+ <InputGroup>
+ {prefixText && <InputGroup.Text>{prefixText}</InputGroup.Text>}
+ {uiOpt && 'prefixBtnOptions' in uiOpt && (
+ <InputGroupBtn
+ uiOpt={uiOpt.prefixBtnOptions}
+ formKitWithContext={formKitWithContext}
+ />
+ )}
+ {children}
+ {uiOpt && 'suffixBtnOptions' in uiOpt && (
+ <InputGroupBtn
+ uiOpt={uiOpt.suffixBtnOptions}
+ formKitWithContext={formKitWithContext}
+ />
+ )}
+ {suffixText ? <InputGroup.Text>{suffixText}</InputGroup.Text> : null}
+ </InputGroup>
+ );
+};
+
+export default Index;
diff --git a/ui/src/components/SchemaForm/components/index.ts b/ui/src/components/SchemaForm/components/index.ts
index 4e74be30..df28f4ac 100644
--- a/ui/src/components/SchemaForm/components/index.ts
+++ b/ui/src/components/SchemaForm/components/index.ts
@@ -26,6 +26,7 @@ import Upload from './Upload';
import Textarea from './Textarea';
import Input from './Input';
import Button from './Button';
+import InputGroup from './InputGroup';
export {
Legend,
@@ -37,4 +38,5 @@ export {
Textarea,
Input,
Button,
+ InputGroup,
};
diff --git a/ui/src/components/SchemaForm/index.tsx b/ui/src/components/SchemaForm/index.tsx
index e3464bc9..c90abee7 100644
--- a/ui/src/components/SchemaForm/index.tsx
+++ b/ui/src/components/SchemaForm/index.tsx
@@ -37,6 +37,7 @@ import type {
FormRef,
BaseUIOptions,
FormKit,
+ InputGroupOptions,
} from './types';
import {
Legend,
@@ -48,6 +49,7 @@ import {
Textarea,
Input,
Button as SfButton,
+ InputGroup,
} from './components';
export * from './types';
@@ -377,8 +379,33 @@ const SchemaForm: ForwardRefRenderFunction<FormRef, FormProps> = (
uiOpt && 'variant' in uiOpt ? uiOpt.variant : undefined
}
size={uiOpt && 'size' in uiOpt ? uiOpt.size : undefined}
+ title={uiOpt && 'title' in uiOpt ? uiOpt?.title : ''}
/>
) : null}
+ {widget === 'input_group' ? (
+ <InputGroup
+ formKitWithContext={formKitWithContext}
+ uiOpt={uiOpt as InputGroupOptions}
+ prefixText={
+ (uiOpt && 'prefixText' in uiOpt && uiOpt.prefixText) || ''
+ }
+ suffixText={
+ (uiOpt && 'suffixText' in uiOpt && uiOpt.suffixText) || ''
+ }>
+ <Input
+ type={
+ uiOpt && 'inputType' in uiOpt ? uiOpt.inputType : 'text'
+ }
+ placeholder={
+ uiOpt && 'placeholder' in uiOpt ? uiOpt.placeholder : ''
+ }
+ fieldName={key}
+ onChange={onChange}
+ formData={formData}
+ readOnly={readOnly}
+ />
+ </InputGroup>
+ ) : null}
{/* Unified handling of `Feedback` and `Text` */}
<Form.Control.Feedback type="invalid">
{fieldState?.errorMsg}
@@ -397,6 +424,7 @@ const SchemaForm: ForwardRefRenderFunction<FormRef, FormProps> = (
</Form>
);
};
+
export const initFormData = (schema: JSONSchema): Type.FormDataType => {
const formData: Type.FormDataType = {};
const props: JSONSchema['properties'] = schema?.properties || {};
diff --git a/ui/src/components/SchemaForm/types.ts b/ui/src/components/SchemaForm/types.ts
index 69cbe617..794761a0 100644
--- a/ui/src/components/SchemaForm/types.ts
+++ b/ui/src/components/SchemaForm/types.ts
@@ -112,10 +112,20 @@ export interface TextareaOptions extends BaseUIOptions {
export interface ButtonOptions extends BaseUIOptions {
text: string;
- icon?: string;
+ iconName?: string;
action?: UIAction;
+ actionType: 'click' | 'submit';
variant?: ButtonProps['variant'];
size?: ButtonProps['size'];
+ title?: string;
+ clickCallback?: () => void;
+}
+
+export interface InputGroupOptions extends InputOptions {
+ prefixText?: string;
+ suffixText?: string;
+ prefixBtnOptions?: ButtonOptions;
+ suffixBtnOptions?: ButtonOptions;
}
export type UIOptions =
@@ -127,7 +137,8 @@ export type UIOptions =
| CheckboxOptions
| RadioOptions
| TextareaOptions
- | ButtonOptions;
+ | ButtonOptions
+ | InputGroupOptions;
export type UIWidget =
| 'textarea'
@@ -139,7 +150,8 @@ export type UIWidget =
| 'timezone'
| 'switch'
| 'legend'
- | 'button';
+ | 'button'
+ | 'input_group';
export interface UISchema {
[key: string]: {
'ui:widget'?: UIWidget;
diff --git a/ui/src/pages/Admin/Themes/index.tsx b/ui/src/pages/Admin/Themes/index.tsx
index 990f5e54..346e2e05 100644
--- a/ui/src/pages/Admin/Themes/index.tsx
+++ b/ui/src/pages/Admin/Themes/index.tsx
@@ -82,13 +82,31 @@ const Index: FC = () => {
'ui:widget': 'select',
},
primary_color: {
+ 'ui:widget': 'input_group',
'ui:options': {
inputType: 'color',
+ suffixBtnOptions: {
+ text: '',
+ variant: 'outline-secondary',
+ iconName: 'arrow-counterclockwise',
+ actionType: 'click',
+ title: t('reset', { keyPrefix: 'btns' }),
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
+ clickCallback: () => resetPrimaryScheme(),
+ },
},
},
};
+
const [formData, setFormData] = useState(initFormData(schema));
const { update: updateThemeSetting } = themeSettingStore((_) => _);
+
+ const resetPrimaryScheme = () => {
+ const formMeta = { ...formData };
+ formMeta.primary_color.value = '#0033FF';
+ setFormData({ ...formMeta });
+ };
+
const onSubmit = (evt) => {
evt.preventDefault();
evt.stopPropagation();