feat: pp-48

This commit is contained in:
zhaisifeng 2023-10-31 15:40:53 +08:00
parent 92309b881a
commit 18f5ca2174
35 changed files with 896 additions and 152 deletions

View File

@ -175,6 +175,7 @@
"rc-pagination": "^3.1.3",
"rc-select": "^14.1.9",
"rc-tree-select": "^5.4.0",
"rc-trigger": "^5.3.4",
"re-reselect": "^3.4.0",
"react": "^17.0.2",
"react-append-to-body": "^2.0.26",
@ -186,6 +187,7 @@
"react-dnd-touch-backend": "11.1.3",
"react-documents": "^1.0.4",
"react-dom": "^17.0.2",
"react-draggable": "4.4.4",
"react-full-screen": "^1.1.0",
"react-fusioncharts": "^3.1.2",
"react-google-recaptcha": "^2.1.0",
@ -203,6 +205,7 @@
"react-qr-barcode-scanner": "^1.0.6",
"react-rating": "^2.0.5",
"react-redux": "^7.2.4",
"react-resizable": "^3.0.5",
"react-responsive": "^9.0.0-beta.3",
"react-router": "^5.1.2",
"react-router-dom": "^5.1.2",
@ -291,6 +294,7 @@
"@types/react-instantsearch-dom": "^6.3.0",
"@types/react-modal": "^3.13.1",
"@types/react-redux": "^7.0.1",
"@types/react-resizable": "^3.0.4",
"@types/react-router-dom": "^5.1.2",
"@types/react-select": "^3.0.5",
"@types/react-syntax-highlighter": "^13.5.2",

View File

@ -0,0 +1,39 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_10206_8528)">
<path
d="M3.56425 5.99545C4.0514 5.58124 4.5856 5.16267 5.13731 4.79883C4.71838 6.18226 4.63909 9.1593 7.82282 9.66045C10.2135 10.0369 10.8169 10.7953 10.5369 14.5803C10.0446 14.8124 9.55603 15.0052 9.05664 15.1841C9.37272 13.615 9.72202 10.8004 7.44343 10.3418C4.66708 9.78317 3.22595 9.41656 3.56425 5.99545Z"
fill="#13C2C2" />
<path
d="M5.51585 4.55116C5.98893 4.25067 6.45682 3.99026 6.98217 3.70898C6.44126 6.24269 6.62223 8.44001 9.58863 8.90341C11.3452 9.17798 12.7082 9.81327 12.3562 13.5829C11.8902 13.8811 11.4638 14.1132 10.9912 14.3622C11.2514 12.8579 11.2582 9.82114 9.17777 9.50093C6.05006 9.01904 5.10383 8.16462 5.51585 4.55116Z"
fill="#13C2C2" />
<path
d="M7.41954 3.49866C7.91203 3.27836 8.60022 2.98375 8.87264 2.9082C8.33547 4.81372 8.60868 7.82884 11.0525 8.22933C13.3379 8.6042 14.3883 9.8795 14.1465 12.3074C13.6816 12.6752 13.2546 12.9903 12.7798 13.3093C13.1845 10.9727 12.3158 8.98461 10.7004 8.75012C7.23109 8.2466 6.84265 6.79467 7.41954 3.49866Z"
fill="#13C2C2" />
<path
d="M2.84769 6.66992C0.595256 8.79687 -0.612011 11.6374 0.313204 13.7034C1.368 16.0581 5.2333 16.49 8.23603 15.4283C8.87373 12.6464 9.19746 11.1012 6.6425 10.6095C2.92083 9.8928 2.87716 8.41966 2.84769 6.66992Z"
fill="#13C2C2" />
<mask id="mask0_10206_8528" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="9" y="2" width="9"
height="10">
<path d="M9.27148 2.11719H18V11.5276H9.27148V2.11719Z" fill="white" />
</mask>
<g mask="url(#mask0_10206_8528)">
<path
d="M15.0078 11.5276C17.212 9.37317 18.7393 6.44183 17.6282 4.26923C16.3726 1.81341 12.4061 1.74577 9.6932 2.65013C8.89542 4.82351 9.11518 7.53023 11.3494 7.85516C14.5938 8.3268 14.723 9.68552 15.0078 11.5276Z"
fill="#13C2C2" />
</g>
<path
d="M3.56425 5.99389C4.0514 5.57968 4.5856 5.16111 5.13731 4.79688C4.71838 6.18074 4.63909 9.15735 7.82282 9.65853C10.2135 10.035 10.8169 10.7938 10.5369 14.5784C10.0446 14.8109 9.55603 15.0036 9.05664 15.1826C9.37272 13.6134 9.72202 10.7989 7.44343 10.3402C4.66708 9.78161 3.22595 9.41504 3.56425 5.99389Z"
fill="#13C2C2" />
<path
d="M5.51585 4.54964C5.98893 4.24872 6.45682 3.98869 6.98217 3.70703C6.44126 6.24113 6.62223 8.43848 9.58863 8.90189C11.3452 9.17642 12.7082 9.8117 12.3562 13.5813C11.8902 13.8796 11.4638 14.1116 10.9912 14.3606C11.2514 12.8564 11.2582 9.81958 9.17777 9.49901C6.05006 9.01752 5.10383 8.16313 5.51585 4.54964Z"
fill="#13C2C2" />
<path
d="M7.41954 3.49905C7.91203 3.2784 8.60022 2.98372 8.87264 2.9082C8.33547 4.81411 8.60868 7.82923 11.0525 8.22972C13.3379 8.6042 14.3883 9.87989 14.1465 12.3078C13.6816 12.6751 13.2546 12.9903 12.7798 13.3093C13.1845 10.973 12.3158 8.985 10.7004 8.75016C7.23109 8.24664 6.84265 6.7951 7.41954 3.49905Z"
fill="#13C2C2" />
</g>
<defs>
<clipPath id="clip0_10206_8528">
<rect width="18" height="18" fill="white" />
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -0,0 +1,8 @@
<svg width="16" height="18" viewBox="0 0 16 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.79439 17.4226L0.5 13.2109V4.78915L7.79439 0.577363L15.0888 4.78915V13.2109L7.79439 17.4226Z"
stroke="#13C2C2" />
<path
d="M7.78956 3.00586L2.61328 5.99426V8.98169L5.20239 7.48701V13.5044L7.78956 14.9962V5.99329L10.3777 4.49958L7.78956 3.00586Z"
fill="#13C2C2" />
<path d="M10.3926 7.50145V13.4995L12.9914 12V6L10.3926 7.50145Z" fill="#13C2C2" />
</svg>

After

Width:  |  Height:  |  Size: 497 B

View File

@ -21,6 +21,7 @@ export interface INJECTED_CONFIGS {
fusioncharts: {
licenseKey: string;
};
enableWeChatOAuth: boolean;
enableMixpanel: boolean;
google: string;
enableTNCPP: boolean;
@ -75,6 +76,9 @@ export const getConfigsFromEnvVars = (): INJECTED_CONFIGS => {
fusioncharts: {
licenseKey: process.env.REACT_APP_FUSIONCHARTS_LICENSE_KEY || "",
},
enableWeChatOAuth: process.env.APPSMITH_WX_CLIENT_ID
? process.env.APPSMITH_WX_CLIENT_SECRET.length > 0
: false,
enableMixpanel: process.env.REACT_APP_SEGMENT_KEY
? process.env.REACT_APP_SEGMENT_KEY.length > 0
: false,
@ -244,6 +248,10 @@ export const getAppsmithConfigs = (): AppsmithUIConfigs => {
ENV_CONFIG.enableRapidAPI ||
APPSMITH_FEATURE_CONFIGS?.enableRapidAPI ||
false,
enableWeChatOAuth:
ENV_CONFIG.enableWeChatOAuth ||
APPSMITH_FEATURE_CONFIGS?.enableWeChatOAuth ||
false,
enableMixpanel:
ENV_CONFIG.enableMixpanel ||
APPSMITH_FEATURE_CONFIGS?.enableMixpanel ||

View File

@ -45,6 +45,7 @@ export interface AppsmithUIConfigs {
enableRapidAPI: boolean;
enableMixpanel: boolean;
enableTNCPP: boolean;
enableWeChatOAuth: boolean;
cloudHosting: boolean;

View File

@ -3,11 +3,13 @@ import {
GITHUB_SIGNUP_SETUP_DOC,
GOOGLE_SIGNUP_SETUP_DOC,
SIGNUP_RESTRICTION_DOC,
WX_SIGNUP_SETUP_DOC,
} from "constants/ThirdPartyConstants";
import type { AdminConfigType } from "@appsmith/pages/AdminSettings/config/types";
import {
CategoryType,
SettingCategories,
SettingSubCategories,
SettingSubtype,
SettingTypes,
} from "@appsmith/pages/AdminSettings/config/types";
@ -34,7 +36,11 @@ import {
import { isSAMLEnabled, isOIDCEnabled } from "@appsmith/utils/planHelpers";
import { selectFeatureFlags } from "@appsmith/selectors/featureFlagsSelectors";
import store from "store";
import WeChat from "assets/images/WeChat.svg";
import { getAppsmithConfigs } from "@appsmith/configs";
import { getWXLoginClientId } from "ce/selectors/settingsSelectors";
const { enableWeChatOAuth } = getAppsmithConfigs();
const featureFlags = selectFeatureFlags(store.getState());
const FormAuth: AdminConfigType = {
@ -192,6 +198,47 @@ const GithubAuth: AdminConfigType = {
],
};
const WeChatAuth: AdminConfigType = {
type: SettingCategories.WECHAT_AUTH,
controlType: SettingTypes.GROUP,
title: "微信登录",
subText: "让你可以微信账号进行登录",
canSave: true,
isConnected: enableWeChatOAuth,
categoryType: CategoryType.OTHER,
settings: [
{
id: "APPSMITH_OAUTH2_OIDC_READ_MORE",
category: SettingCategories.WECHAT_AUTH,
subCategory: SettingSubCategories.WECHAT,
controlType: SettingTypes.LINK,
label: "如何配置?",
url: WX_SIGNUP_SETUP_DOC,
},
{
id: "APPSMITH_WX_CLIENT_REDIRECT_URL",
category: SettingCategories.WECHAT_AUTH,
subCategory: SettingSubCategories.WECHAT,
controlType: SettingTypes.UNEDITABLEFIELD,
label: "Redirect URL",
fieldName: "oidc-redirect-url",
formName: "OidcRedirectUrl",
value: "/api/v1/wxLogin/callback",
helpText: "拷贝到你的认证服务器配置中",
forceHidden: true,
},
{
id: "APPSMITH_WX_CLIENT_SECRET",
category: SettingCategories.WECHAT_AUTH,
subCategory: SettingSubCategories.WECHAT,
controlType: SettingTypes.TEXTINPUT,
controlSubType: SettingSubtype.TEXT,
label: "Client Secret",
isRequired: true,
},
],
};
export const FormAuthCallout: AuthMethodType = {
id: "APPSMITH_FORM_LOGIN_AUTH",
category: SettingCategories.FORM_AUTH,
@ -238,17 +285,32 @@ export const OidcAuthCallout: AuthMethodType = {
isFeatureEnabled: isOIDCEnabled(featureFlags),
};
const WeChatCallout: AuthMethodType = {
id: "APPSMITH_WECHAT_AUTH",
category: SettingCategories.WECHAT_AUTH,
label: "微信",
subText: `允许使用 微信账号登录你的平台`,
image: WeChat,
isConnected: enableWeChatOAuth,
needsUpgrade: false,
isFeatureEnabled: false,
};
const AuthMethods = [
// OidcAuthCallout,
// SamlAuthCallout,
GoogleAuthCallout,
GithubAuthCallout,
FormAuthCallout,
WeChatCallout,
];
function AuthMain() {
const WXLoginClientId = useSelector(getWXLoginClientId);
FormAuthCallout.isConnected = useSelector(getIsFormLoginEnabled);
const socialLoginList = useSelector(getThirdPartyAuths);
WeChatAuth.isConnected = WeChatCallout.isConnected =
socialLoginList.includes("wechat") || !!WXLoginClientId;
GoogleAuth.isConnected = GoogleAuthCallout.isConnected =
socialLoginList.includes("google");
GithubAuth.isConnected = GithubAuthCallout.isConnected =
@ -263,6 +325,6 @@ export const config: AdminConfigType = {
controlType: SettingTypes.PAGE,
title: "身份认证",
canSave: false,
children: [FormAuth, GoogleAuth, GithubAuth],
children: [FormAuth, GoogleAuth, GithubAuth, WeChatAuth],
component: AuthMain,
};

View File

@ -49,6 +49,13 @@ export enum SettingSubtype {
PASSWORD = "password",
}
export const SettingSubCategories = {
GOOGLE: "google signup",
GITHUB: "github signup",
FORMLOGIN: "form login",
WECHAT: "微信登录",
};
export type Setting = ControlType & {
id: string;
category?: string;
@ -79,6 +86,7 @@ export type Setting = ControlType & {
calloutType?: CalloutKind;
advanced?: Setting[];
isRequired?: boolean;
forceHidden?: boolean;
formName?: string;
fieldName?: string;
dropdownOptions?: Partial<SelectOptionProps>[];
@ -116,6 +124,7 @@ export const SettingCategories = {
ACCESS_CONTROL: "access-control",
PROVISIONING: "provisioning",
BRANDING: "branding",
WECHAT_AUTH: "wechat-auth",
SAML_AUTH: "saml-auth",
OIDC_AUTH: "oidc-auth",
};

View File

@ -0,0 +1,4 @@
import type { AppState } from "@appsmith/reducers";
export const getWXLoginClientId = (state: AppState) =>
state.settings.config.APPSMITH_WX_CLIENT_ID;

View File

@ -1,32 +1,6 @@
import { tenantConfigConnection } from "@appsmith/constants/tenantConstants";
import { ADMIN_SETTINGS_CATEGORY_DEFAULT_PATH } from "constants/routes";
import type { User } from "constants/userConstants";
// const { disableLoginForm, enableGithubOAuth, enableGoogleOAuth } =
// getAppsmithConfigs();
/* settings is the updated & unsaved settings on Admin settings page */
// export const saveAllowed = (
// settings: any,
// isFormLoginEnabled: boolean,
// socialLoginList: string[],
// ) => {
// const connectedMethodsCount =
// socialLoginList.length + (isFormLoginEnabled ? 1 : 0);
// if (connectedMethodsCount === 1) {
// const checkFormLogin =
// !("APPSMITH_FORM_LOGIN_DISABLED" in settings) && isFormLoginEnabled,
// checkGoogleAuth =
// settings["APPSMITH_OAUTH2_GOOGLE_CLIENT_ID"] !== "" &&
// enableGoogleOAuth,
// checkGithubAuth =
// settings["APPSMITH_OAUTH2_GITHUB_CLIENT_ID"] !== "" &&
// enableGithubOAuth;
// return checkFormLogin || checkGoogleAuth || checkGithubAuth;
// } else {
// return connectedMethods.length >= 2;
// }
// };
/* settings is the updated & unsaved settings on Admin settings page */
export const saveAllowed = (
settings: any,
@ -37,15 +11,25 @@ export const saveAllowed = (
socialLoginList.length + (isFormLoginEnabled ? 1 : 0);
if (connectedMethodsCount === 1) {
const checkFormLogin =
!("APPSMITH_FORM_LOGIN_DISABLED" in settings) && isFormLoginEnabled,
!("APPSMITH_FORM_LOGIN_DISABLED" in settings) && isFormLoginEnabled,
checkGoogleAuth =
settings["APPSMITH_OAUTH2_GOOGLE_CLIENT_ID"] !== "" &&
socialLoginList.includes("google"),
checkGithubAuth =
settings["APPSMITH_OAUTH2_GITHUB_CLIENT_ID"] !== "" &&
socialLoginList.includes("github");
socialLoginList.includes("github"),
checkWeChatAuth =
settings["APPSMITH_WX_CLIENT_ID"] !== "" &&
socialLoginList.includes("wechat");
return (
checkFormLogin ||
checkGoogleAuth ||
checkGithubAuth ||
checkWeChatAuth
);
return checkFormLogin || checkGoogleAuth || checkGithubAuth;
} else {
return connectedMethodsCount >= 2;
}

View File

@ -0,0 +1,160 @@
import React, { useMemo, useState } from "react";
import styled from "styled-components";
import Trigger from "rc-trigger";
import { Button } from "antd";
import { Icon } from "@blueprintjs/core";
import { Resizable } from "react-resizable";
import Handle from "./handler";
import Draggable from "react-draggable";
import { getPanelStyle, savePanelStyle } from "utils/AppUtils";
const Wrapper = styled.div`
position: fixed;
// top: 50%;
left: 12%;
z-index: 10;
box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 10px 0px;
border-radius: 8px;
background: #fff;
`;
const WrapperOverLay = styled.div`
position: fixed;
z-index: 10;
border: 1px solid pink;
border-radius: 8px;
`;
const HeaderWrapper = styled.div`
cursor: move;
padding: 8px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #d7d9e0;
border-radius: 8px 8px 0 0;
`;
const TitleWrapper = styled.div`
display: flex;
align-items: center;
font-weight: 500;
font-size: 16px;
line-height: 16px;
color: #222222;
`;
const BodyWrapper = styled.div`
height: calc(100% - 40px);
`;
type Position = {
xRate: number;
yRate: number;
};
const CodeEditorPanel = (props: any) => {
const [visible, setVisible] = useState<boolean>(false);
const [currentPosition, setCurrentPosition] = useState<Position>({
xRate: 150,
yRate: 150,
});
const panelStyle = useMemo(() => getPanelStyle(), [props.editor]);
const [size, setSize] = useState({
w: panelStyle.codeEditor.w,
h: panelStyle.codeEditor.h,
});
const onDrag = (e: any, data: any) => {
setCurrentPosition({ xRate: data.lastX, yRate: data.lastY });
};
const onHandleVisible = (v: boolean) => {
setVisible(v);
props.onPanelVisibleChange && props.onPanelVisibleChange(v);
};
return (
<Trigger
popupVisible={visible}
action={["click"]}
zIndex={50}
popupStyle={{ opacity: 1, display: visible ? "block" : "none" }}
maskClosable={true}
onPopupVisibleChange={(visible) => onHandleVisible(visible)}
// afterPopupVisibleChange={(visible) => props.onVisibleChange(visible)}
popup={() => (
<WrapperOverLay id="code-portal">
<Draggable
position={{
x: currentPosition.xRate,
y: currentPosition.yRate,
}}
onDrag={onDrag}
handle="strong"
>
<Resizable
width={size.w}
height={size.h}
onResize={(event, { size }) => {
setSize({ w: size.width, h: size.height });
}}
onResizeStop={() =>
savePanelStyle({
...panelStyle,
codeEditor: { w: size.w, h: size.h },
})
}
handle={Handle}
resizeHandles={["s", "e", "se"]}
minConstraints={[480, 360]}
>
<Wrapper style={{ width: size.w + "px", height: size.h + "px" }}>
<strong className="cursor-move">
<HeaderWrapper>
<TitleWrapper>
<Icon icon="drag-handle-vertical" />
<span>{props.source}</span>
</TitleWrapper>
<Button
type="text"
size="small"
onClick={() => onHandleVisible(false)}
>
<span className="">
<Icon icon="minimize" />
</span>
</Button>
</HeaderWrapper>
</strong>
<div
style={{
width: "100%",
height: "100%",
}}
>
<BodyWrapper>{props.editor}</BodyWrapper>
</div>
</Wrapper>
</Resizable>
</Draggable>
</WrapperOverLay>
)}
>
<div
className={`absolute right-0 bottom-1 flex justify-end ${
!props.isShow ? "hidden" : ""
}`}
>
<Button
className="border-l border-t border-slate-500"
size="small"
type="text"
onClick={() => onHandleVisible(true)}
>
<span className="text-gray-500 rotate-90">
<Icon icon="expand-all" />
</span>
</Button>
</div>
</Trigger>
);
};
export default CodeEditorPanel;

View File

@ -0,0 +1,116 @@
import styled, { css } from "styled-components";
// util
export type ReactRef<T extends HTMLElement> = {
readonly current: T | null;
};
// Defines which resize handles should be rendered (default: 'se')
// Allows for any combination of:
// 's' - South handle (bottom-center)
// 'w' - West handle (left-center)
// 'e' - East handle (right-center)
// 'n' - North handle (top-center)
// 'sw' - Southwest handle (bottom-left)
// 'nw' - Northwest handle (top-left)
// 'se' - Southeast handle (bottom-right)
// 'ne' - Northeast handle (top-right)
// Custom component for resize handles
export type ResizeHandleAxis =
| "s"
| "w"
| "e"
| "n"
| "sw"
| "nw"
| "se"
| "ne";
const color = "rgb(118, 136, 150)";
const EdgeHandle = css`
&::before {
position: absolute;
// background: ${color};
content: "";
}
// small middle circles
&::after {
position: absolute;
content: "";
width: 6px;
height: 6px;
// border-radius: 50%;
// background: ${color};
top: calc(50% - 2px);
left: calc(50% - 2px);
border: none !important;
}
`;
const HorizontalHandle = css<{ axis: string }>`
${EdgeHandle}
${(props) => (props.axis === "s" ? "bottom: -10px;" : "top: -10px;")}
/* left: -4px; */
height: 12px !important;
/* width: calc(100% + 8px) !important; */
width: 100%;
cursor: row-resize;
&::before {
top: 50%;
right: 0px;
left: 0px;
height: 1px;
}
`;
const VerticalHandleStyles = css<{ axis: string }>`
${EdgeHandle}
${(props) => (props.axis === "e" ? "right: -10px;" : "left: -10px;")}
width: 12px !important;
top: 0px;
/* height: calc(100% + 8px) !important; */
height: 100%;
cursor: col-resize;
&::before {
left: 50%;
bottom: 0px;
top: 0px;
width: 1px;
}
`;
const CornerHandle = css<{ axis: string }>`
position: absolute;
z-index: 3;
width: 10px !important;
height: 10px !important;
&::after {
width: 10px !important;
height: 10px !important;
border: none !important;
}
cursor: ${(props) => props.axis + "-resize"} !important;
${(props) => (["nw", "ne"].indexOf(props.axis) >= 0 ? "top: -5px;" : "")};
${(props) => (["sw", "se"].indexOf(props.axis) >= 0 ? "bottom: -5px;" : "")};
${(props) => (["sw", "nw"].indexOf(props.axis) >= 0 ? "left: -5px;" : "")};
${(props) => (["se", "ne"].indexOf(props.axis) >= 0 ? "right: -5px;" : "")};
`;
const ResizeHandle = styled.div<{ axis: string }>`
position: absolute;
background-image: none;
${(props) => (["s", "n"].indexOf(props.axis) >= 0 ? HorizontalHandle : "")};
${(props) =>
["w", "e"].indexOf(props.axis) >= 0 ? VerticalHandleStyles : ""};
${(props) =>
["sw", "nw", "se", "ne"].indexOf(props.axis) >= 0 ? CornerHandle : ""};
`;
const Handle = (axis: ResizeHandleAxis, ref: ReactRef<HTMLDivElement>) => {
return (
<ResizeHandle
ref={ref}
axis={axis}
className={`react-resizable-handle`}
></ResizeHandle>
);
};
export default Handle;

View File

@ -11,6 +11,7 @@ import { CODE_EDITOR_LOADING_ERROR } from "@appsmith/constants/messages";
import assertNever from "assert-never/index";
import log from "loglevel";
import { toast } from "design-system";
import CodeEditorPanel from "../CodeEditor/CodeEditorPanel";
let CachedCodeEditor: typeof CodeEditor | undefined;
@ -173,6 +174,8 @@ function LazyCodeEditor({
"editor" | "editor-focused" | "fallback"
>("fallback");
const [showLoadingProgress, setShowLoadingProgress] = useState(false);
const [panelVisible, setPanelVisible] = useState(false);
const [isHovered, setPanelIsHovered] = useState(false);
const stateMachine = useRef(
new LazyCodeEditorStateMachine((state) => {
@ -213,18 +216,64 @@ function LazyCodeEditor({
throw new Error(
"CodeEditor is not loaded. This is likely an issue with the state machine.",
);
const content = (flag?: any) => {
const panelEditorStyle = !flag
? {
border: "none",
borderLess: true,
folding: true,
height: "100%",
hideEvaluatedValue: true,
mode: "javascript",
showLightningMenu: false,
showLineNumbers: true,
size: "EXTENDED",
tabBehaviour: "INDENT",
theme: "LIGHT",
}
: {};
return (
<div
className={
flag && panelVisible
? "pointer-events-none opacity-50 h-full w-ful"
: "h-full w-full"
}
>
<LazyEditorWrapper
className="t--lazyCodeEditor-editor"
ref={editorWrapperRef}
>
<CachedCodeEditor
input={input}
placeholder={placeholder}
{...otherProps}
{...panelEditorStyle}
/>
</LazyEditorWrapper>
</div>
);
};
if (otherProps.isJSObject) {
return content(true);
}
return (
<LazyEditorWrapper
className="t--lazyCodeEditor-editor"
ref={editorWrapperRef}
<div
onMouseEnter={() => setPanelIsHovered(true)}
onMouseLeave={() => setPanelIsHovered(false)}
onFocus={() => setPanelIsHovered(true)}
>
<CachedCodeEditor
input={input}
placeholder={placeholder}
{...otherProps}
{content(true)}
<CodeEditorPanel
editor={content()}
onPanelVisibleChange={(v: boolean) => {
setPanelVisible(v);
}}
isShow={isHovered}
source={otherProps.evaluatedPopUpLabel}
/>
</LazyEditorWrapper>
</div>
);
}

View File

@ -45,7 +45,7 @@ const VerticalResizeIndicators = css<{
border-radius: 50%/16%;
background: ${Colors.GREY_1};
top: calc(50% - 8px);
left: calc(50% - 2.5px);
left: calc(50% + 3.5px);
border: ${(props) => {
return `1px solid ${
props.isHovered ? Colors.PRIMARY_LIGHT : Colors.PRIMARY
@ -142,25 +142,25 @@ export const HorizontalHandleStyles = css<{
&::after {
width: ${EDGE_RESIZE_BAR_LONG}px;
height: ${EDGE_RESIZE_BAR_SHORT}px;
top: calc(50% - 2px);
top: calc(50% + 2.5px);
left: calc(50% - ${EDGE_RESIZE_BAR_LONG / 2}px);
}
`;
export const LeftHandleStyles = styled.div`
${VerticalHandleStyles}
left: ${-EDGE_RESIZE_HANDLE_WIDTH / 2 - WIDGET_PADDING + 1.5}px;
left: ${-EDGE_RESIZE_HANDLE_WIDTH / 2 - WIDGET_PADDING - 8.5}px;
`;
export const RightHandleStyles = styled.div`
${VerticalHandleStyles};
right: ${-EDGE_RESIZE_HANDLE_WIDTH / 2 - WIDGET_PADDING + 3.5}px;
right: ${-EDGE_RESIZE_HANDLE_WIDTH / 2 - WIDGET_PADDING + 5.5}px;
height: calc(100% + ${2 * WIDGET_PADDING}px);
`;
export const TopHandleStyles = styled.div`
${HorizontalHandleStyles};
top: ${-EDGE_RESIZE_HANDLE_WIDTH / 2 - WIDGET_PADDING + 1.5}px;
top: ${-EDGE_RESIZE_HANDLE_WIDTH / 2 - WIDGET_PADDING - 6.5}px;
`;
export const BottomHandleStyles = styled.div`

View File

@ -48,7 +48,7 @@ const PositionStyle = styled.div<{
cursor: pointer;
top: ${(props) =>
props.topRow > 2
? `${-1 * WidgetNameComponentHeight + 1 + props.positionOffset[0]}px`
? `${-1 * WidgetNameComponentHeight + props.positionOffset[0] - 4}px`
: `calc(100% - ${1 + props.positionOffset[0]}px)`};
height: ${WidgetNameComponentHeight}px;
right: ${(props) => props.positionOffset[1]}px;

View File

@ -0,0 +1,132 @@
import React, { useContext } from "react";
import type { ControlProps } from "./BaseControl";
import BaseControl from "./BaseControl";
import { StyledDynamicInput } from "./StyledControls";
import type { InputType } from "components/constants";
import type { CodeEditorExpected } from "components/editorComponents/CodeEditor";
import {
CodeEditorBorder,
EditorModes,
EditorSize,
EditorTheme,
TabBehaviour,
} from "components/editorComponents/CodeEditor/EditorConfig";
import { CollapseContext } from "pages/Editor/PropertyPane/PropertySection";
import LazyCodeEditor from "../editorComponents/LazyCodeEditor";
import type { AdditionalDynamicDataTree } from "utils/autocomplete/customTreeTypeDefCreator";
export function JsData(props: {
label: string;
value: string;
onBlur?: () => void;
onChange: (event: React.ChangeEvent<HTMLTextAreaElement> | string) => void;
onFocus?: () => void;
evaluatedValue?: any;
expected?: CodeEditorExpected;
placeholder?: string;
dataTreePath?: string;
additionalAutocomplete?: AdditionalDynamicDataTree;
theme?: EditorTheme;
hideEvaluatedValue?: boolean;
}) {
const {
dataTreePath,
evaluatedValue,
expected,
hideEvaluatedValue,
label,
onBlur,
onChange,
onFocus,
placeholder,
value,
} = props;
//subscribing to context to help re-render component on Property section open or close
const isOpen = useContext(CollapseContext);
return (
<StyledDynamicInput>
<LazyCodeEditor
AIAssisted
additionalDynamicData={props.additionalAutocomplete}
border={CodeEditorBorder.ALL_SIDE}
dataTreePath={dataTreePath}
evaluatedPopUpLabel={label}
evaluatedValue={evaluatedValue}
expected={expected}
hideEvaluatedValue={hideEvaluatedValue}
hoverInteraction
input={{
value: value,
onChange: onChange,
}}
isEditorHidden={!isOpen}
mode={EditorModes.JAVASCRIPT}
onEditorBlur={onBlur}
onEditorFocus={onFocus}
placeholder={placeholder}
size={EditorSize.EXTENDED}
tabBehaviour={TabBehaviour.INDENT}
theme={props.theme || EditorTheme.LIGHT}
/>
</StyledDynamicInput>
);
}
class JsDataControl extends BaseControl<JsDataControllProps> {
render() {
const {
additionalAutoComplete,
dataTreePath,
defaultValue,
expected,
hideEvaluatedValue,
label,
onBlur,
onFocus,
placeholderText,
propertyValue,
} = this.props;
return (
<JsData
additionalAutocomplete={additionalAutoComplete}
dataTreePath={dataTreePath}
expected={expected}
hideEvaluatedValue={hideEvaluatedValue}
label={label}
onBlur={onBlur}
onChange={this.onTextChange}
onFocus={onFocus}
placeholder={placeholderText}
theme={this.props.theme}
value={propertyValue !== undefined ? propertyValue : defaultValue}
/>
);
}
onTextChange = (event: React.ChangeEvent<HTMLTextAreaElement> | string) => {
const value = event;
// if (typeof event !== "string") {
// value = event.target.value;
// }
this.updateProperty(this.props.propertyName, value, true);
};
static getControlType() {
return "JS_DATA";
}
}
export interface JsDataControllProps extends ControlProps {
placeholderText: string;
inputType: InputType;
validationMessage?: string;
isDisabled?: boolean;
defaultValue?: any;
onFocus?: () => void;
onBlur?: () => void;
}
export default JsDataControl;

View File

@ -70,8 +70,11 @@ import type { OneClickBindingControlProps } from "./OneClickBindingControl";
import OneClickBindingControl from "./OneClickBindingControl";
import type { WrappedCodeEditorControlProps } from "./WrappedCodeEditorControl";
import WrappedCodeEditorControl from "./WrappedCodeEditorControl";
import type { JsDataControllProps } from "components/propertyControls/JSControl";
import JsDataControl from "components/propertyControls/JSControl";
export const PropertyControls = {
JsDataControl,
InputTextControl,
DropDownControl,
SwitchControl,
@ -124,6 +127,7 @@ export const PropertyControls = {
};
export type PropertyControlPropsType =
| JsDataControllProps
| ControlProps
| InputControlProps
| DropDownControlProps

View File

@ -52,7 +52,7 @@ export const Colors = {
PRIMARY: primaryColor,
PRIMARY_DARK: "#3ababc",
PRIMARY_LIGHT: "#CAECDC",
PRIMARY_LIGHT: "#4fb2b4",
GREEN: primaryColor,
FOAM: "#D9FDED",
LIGHT_GREEN_CYAN: "#e5f6ec",

View File

@ -25,6 +25,8 @@ export const SIGNUP_RESTRICTION_DOC =
"https://docs.appsmith.com/getting-started/setup/instance-configuration/disable-user-signup#disable-sign-up";
export const EMBED_PRIVATE_APPS_DOC =
"https://docs.appsmith.com/advanced-concepts/embed-appsmith-into-existing-application#embedding-private-apps";
export const WX_SIGNUP_SETUP_DOC =
"https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html";
export const PROVISIONING_SETUP_DOC =
"http://docs.appsmith.com/advanced-concepts/user-provisioning-group-sync";
export const PRICING_PAGE_URL = (

View File

@ -18,6 +18,7 @@ export type User = {
adminSettingsVisible?: boolean;
isAnonymous?: boolean;
isIntercomConsentGiven?: boolean;
bindWeChat: boolean;
};
export interface UserApplication {
@ -40,6 +41,7 @@ export const DefaultCurrentUserDetails: User = {
enableTelemetry: false,
adminSettingsVisible: false,
isIntercomConsentGiven: false,
bindWeChat: false,
};
// TODO keeping it here instead of the USER_API since it leads to cyclic deps errors during tests

View File

@ -53,7 +53,7 @@ class Empty extends React.Component {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const inst = createReactApp(Empty, React, ReactDOM, {});
// add touch emulator
import "@vant/touch-emulator";
// import "@vant/touch-emulator";
import "react-sortable-tree-patch-react-17/style.css";
const shouldAutoFreeze = process.env.NODE_ENV === "development";

View File

@ -27,13 +27,14 @@ import {
import equal from "fast-deep-equal/es6";
const Section = styled.section<{
height: number;
theight: number;
isMobile: boolean;
}>`
background: ${({ isMobile }) => (isMobile ? "#fff" : "transparent")};
width: ${({ isMobile }) => (isMobile ? "450px" : "100%")};
height: 100%;
min-height: ${({ height, isMobile }) => (isMobile ? `${height}px` : "unset")};
min-height: ${({ theight, isMobile }) =>
isMobile ? `${theight}px` : "unset"};
margin: 0 auto;
position: relative;
overflow: auto;
@ -115,7 +116,7 @@ function AppViewerPageContainer(props: AppViewerPageContainerProps) {
return (
<Section
height={widgetsStructure.bottomRow + fixedHeight + AUTO_HEIGHT_PADDING}
theight={widgetsStructure.bottomRow + fixedHeight + AUTO_HEIGHT_PADDING}
isMobile={isMobile}
id="art-board"
>

View File

@ -11,6 +11,7 @@ import { Icon } from "design-system";
import { getAssetUrl } from "@appsmith/utils/airgapHelpers";
import { importSvg } from "design-system-old";
import { Colors } from "constants/Colors";
import { replacePluginIcon } from "utils/AppsmithUtils";
const ApiIcon = importSvg(() => import("assets/icons/menu/api-colored.svg"));
const CurlIcon = importSvg(() => import("assets/images/Curl-logo.svg"));
@ -101,11 +102,9 @@ const PluginIcon = styled.img`
export const getPluginIcon = (plugin?: Plugin) => {
if (plugin && plugin.iconLocation) {
const logo_location = replacePluginIcon(plugin.iconLocation);
return (
<PluginIcon
alt={plugin.packageName}
src={getAssetUrl(plugin.iconLocation)}
/>
<PluginIcon alt={plugin.packageName} src={getAssetUrl(logo_location)} />
);
}
return <PluginIcon alt="plugin-placeholder" src={ImageAlt} />;

View File

@ -10,6 +10,9 @@ export const BodyContainer = styled.div`
.ads-v2-input__input-section-icon[data-has-onclick="true"] * {
cursor: pointer !important;
}
.ur--has-border {
width: 638px;
}
`;
const HeaderWrapper = styled.div`

View File

@ -52,6 +52,7 @@ const GroupBody = styled.div`
> div {
margin-top: 0px;
margin-bottom: 12px;
width: 638px;
}
}
&&&& {

View File

@ -77,7 +77,7 @@ export function SettingsForm(
const { category, selected: subCategory } = params;
const settingsDetails = getSettingsConfig(category, subCategory);
const { settings, settingsConfig } = props;
const details = getSettingDetail(category, subCategory);
const details = getSettingDetail(category, subCategory) as any;
const dispatch = useDispatch();
const isSavable = AdminConfig.savableCategories.includes(
subCategory ?? category,
@ -101,6 +101,9 @@ export function SettingsForm(
!isTenantConfig(s.id),
);
const addconfig = details?.settings?.find(
(item: any) => item.label === "Redirect URL",
);
const saveChangedSettings = () => {
const settingsKeyLength = Object.keys(props.settings).length;
const isOnlyEnvSettings =
@ -110,7 +113,14 @@ export function SettingsForm(
updatedTenantSettings.length !== settingsKeyLength;
if (isOnlyEnvSettings) {
// only env settings
dispatch(saveSettings(props.settings));
const settings = { ...props.settings };
// 检查 addconfig 是否为 undefined
if (addconfig !== undefined) {
// 如果不为 undefined则添加对应的属性
settings[addconfig.id] = `${window.location.origin}${addconfig.value}`;
}
// 调用 dispatch 保存设置
dispatch(saveSettings(settings));
} else {
// only tenant settings
const config: any = {};

View File

@ -1,4 +1,5 @@
import React, { useState } from "react";
import styled from "styled-components";
import { Button, Input, toast, Text } from "design-system";
import { useDispatch, useSelector } from "react-redux";
import { getCurrentUser } from "selectors/usersSelectors";
@ -17,9 +18,22 @@ import { Wrapper, FieldWrapper, LabelWrapper } from "./StyledComponents";
import { ANONYMOUS_USERNAME } from "constants/userConstants";
import { ALL_LANGUAGE_CHARACTERS_REGEX } from "constants/Regex";
import { createMessage } from "design-system-old/build/constants/messages";
import { notEmptyValidator } from "design-system-old";
import { notEmptyValidator, TextType } from "design-system-old";
import { getIsFormLoginEnabled } from "@appsmith/selectors/tenantSelectors";
type ButtonProps = {
wechatEnable?: boolean;
};
const BindButton = styled.button<ButtonProps>`
width: 96px;
height: 32px;
border: 1px solid ${(props) => (props.wechatEnable ? "#D4DAD9" : "#13c2c2")};
border-radius: 4px;
padding: 5px 15px;
color: ${(props) => (props.wechatEnable ? "#D4DAD9" : "#13c2c2")};
`;
const nameValidator = (
value: string,
): {
@ -71,6 +85,11 @@ function General() {
};
if (user?.email === ANONYMOUS_USERNAME) return null;
const [wechatEnable, setwechatEnable] = useState(false);
const onBindwechatClick = () => {
setwechatEnable(!wechatEnable);
};
return (
<Wrapper>
@ -138,6 +157,20 @@ function General() {
)}
</div>
</FieldWrapper>
<FieldWrapper>
<LabelWrapper>
<Text></Text>
</LabelWrapper>
<div style={{ flexDirection: "column", display: "flex" }}>
{
<BindButton wechatEnable={wechatEnable} onClick={onBindwechatClick}>
</BindButton>
}
{wechatEnable ? <Text></Text> : <Text>'</Text>}
</div>
</FieldWrapper>
</Wrapper>
);
}

View File

@ -47,3 +47,53 @@ export async function readBlob(blobUrl: string): Promise<any> {
};
});
}
export type PanelStatus = { left: boolean; bottom: boolean; right: boolean };
export type PanelStyle = {
bottom: {
h: number;
};
codeEditor: {
w: number;
h: number;
};
};
export const DefaultPanelStatus: PanelStatus = {
left: true,
bottom: true,
right: true,
};
const DefaultPanelStyle: PanelStyle = {
bottom: {
h: 285,
},
codeEditor: {
w: 744,
h: 468,
},
};
export function savePanelStatus(panelStatus: PanelStatus) {
localStorage.setItem("editor_panel_status", JSON.stringify(panelStatus));
}
export function getPanelStatus(): PanelStatus {
const str = localStorage.getItem("editor_panel_status");
if (!str) {
return DefaultPanelStatus;
}
return { ...DefaultPanelStatus, ...JSON.parse(str) };
}
export function savePanelStyle(panelStyle: PanelStyle) {
localStorage.setItem("editor_panel_style", JSON.stringify(panelStyle));
}
export function getPanelStyle(): PanelStyle {
const str = localStorage.getItem("editor_panel_style");
if (!str) {
return DefaultPanelStyle;
}
return { ...DefaultPanelStyle, ...JSON.parse(str) };
}

View File

@ -23,6 +23,7 @@ export type TableSizes = {
TABLE_HEADER_HEIGHT: number;
ROW_HEIGHT: number;
ROW_FONT_SIZE: number;
TABLE_FOOTER_HEIGHT: number;
VERTICAL_PADDING: number;
EDIT_ICON_TOP: number;
ROW_VIRTUAL_OFFSET: number;
@ -57,6 +58,7 @@ export const TABLE_SIZES: { [key: string]: TableSizes } = {
[CompactModeTypes.DEFAULT]: {
COLUMN_HEADER_HEIGHT: 32,
TABLE_HEADER_HEIGHT: 40,
TABLE_FOOTER_HEIGHT: 40,
ROW_HEIGHT: 40,
ROW_FONT_SIZE: 14,
VERTICAL_PADDING: 6,
@ -67,6 +69,7 @@ export const TABLE_SIZES: { [key: string]: TableSizes } = {
[CompactModeTypes.SHORT]: {
COLUMN_HEADER_HEIGHT: 32,
TABLE_HEADER_HEIGHT: 40,
TABLE_FOOTER_HEIGHT: 40,
ROW_HEIGHT: 30,
ROW_FONT_SIZE: 12,
VERTICAL_PADDING: 0,
@ -77,6 +80,7 @@ export const TABLE_SIZES: { [key: string]: TableSizes } = {
[CompactModeTypes.TALL]: {
COLUMN_HEADER_HEIGHT: 32,
TABLE_HEADER_HEIGHT: 40,
TABLE_FOOTER_HEIGHT: 40,
ROW_HEIGHT: 60,
ROW_FONT_SIZE: 18,
VERTICAL_PADDING: 16,

View File

@ -40,6 +40,7 @@ type StaticTableProps = TableColumnHeaderProps & {
scrollContainerStyles: any;
useVirtual: boolean;
tableBodyRef?: React.MutableRefObject<HTMLDivElement | null>;
isVisiblePagination?: boolean;
};
const StaticTable = (props: StaticTableProps, ref: React.Ref<SimpleBar>) => {
@ -90,6 +91,7 @@ const StaticTable = (props: StaticTableProps, ref: React.Ref<SimpleBar>) => {
tableSizes={props.tableSizes}
useVirtual={props.useVirtual}
width={props.width - TABLE_SCROLLBAR_WIDTH / 2}
isVisiblePagination={props.isVisiblePagination}
/>
</SimpleBar>
);

View File

@ -295,11 +295,20 @@ export function Table(props: TableProps) {
height: isHeaderVisible
? props.height -
tableSizes.TABLE_HEADER_HEIGHT -
(props.isVisiblePagination ? tableSizes.TABLE_FOOTER_HEIGHT : 0) -
TABLE_SCROLLBAR_HEIGHT -
SCROLL_BAR_OFFSET
: props.height - TABLE_SCROLLBAR_HEIGHT - SCROLL_BAR_OFFSET,
: props.height -
TABLE_SCROLLBAR_HEIGHT -
SCROLL_BAR_OFFSET -
(props.isVisiblePagination ? tableSizes.TABLE_FOOTER_HEIGHT : 0),
};
}, [isHeaderVisible, props.height, tableSizes.TABLE_HEADER_HEIGHT]);
}, [
isHeaderVisible,
props.height,
tableSizes.TABLE_HEADER_HEIGHT,
props.isVisiblePagination,
]);
const shouldUseVirtual =
props.serverSidePaginationEnabled &&
@ -393,7 +402,7 @@ export function Table(props: TableProps) {
/>
</TableHeaderInnerWrapper>
</TableHeaderWrapper>
</SimpleBar>
</SimpleBar>
)}
{/* 表格内容 */}
<div
@ -407,96 +416,94 @@ export function Table(props: TableProps) {
ref={tableWrapperRef}
>
<div {...getTableProps()} className="table column-freeze">
{!shouldUseVirtual && (
<StaticTable
accentColor={props.accentColor}
borderRadius={props.borderRadius}
canFreezeColumn={props.canFreezeColumn}
columns={props.columns}
disableDrag={props.disableDrag}
editMode={props.editMode}
enableDrag={props.enableDrag}
getTableBodyProps={getTableBodyProps}
handleAllRowSelectClick={handleAllRowSelectClick}
handleColumnFreeze={props.handleColumnFreeze}
handleReorderColumn={props.handleReorderColumn}
headerGroups={headerGroups}
height={props.height}
isAddRowInProgress={props.isAddRowInProgress}
isResizingColumn={isResizingColumn}
isSortable={props.isSortable}
multiRowSelection={props?.multiRowSelection}
pageSize={props.pageSize}
prepareRow={prepareRow}
primaryColumnId={props.primaryColumnId}
ref={scrollBarRef}
rowSelectionState={rowSelectionState}
scrollContainerStyles={scrollContainerStyles}
selectTableRow={props.selectTableRow}
selectedRowIndex={props.selectedRowIndex}
selectedRowIndices={props.selectedRowIndices}
sortTableColumn={props.sortTableColumn}
subPage={subPage}
tableSizes={tableSizes}
totalColumnsWidth={totalColumnsWidth}
useVirtual={shouldUseVirtual}
widgetId={props.widgetId}
width={props.width}
/>
)}
{!shouldUseVirtual && (
<StaticTable
accentColor={props.accentColor}
borderRadius={props.borderRadius}
canFreezeColumn={props.canFreezeColumn}
columns={props.columns}
disableDrag={props.disableDrag}
editMode={props.editMode}
enableDrag={props.enableDrag}
getTableBodyProps={getTableBodyProps}
handleAllRowSelectClick={handleAllRowSelectClick}
handleColumnFreeze={props.handleColumnFreeze}
handleReorderColumn={props.handleReorderColumn}
headerGroups={headerGroups}
height={props.height}
isAddRowInProgress={props.isAddRowInProgress}
isResizingColumn={isResizingColumn}
isSortable={props.isSortable}
multiRowSelection={props?.multiRowSelection}
pageSize={props.pageSize}
prepareRow={prepareRow}
primaryColumnId={props.primaryColumnId}
ref={scrollBarRef}
rowSelectionState={rowSelectionState}
scrollContainerStyles={scrollContainerStyles}
selectTableRow={props.selectTableRow}
selectedRowIndex={props.selectedRowIndex}
selectedRowIndices={props.selectedRowIndices}
sortTableColumn={props.sortTableColumn}
subPage={subPage}
tableSizes={tableSizes}
totalColumnsWidth={totalColumnsWidth}
useVirtual={shouldUseVirtual}
widgetId={props.widgetId}
width={props.width}
isVisiblePagination={props.isVisiblePagination}
/>
)}
{shouldUseVirtual && (
<VirtualTable
accentColor={props.accentColor}
borderRadius={props.borderRadius}
canFreezeColumn={props.canFreezeColumn}
columns={props.columns}
disableDrag={props.disableDrag}
editMode={props.editMode}
enableDrag={props.enableDrag}
getTableBodyProps={getTableBodyProps}
handleAllRowSelectClick={handleAllRowSelectClick}
handleColumnFreeze={props.handleColumnFreeze}
handleReorderColumn={props.handleReorderColumn}
headerGroups={headerGroups}
height={props.height}
isAddRowInProgress={props.isAddRowInProgress}
isResizingColumn={isResizingColumn}
isSortable={props.isSortable}
multiRowSelection={props?.multiRowSelection}
pageSize={props.pageSize}
prepareRow={prepareRow}
primaryColumnId={props.primaryColumnId}
ref={scrollBarRef}
rowSelectionState={rowSelectionState}
scrollContainerStyles={scrollContainerStyles}
selectTableRow={props.selectTableRow}
selectedRowIndex={props.selectedRowIndex}
selectedRowIndices={props.selectedRowIndices}
sortTableColumn={props.sortTableColumn}
subPage={subPage}
tableSizes={tableSizes}
totalColumnsWidth={totalColumnsWidth}
useVirtual={shouldUseVirtual}
widgetId={props.widgetId}
width={props.width}
/>
)}
{shouldUseVirtual && (
<VirtualTable
accentColor={props.accentColor}
borderRadius={props.borderRadius}
canFreezeColumn={props.canFreezeColumn}
columns={props.columns}
disableDrag={props.disableDrag}
editMode={props.editMode}
enableDrag={props.enableDrag}
getTableBodyProps={getTableBodyProps}
handleAllRowSelectClick={handleAllRowSelectClick}
handleColumnFreeze={props.handleColumnFreeze}
handleReorderColumn={props.handleReorderColumn}
headerGroups={headerGroups}
height={props.height}
isAddRowInProgress={props.isAddRowInProgress}
isResizingColumn={isResizingColumn}
isSortable={props.isSortable}
multiRowSelection={props?.multiRowSelection}
pageSize={props.pageSize}
prepareRow={prepareRow}
primaryColumnId={props.primaryColumnId}
ref={scrollBarRef}
rowSelectionState={rowSelectionState}
scrollContainerStyles={scrollContainerStyles}
selectTableRow={props.selectTableRow}
selectedRowIndex={props.selectedRowIndex}
selectedRowIndices={props.selectedRowIndices}
sortTableColumn={props.sortTableColumn}
subPage={subPage}
tableSizes={tableSizes}
totalColumnsWidth={totalColumnsWidth}
useVirtual={shouldUseVirtual}
widgetId={props.widgetId}
width={props.width}
isVisiblePagination={props.isVisiblePagination}
/>
)}
</div>
</div>
{/* 表格工具栏-底部 */}
{isHeaderVisible && (
<SimpleBar
style={{
maxHeight: tableSizes.TABLE_HEADER_HEIGHT,
}}
>
{props.isVisiblePagination && (
<TableHeaderWrapper
backgroundColor={Colors.WHITE}
ref={tableHeaderWrapperRef}
serverSidePaginationEnabled={props.serverSidePaginationEnabled}
tableSizes={tableSizes}
width={props.width}
topBoxShadow
>
<TableHeaderInnerWrapper
backgroundColor={Colors.WHITE}
@ -535,7 +542,6 @@ export function Table(props: TableProps) {
/>
</TableHeaderInnerWrapper>
</TableHeaderWrapper>
</SimpleBar>
)}
</TableWrapper>
</>

View File

@ -80,6 +80,7 @@ type BodyPropsType = {
width?: number;
tableSizes: TableSizes;
innerElementType?: ReactElementType;
isVisiblePagination?: boolean;
};
const TableVirtualBodyComponent = React.forwardRef(
@ -91,6 +92,9 @@ const TableVirtualBodyComponent = React.forwardRef(
height={
props.height -
props.tableSizes.TABLE_HEADER_HEIGHT -
(props.isVisiblePagination
? props.tableSizes.TABLE_FOOTER_HEIGHT
: 0) -
2 * WIDGET_PADDING
}
innerElementType={props.innerElementType}

View File

@ -684,6 +684,7 @@ export const TableHeaderWrapper = styled.div<{
width: number;
tableSizes: TableSizes;
backgroundColor?: Color;
topBoxShadow?: boolean;
}>`
position: relative;
display: flex;
@ -694,6 +695,8 @@ export const TableHeaderWrapper = styled.div<{
}
height: ${(props) => props.tableSizes.TABLE_HEADER_HEIGHT}px;
min-height: ${(props) => props.tableSizes.TABLE_HEADER_HEIGHT}px;
box-shadow: ${(props) =>
props.topBoxShadow ? "rgba(33, 35, 38, 0.1) 0px -10px 10px -10px" : ""};
`;
export const TableHeaderInnerWrapper = styled.div<{

View File

@ -35,6 +35,7 @@ type VirtualTableProps = TableColumnHeaderProps & {
totalColumnsWidth?: number;
scrollContainerStyles: any;
useVirtual: boolean;
isVisiblePagination?: boolean;
};
const VirtualTable = (props: VirtualTableProps, ref: React.Ref<SimpleBar>) => {
@ -75,6 +76,7 @@ const VirtualTable = (props: VirtualTableProps, ref: React.Ref<SimpleBar>) => {
useVirtual={props.useVirtual}
widgetId={props.widgetId}
width={props.width}
isVisiblePagination={props.isVisiblePagination}
/>
)}
</SimpleBar>

View File

@ -52,16 +52,7 @@ export function TableHeader_Bottom(
...ActionProps
} = props;
return isAddRowInProgress ? (
<Banner
accentColor={accentColor}
borderRadius={borderRadius}
boxShadow={boxShadow}
disabledAddNewRowSave={disabledAddNewRowSave}
isAddRowInProgress={isAddRowInProgress}
onAddNewRowAction={onAddNewRowAction}
/>
) : (
return (
<BottomActions
accentColor={accentColor}
borderRadius={borderRadius}

View File

@ -9113,6 +9113,15 @@ __metadata:
languageName: node
linkType: hard
"@types/react-resizable@npm:^3.0.4":
version: 3.0.6
resolution: "@types/react-resizable@npm:3.0.6"
dependencies:
"@types/react": "*"
checksum: da5594b42ae5ab0c6ce27abb54cc3f1d5738e6905c2dac2beb2b12f941b47469d94dc3309274627b9d8a3ee9cc7bdf2c463d73e2a61a098dc80326c2d83ea237
languageName: node
linkType: hard
"@types/react-router-dom@npm:^5.1.2":
version: 5.3.3
resolution: "@types/react-router-dom@npm:5.3.3"
@ -10303,6 +10312,7 @@ __metadata:
"@types/react-modal": ^3.13.1
"@types/react-page-visibility": ^6.4.1
"@types/react-redux": ^7.0.1
"@types/react-resizable": ^3.0.4
"@types/react-router-dom": ^5.1.2
"@types/react-select": ^3.0.5
"@types/react-syntax-highlighter": ^13.5.2
@ -10459,6 +10469,7 @@ __metadata:
rc-pagination: ^3.1.3
rc-select: ^14.1.9
rc-tree-select: ^5.4.0
rc-trigger: ^5.3.4
re-reselect: ^3.4.0
react: ^17.0.2
react-append-to-body: ^2.0.26
@ -10470,6 +10481,7 @@ __metadata:
react-dnd-touch-backend: 11.1.3
react-documents: ^1.0.4
react-dom: ^17.0.2
react-draggable: 4.4.4
react-full-screen: ^1.1.0
react-fusioncharts: ^3.1.2
react-google-recaptcha: ^2.1.0
@ -10488,6 +10500,7 @@ __metadata:
react-qr-barcode-scanner: ^1.0.6
react-rating: ^2.0.5
react-redux: ^7.2.4
react-resizable: ^3.0.5
react-responsive: ^9.0.0-beta.3
react-router: ^5.1.2
react-router-dom: ^5.1.2
@ -25924,7 +25937,7 @@ __metadata:
languageName: node
linkType: hard
"prop-types@npm:^15.5.0, prop-types@npm:^15.5.10, prop-types@npm:^15.5.4, prop-types@npm:^15.5.8, prop-types@npm:^15.5.9, prop-types@npm:^15.6.0, prop-types@npm:^15.6.1, prop-types@npm:^15.6.2, prop-types@npm:^15.7.2, prop-types@npm:^15.8.1":
"prop-types@npm:15.x, prop-types@npm:^15.5.0, prop-types@npm:^15.5.10, prop-types@npm:^15.5.4, prop-types@npm:^15.5.8, prop-types@npm:^15.5.9, prop-types@npm:^15.6.0, prop-types@npm:^15.6.1, prop-types@npm:^15.6.2, prop-types@npm:^15.7.2, prop-types@npm:^15.8.1":
version: 15.8.1
resolution: "prop-types@npm:15.8.1"
dependencies:
@ -26902,7 +26915,7 @@ __metadata:
languageName: node
linkType: hard
"rc-trigger@npm:^5.3.1":
"rc-trigger@npm:^5.3.1, rc-trigger@npm:^5.3.4":
version: 5.3.4
resolution: "rc-trigger@npm:5.3.4"
dependencies:
@ -27349,6 +27362,32 @@ __metadata:
languageName: node
linkType: hard
"react-draggable@npm:4.4.4":
version: 4.4.4
resolution: "react-draggable@npm:4.4.4"
dependencies:
clsx: ^1.1.1
prop-types: ^15.6.0
peerDependencies:
react: ">= 16.3.0"
react-dom: ">= 16.3.0"
checksum: b8258a58938c261a79f1b9ffd67774283c1ac732423c1c9c9f5fe4d17a06886edd659891e445ba089828ca59f1885e5b909262e24cf60640b8ed05c8499c88bb
languageName: node
linkType: hard
"react-draggable@npm:^4.0.3":
version: 4.4.6
resolution: "react-draggable@npm:4.4.6"
dependencies:
clsx: ^1.1.1
prop-types: ^15.8.1
peerDependencies:
react: ">= 16.3.0"
react-dom: ">= 16.3.0"
checksum: 9b15aac59244873ac4561c5a2bead43a56e18d406e0a5f242bd4f9d151c074530c02b99387983104bf43417292f9cf8d063e554ed08d88792235e3fbc965f1b8
languageName: node
linkType: hard
"react-element-to-jsx-string@npm:^15.0.0":
version: 15.0.0
resolution: "react-element-to-jsx-string@npm:15.0.0"
@ -27790,6 +27829,18 @@ __metadata:
languageName: node
linkType: hard
"react-resizable@npm:^3.0.5":
version: 3.0.5
resolution: "react-resizable@npm:3.0.5"
dependencies:
prop-types: 15.x
react-draggable: ^4.0.3
peerDependencies:
react: ">= 16.3"
checksum: 616a10205acfaf8cc3aa0824b60f6d037eef87143d8f338cf826deb74a353db9b9baad67a65dc8535fe90840bfc3e1b8a901f9c247033ffeec2f30405ac7528e
languageName: node
linkType: hard
"react-resize-detector@npm:^7.1.2":
version: 7.1.2
resolution: "react-resize-detector@npm:7.1.2"