Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
94 changes: 79 additions & 15 deletions client/packages/lowcoder/src/comps/controls/codeStateControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
CompAction,
CompActionTypes,
ConstructorToView,
CustomAction,
evalNodeOrMinor,
updateNodesV2Action,
} from "lowcoder-core";
Expand All @@ -42,8 +43,14 @@ import {
toStringNumberArray,
} from "util/convertUtils";
import { JSONObject, JSONValue } from "util/jsonTypes";
import { getPromiseAfterDispatch } from "../../util/promiseUtils";
import { EvalParamType, ParamConfig, ParamType } from "./actionSelector/executeCompTypes";
import { getPromiseAfterDispatch, handlePromiseAfterResult } from "../../util/promiseUtils";
import {
EvalParamType,
ExecuteAction,
MethodConfig,
ParamConfig,
ParamType,
} from "./actionSelector/executeCompTypes";

export const __TMP_STATE_FIELD_NAME = "__TMP_STATE_FIELD_NAME";

Expand Down Expand Up @@ -173,19 +180,76 @@ export function withLinkedDefaultValue<
): TCtor {
class LinkedDefaultValueComp extends (Base as any) {
reduce(action: CompAction): this {
const ret = super.reduce(action) as this;
if (
action.type === CompActionTypes.UPDATE_NODES_V2 &&
(ret.children as any)[defaultValueKey] !== (this.children as any)[defaultValueKey]
) {
const defaultValue = (ret.children as any)[defaultValueKey].getView().value;
const valueChild = (ret.children as any)[valueKey];
const newValue = transformDefaultValue ? transformDefaultValue(defaultValue, ret) : defaultValue;
if (!_.isEqual(newValue, valueChild.getView().value)) {
return (ret as any).setChild(valueKey, valueChild.reduce(changeChildAction("value", newValue, false)));
}
const updated = super.reduce(action) as this;

const defaultValueFieldBefore = (this.children as any)[defaultValueKey];
const defaultValueFieldAfter = (updated.children as any)[defaultValueKey];
if (defaultValueFieldAfter === defaultValueFieldBefore) {
return updated;
}

const defaultBefore = defaultValueFieldBefore.getView().value;
const defaultAfter = defaultValueFieldAfter.getView().value;
if (_.isEqual(defaultBefore, defaultAfter)) {
return updated;
}

const currentValueField = (updated.children as any)[valueKey];

let newValue = defaultAfter;
if (transformDefaultValue) {
newValue = transformDefaultValue(newValue, updated);
}
if (_.isEqual(newValue, currentValueField.getView().value)) {
return updated;
}

const setValueMessage = changeChildAction("value", newValue, false);

if (action.type === CompActionTypes.UPDATE_NODES_V2) {
setTimeout(currentValueField.dispatch, 0, setValueMessage);
return updated;
}
return ret;

const updatedCurrentValueField = currentValueField.reduce(setValueMessage);
return (updated as any).setChild(valueKey, updatedCurrentValueField);
}

// Someone called a method on this component, e.g. switch1.resetValue().
// "call" holds the method's name and its arguments.
// Returns true if this function took care of the call.
executeMethod(call: CustomAction<ExecuteAction>): boolean {
const calledMethodName = call.value.methodName;

// What the component shows right now (e.g. the switch is on or off).
const currentValueField = (this.children as any)[valueKey];

// What was entered as "Default value" in the property panel.
const defaultValueField = (this.children as any)[defaultValueKey];

// The current value field offers three methods: set…, clear… and reset…
// (e.g. setValue, clearValue, resetValue). Find the name of the reset one.
const currentValueMethods: MethodConfig[] = currentValueField.getMethodConfig();
const resetMethod = currentValueMethods.find((method) => method.name.startsWith("reset"));

if (calledMethodName !== resetMethod?.name) {
// Any other method (setValue, clearValue, focus, ...): handle it as before.
return super.executeMethod(call);
}

// The current value field's own reset would read a default of its own,
// which is always empty. Take the one from the property panel instead.
let defaultValue = defaultValueField.getView().value;
if (transformDefaultValue) {
defaultValue = transformDefaultValue(defaultValue, this);
}

// Same as calling setValue(defaultValue).
const doneWhenChanged = currentValueField.change(defaultValue);

// Lets the caller wait for the change, e.g. "await switch1.resetValue()".
handlePromiseAfterResult(call, doneWhenChanged);
return true;
}
}

Expand Down Expand Up @@ -305,7 +369,7 @@ export const jsonObjectStateControl = (defaultValue?: JSONObject) =>

export const arrayObjectStateControl = (defaultValue?: JSONObject[]) =>
withTmpState(jsonArrayControl(defaultValue), {});

export const jsonValueStateControl = (defaultValue?: JSONValue) =>
withTmpState(jsonValueControl(defaultValue), "");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,8 @@ export function withMultiContext<TCtor extends MultiCompConstructor>(VariantComp
comp = this.getOriginalComp();
} else {
comp = this.getOriginalComp()
.setParams(params)
.changeDispatch(wrapDispatch(wrapDispatch(this.dispatch, MAP_KEY), key));
.changeDispatch(wrapDispatch(wrapDispatch(this.dispatch, MAP_KEY), key))
.setParams(params);
}
}
return comp;
Expand Down Expand Up @@ -184,8 +184,8 @@ export function withMultiContext<TCtor extends MultiCompConstructor>(VariantComp
if (params) {
const childComp = comp
.getOriginalComp()
.setParams(params)
.changeDispatch(wrapDispatch(wrapDispatch(comp.dispatch, MAP_KEY), key));
.changeDispatch(wrapDispatch(wrapDispatch(comp.dispatch, MAP_KEY), key))
.setParams(params);
const newChildComp = childComp.reduce(childAction);

if (childComp !== newChildComp) {
Expand Down
23 changes: 11 additions & 12 deletions deploy/docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ CMD [ "/bin/sh", "/lowcoder/node-service/entrypoint.sh" ]
##
## Standalone image is built from server/proxy-service/Dockerfile
##
FROM node:22.23-slim AS build-proxy-service
FROM node:22.23.4-slim AS build-proxy-service

# Copy only the build inputs, so local build/ and node_modules folders are never picked up
COPY server/proxy-service/package.json server/proxy-service/yarn.lock server/proxy-service/tsconfig.json /lowcoder/proxy-service/app/
Expand All @@ -137,7 +137,7 @@ RUN chmod +x /lowcoder/proxy-service/*.sh
##
## Standalone image is built from deploy/docker/agora-token-service/Dockerfile
##
FROM node:22.23-slim AS build-agora-token-service
FROM node:22.23.4-slim AS build-agora-token-service

WORKDIR /lowcoder/agora-token-service/app
COPY deploy/docker/agora-token-service/package.json ./
Expand All @@ -157,7 +157,7 @@ RUN chmod +x /lowcoder/agora-token-service/*.sh
## HOCUSPOCUS_SERVER_VERSION in sync with it.
## @hocuspocus/server 4.x requires node >= 22.
##
FROM node:22.23-slim AS build-hocuspocus
FROM node:22.23.4-slim AS build-hocuspocus

ARG HOCUSPOCUS_SERVER_VERSION=4.3.0

Expand All @@ -176,7 +176,7 @@ RUN chmod +x /lowcoder/hocuspocus/*.sh
##
## Build lowcoder client application
##
FROM node:22.23-slim AS build-client
FROM node:22.23.4-slim AS build-client

# curl is required for yarn build to succeed, because it calls it while building client
RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates
Expand Down Expand Up @@ -217,7 +217,7 @@ RUN yarn build
## To create a separate image out of it, build it with:
## DOCKER_BUILDKIT=1 docker build -f deploy/docker/Dockerfile -t lowcoderorg/lowcoder-ce-frontend --target lowcoder-ce-frontend .
##
FROM nginx:1.27.1 AS lowcoder-ce-frontend
FROM nginx:1.30.6 AS lowcoder-ce-frontend
LABEL maintainer="lowcoder"

# Change default nginx user into lowcoder user and remove default nginx config
Expand Down Expand Up @@ -258,7 +258,7 @@ EXPOSE 3443
##
## Build lowcoder client (Enterprise) application
##
FROM node:22.23-slim AS build-client-ee
FROM node:22.23.4-slim AS build-client-ee

# curl is required for yarn build to succeed, because it calls it while building client
RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates
Expand Down Expand Up @@ -299,7 +299,7 @@ RUN yarn build
## To create a separate image out of it, build it with:
## DOCKER_BUILDKIT=1 docker build -f deploy/docker/Dockerfile -t lowcoderorg/lowcoder-ee-frontend --target lowcoder-ee-frontend .
##
FROM nginx:1.27.1 AS lowcoder-enterprise-frontend
FROM nginx:1.30.6 AS lowcoder-enterprise-frontend
LABEL maintainer="lowcoder"

# Change default nginx user into lowcoder user and remove default nginx config
Expand Down Expand Up @@ -357,12 +357,12 @@ RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg -
&& curl -fsSL https://www.mongodb.org/static/pgp/server-7.0.asc | gpg --dearmor -o /usr/share/keyrings/mongodb-archive-keyring.gpg \
&& echo "deb [signed-by=/usr/share/keyrings/mongodb-archive-keyring.gpg] https://repo.mongodb.org/apt/ubuntu `lsb_release -cs`/mongodb-org/7.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-7.0.list \
&& curl -fsSL https://nginx.org/keys/nginx_signing.key | gpg --dearmor -o /usr/share/keyrings/nginx-archive-keyring.gpg \
&& echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] http://nginx.org/packages/mainline/ubuntu `lsb_release -cs` nginx" | tee /etc/apt/sources.list.d/nginx.list
&& echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" | tee /etc/apt/sources.list.d/nginx.list


# Install required packages
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends -y \
nginx=1.27.1-1~jammy \
nginx=1.30.6-1~jammy \
mongodb-org \
redis \
supervisor \
Expand All @@ -376,8 +376,8 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -y install --no-ins

# Use configuration setup from official nginx image
RUN rm -rf /etc/nginx/nginx.conf
COPY --from=nginx:1.27.1 /docker-entrypoint.d /docker-entrypoint.d
COPY --from=nginx:1.27.1 /docker-entrypoint.sh /docker-entrypoint.sh
COPY --from=nginx:1.30.6 /docker-entrypoint.d /docker-entrypoint.d
COPY --from=nginx:1.30.6 /docker-entrypoint.sh /docker-entrypoint.sh

# Add lowcoder user
RUN usermod --login lowcoder --uid 9001 nginx \
Expand Down Expand Up @@ -450,4 +450,3 @@ EXPOSE 8081

ENTRYPOINT [ "/bin/sh" , "/lowcoder/entrypoint.sh" ]
CMD ["/usr/bin/supervisord", "-n" , "-c" , "/lowcoder/etc/supervisord.conf"]

2 changes: 1 addition & 1 deletion deploy/docker/agora-token-service/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:22-alpine
FROM node:22.23.4-alpine

WORKDIR /app

Expand Down
2 changes: 1 addition & 1 deletion deploy/docker/hocuspocus/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Hocuspocus (Yjs WebSocket) server for lowcoder ChatBox.
# Build context: client/packages/lowcoder (see Dockerfile.dockerignore next to this file)
FROM node:26-alpine
FROM node:26.12.1-alpine

ARG HOCUSPOCUS_SERVER_VERSION=4.3.0

Expand Down
2 changes: 1 addition & 1 deletion server/proxy-service/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:22-alpine
FROM node:22.23.4-alpine

WORKDIR /lowcoder/proxy-service

Expand Down
Loading