Skip to content

Commit 906df19

Browse files
Merge branch 'dev' into dynamic-style-fixes
2 parents 7929e20 + a28726f commit 906df19

File tree

18 files changed

+139
-31
lines changed

18 files changed

+139
-31
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ And we mean it... Day by day!
9090
## 💻 Deployment Options
9191
[![Deploy to AWS using Stitch](https://img.shields.io/badge/deploy_with-Stitch-%23E369F7?logo=amazonaws&color=%23E369F7)](https://deploy.stitch.tech/lowcoder/lowcoder)
9292

93-
[![Deploy in minutes on Elest.io](https://raw.githubusercontent.com/elestio-examples/element/main/deploy-on-elestio.png)](https://elest.io/open-source/lowcoder)
93+
[![Deploy to Elestio](https://img.shields.io/badge/Deploy_to-Elestio-%23E369F7?color=orange)](https://elest.io/open-source/lowcoder)
9494

9595
You can access Lowcoder from [cloud-hosted version](https://app.lowcoder.cloud/) at any time, or use the following resources for self-host Lowcoder on different platforms:
9696
- [Docker](https://docs.lowcoder.cloud/lowcoder-documentation/setup-and-run/self-hosting)
@@ -110,4 +110,4 @@ Like ... [@Darkjamin](https://github.com/Darkjamin), [@spacegoats-io](https://g
110110

111111
## Intro Video
112112

113-
[![Watch the video](https://i.ytimg.com/vi/s4ltAqS0hzM/maxresdefault.jpg?sqp=-oaymwEmCIAKENAF8quKqQMa8AEB-AH-CYAC0AWKAgwIABABGD0gSShyMA8=&rs=AOn4CLAlPOIFdtauythoBKNPXhi6XGwlDQ)](https://youtu.be/s4ltAqS0hzM?feature=shared)
113+
[![Watch the video](https://i.ytimg.com/vi/s4ltAqS0hzM/maxresdefault.jpg?sqp=-oaymwEmCIAKENAF8quKqQMa8AEB-AH-CYAC0AWKAgwIABABGD0gSShyMA8=&rs=AOn4CLAlPOIFdtauythoBKNPXhi6XGwlDQ)](https://youtu.be/s4ltAqS0hzM?feature=shared)

client/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@
8080
"chalk": "4",
8181
"flag-icons": "^7.2.1",
8282
"number-precision": "^1.6.0",
83-
"posthog-js": "^1.144.2",
83+
"posthog-js": "^1.155.4",
8484
"react-countup": "^6.5.3",
8585
"react-player": "^2.11.0",
8686
"resize-observer-polyfill": "^1.5.1",

client/packages/lowcoder/src/comps/generators/list.tsx

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ export type CustomListAction<CompCtor extends CompConstructor = CompConstructor>
2626
>;
2727

2828
type ListAction<CompCtor extends CompConstructor = CompConstructor> =
29+
| {
30+
type: "setChildrens";
31+
value: Array<ConstructorToDataType<CompCtor>>;
32+
}
2933
| {
3034
type: "push";
3135
value: ConstructorToDataType<CompCtor>;
@@ -145,7 +149,19 @@ export function list<ChildCompCtor extends CompConstructor<any, any>>(
145149

146150
private reduceCustom(action: ListAction<ChildCompCtor>): this {
147151
switch (action.type) {
148-
case "push":
152+
case "setChildrens": {
153+
const childrenMap: Record<number, ConstructorToComp<ChildCompCtor>> = {};
154+
const childrenOrder: number[] = [];
155+
action.value.forEach((children: any, key: number) => {
156+
childrenMap[key] = newChild(this.dispatch, String(key), children);
157+
childrenOrder.push(key);
158+
})
159+
return setFieldsNoTypeCheck(this, {
160+
children: childrenMap,
161+
childrenOrder: childrenOrder,
162+
});
163+
}
164+
case "push": {
149165
const key = this.genKey();
150166
const newChildren = {
151167
...this.children,
@@ -155,6 +171,7 @@ export function list<ChildCompCtor extends CompConstructor<any, any>>(
155171
children: newChildren,
156172
childrenOrder: [...this.childrenOrder, key],
157173
});
174+
}
158175
case "pushComp": {
159176
const key = this.genKey();
160177
const newChildren = {
@@ -209,6 +226,17 @@ export function list<ChildCompCtor extends CompConstructor<any, any>>(
209226
}
210227
}
211228
}
229+
230+
setChildrensAction(value: Array<ConstructorToDataType<ChildCompCtor>>) {
231+
return customAction<ListAction<ChildCompCtor>>(
232+
{
233+
type: "setChildrens",
234+
value: value,
235+
},
236+
true
237+
);
238+
}
239+
212240
pushAction(value: ConstructorToDataType<ChildCompCtor>) {
213241
return customAction<ListAction<ChildCompCtor>>(
214242
{

client/yarn.lock

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13822,7 +13822,7 @@ coolshapes-react@lowcoder-org/coolshapes-react:
1382213822
lowcoder-cli: "workspace:^"
1382313823
mq-polyfill: ^1.1.8
1382413824
number-precision: ^1.6.0
13825-
posthog-js: ^1.144.2
13825+
posthog-js: ^1.155.4
1382613826
prettier: ^3.1.0
1382713827
react-countup: ^6.5.3
1382813828
react-player: ^2.11.0
@@ -16126,14 +16126,14 @@ coolshapes-react@lowcoder-org/coolshapes-react:
1612616126
languageName: node
1612716127
linkType: hard
1612816128

16129-
"posthog-js@npm:^1.144.2":
16130-
version: 1.144.2
16131-
resolution: "posthog-js@npm:1.144.2"
16129+
"posthog-js@npm:^1.155.4":
16130+
version: 1.155.4
16131+
resolution: "posthog-js@npm:1.155.4"
1613216132
dependencies:
1613316133
fflate: ^0.4.8
1613416134
preact: ^10.19.3
1613516135
web-vitals: ^4.0.1
16136-
checksum: c856f49a34b825eb0678b40e137affa4a79a29ff64205f059a9a0ad78ce6ac8b3d8413f955e3fa72b08cf91e923e443aedb7e41b2e40c76c1cab20b88fe1c3d7
16136+
checksum: 749d180a4bfda0cb89307bad81eb230523c3e8f03dc94ac35dde212a130593a23dd98768bbff64753931dc501bca345397d7b39157dcc6eb174d57bd647c33d5
1613716137
languageName: node
1613816138
linkType: hard
1613916139

server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/model/Application.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ public class Application extends HasIdAndAuditing {
5252
private Boolean publicToMarketplace;
5353
@Setter
5454
private Boolean agencyProfile;
55+
@Getter
56+
@Setter
57+
private String editingUserId;
5558

5659
public Application(
5760
@JsonProperty("orgId") String organizationId,
@@ -63,7 +66,8 @@ public Application(
6366
@JsonProperty("editingApplicationDSL") Map<String, Object> editingApplicationDSL,
6467
@JsonProperty("publicToAll") Boolean publicToAll,
6568
@JsonProperty("publicToMarketplace") Boolean publicToMarketplace,
66-
@JsonProperty("agencyProfile") Boolean agencyProfile
69+
@JsonProperty("agencyProfile") Boolean agencyProfile,
70+
@JsonProperty("editingUserId") String editingUserId
6771
) {
6872
this.gid = gid;
6973
this.organizationId = organizationId;
@@ -75,6 +79,7 @@ public Application(
7579
this.publicToMarketplace = publicToMarketplace;
7680
this.agencyProfile = agencyProfile;
7781
this.editingApplicationDSL = editingApplicationDSL;
82+
this.editingUserId = editingUserId;
7883
}
7984

8085
@Transient

server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationHistorySnapshotService.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@ public interface ApplicationHistorySnapshotService {
1818

1919
Mono<ApplicationHistorySnapshot> getHistorySnapshotDetail(String historySnapshotId);
2020

21+
Mono<ApplicationHistorySnapshot> getLastSnapshotByApp(String applicationId);
2122
}

server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationService.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ public interface ApplicationService {
2323

2424
Mono<Application> publish(String applicationId);
2525

26+
Mono<Boolean> updateEditState(String applicationId, Boolean editingFinished);
27+
2628
Mono<Application> create(Application newApplication, String visitorId);
2729

2830
Flux<Application> findByOrganizationIdWithDsl(String organizationId);

server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationServiceImpl.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,16 @@ public Mono<Application> publish(String applicationId) {
9393
});
9494
}
9595

96+
@Override
97+
public Mono<Boolean> updateEditState(String applicationId, Boolean editingFinished) {
98+
return findById(applicationId)
99+
.flatMap(newApplication -> {
100+
Application application = Application.builder().editingUserId("").build();
101+
if(editingFinished) return mongoUpsertHelper.updateById(application, applicationId);
102+
return Mono.just(true);
103+
});
104+
}
105+
96106
@Override
97107
public Mono<Application> create(Application newApplication, String visitorId) {
98108
return repository.save(newApplication)

server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/impl/ApplicationHistorySnapshotServiceImpl.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import static org.lowcoder.sdk.util.ExceptionUtils.deferredError;
55
import static org.lowcoder.sdk.util.ExceptionUtils.ofException;
66

7+
import java.time.Instant;
78
import java.util.List;
89
import java.util.Map;
910

@@ -57,4 +58,13 @@ public Mono<ApplicationHistorySnapshot> getHistorySnapshotDetail(String historyS
5758
return repository.findById(historySnapshotId)
5859
.switchIfEmpty(deferredError(INVALID_HISTORY_SNAPSHOT, "INVALID_HISTORY_SNAPSHOT", historySnapshotId));
5960
}
61+
62+
@Override
63+
public Mono<ApplicationHistorySnapshot> getLastSnapshotByApp(String applicationId) {
64+
ApplicationHistorySnapshot _default = new ApplicationHistorySnapshot();
65+
_default.setCreatedAt(Instant.ofEpochMilli(0));
66+
_default.setCreatedBy("");
67+
return repository.findAllByApplicationId(applicationId, PageRequest.of(0, 1).withSort(Direction.DESC, "createdAt"))
68+
.switchIfEmpty(Mono.just(_default)).next();
69+
}
6070
}

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationApiService.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ public interface ApplicationApiService {
3535

3636
Mono<ApplicationView> publish(String applicationId);
3737

38+
Mono<Boolean> updateEditState(String applicationId, ApplicationEndpoints.UpdateEditStateRequest updateEditStateRequest);
39+
3840
Mono<Boolean> grantPermission(String applicationId,
3941
Set<String> userIds,
4042
Set<String> groupIds, ResourceRole role);

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationApiServiceImpl.java

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,8 @@
2121
import org.lowcoder.api.permission.PermissionHelper;
2222
import org.lowcoder.api.permission.view.PermissionItemView;
2323
import org.lowcoder.api.usermanagement.OrgDevChecker;
24-
import org.lowcoder.domain.application.model.Application;
25-
import org.lowcoder.domain.application.model.ApplicationRequestType;
26-
import org.lowcoder.domain.application.model.ApplicationStatus;
27-
import org.lowcoder.domain.application.model.ApplicationType;
24+
import org.lowcoder.domain.application.model.*;
25+
import org.lowcoder.domain.application.service.ApplicationHistorySnapshotService;
2826
import org.lowcoder.domain.application.service.ApplicationService;
2927
import org.lowcoder.domain.datasource.model.Datasource;
3028
import org.lowcoder.domain.datasource.service.DatasourceService;
@@ -45,7 +43,6 @@
4543
import org.lowcoder.sdk.exception.BizException;
4644
import org.lowcoder.sdk.plugin.common.QueryExecutor;
4745
import org.lowcoder.sdk.util.ExceptionUtils;
48-
import org.springframework.context.annotation.Lazy;
4946
import org.springframework.http.HttpHeaders;
5047
import org.springframework.stereotype.Service;
5148
import reactor.core.publisher.Flux;
@@ -58,7 +55,6 @@
5855
import java.util.List;
5956
import java.util.Map;
6057
import java.util.Set;
61-
import java.util.concurrent.TimeUnit;
6258
import java.util.stream.Collectors;
6359

6460
import static org.lowcoder.domain.application.model.ApplicationStatus.NORMAL;
@@ -94,6 +90,7 @@ public class ApplicationApiServiceImpl implements ApplicationApiService {
9490
private final TemplateService templateService;
9591
private final PermissionHelper permissionHelper;
9692
private final DatasourceService datasourceService;
93+
private final ApplicationHistorySnapshotService applicationHistorySnapshotService;
9794

9895
@Override
9996
public Mono<ApplicationView> create(CreateApplicationRequest createApplicationRequest) {
@@ -105,7 +102,7 @@ public Mono<ApplicationView> create(CreateApplicationRequest createApplicationRe
105102
NORMAL,
106103
createApplicationRequest.publishedApplicationDSL(),
107104
createApplicationRequest.editingApplicationDSL(),
108-
false, false, false);
105+
false, false, false, "");
109106

110107
if (StringUtils.isBlank(application.getOrganizationId())) {
111108
return deferredError(INVALID_PARAMETER, "ORG_ID_EMPTY");
@@ -259,19 +256,28 @@ public Mono<ApplicationView> getEditingApplication(String applicationId) {
259256
.delayUntil(application -> checkApplicationStatus(application, NORMAL)))
260257
.zipWhen(tuple -> applicationService.getAllDependentModulesFromApplication(tuple.getT2(), false), TupleUtils::merge)
261258
.zipWhen(tuple -> organizationService.getOrgCommonSettings(tuple.getT2().getOrganizationId()), TupleUtils::merge)
262-
.map(tuple -> {
263-
ResourcePermission permission = tuple.getT1();
264-
Application application = tuple.getT2();
265-
List<Application> dependentModules = tuple.getT3();
266-
Map<String, Object> commonSettings = tuple.getT4();
259+
.zipWhen(tuple -> sessionUserService.getVisitorId().zipWith(applicationHistorySnapshotService.getLastSnapshotByApp(applicationId)))
260+
.flatMap(tuple -> {
261+
ResourcePermission permission = tuple.getT1().getT1();
262+
Application application = tuple.getT1().getT2();
263+
List<Application> dependentModules = tuple.getT1().getT3();
264+
Map<String, Object> commonSettings = tuple.getT1().getT4();
265+
String visitorId = tuple.getT2().getT1();
266+
ApplicationHistorySnapshot lastSnapshot = tuple.getT2().getT2();
267+
268+
if(!visitorId.equals(application.getEditingUserId()) && lastSnapshot.getCreatedAt().compareTo(Instant.now().minusSeconds(300)) < 0) {
269+
application.setEditingUserId(visitorId);
270+
}
271+
267272
Map<String, Map<String, Object>> dependentModuleDsl = dependentModules.stream()
268273
.collect(Collectors.toMap(Application::getId, Application::getLiveApplicationDsl, (a, b) -> b));
269-
return ApplicationView.builder()
274+
return applicationService.updateById(applicationId, application).map(__ ->
275+
ApplicationView.builder()
270276
.applicationInfoView(buildView(application, permission.getResourceRole().getValue()))
271277
.applicationDSL(application.getEditingApplicationDSL())
272278
.moduleDSL(dependentModuleDsl)
273279
.orgCommonSettings(commonSettings)
274-
.build();
280+
.build());
275281
});
276282
}
277283

@@ -365,6 +371,15 @@ public Mono<ApplicationView> publish(String applicationId) {
365371
.build()));
366372
}
367373

374+
@Override
375+
public Mono<Boolean> updateEditState(String applicationId, ApplicationEndpoints.UpdateEditStateRequest updateEditStateRequest) {
376+
return checkApplicationStatus(applicationId, NORMAL)
377+
.then(sessionUserService.getVisitorId())
378+
.flatMap(userId -> resourcePermissionService.checkAndReturnMaxPermission(userId,
379+
applicationId, EDIT_APPLICATIONS))
380+
.flatMap(permission -> applicationService.updateEditState(applicationId, updateEditStateRequest.editingFinished()));
381+
}
382+
368383
@Override
369384
public Mono<Boolean> grantPermission(String applicationId,
370385
Set<String> userIds,
@@ -540,6 +555,7 @@ private ApplicationInfoView buildView(Application application, String role, @Nul
540555
.publicToAll(application.isPublicToAll())
541556
.publicToMarketplace(application.isPublicToMarketplace())
542557
.agencyProfile(application.agencyProfile())
558+
.editingUserId(application.getEditingUserId())
543559
.build();
544560
}
545561

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationController.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,13 @@ public Mono<ResponseView<ApplicationView>> publish(@PathVariable String applicat
142142
.map(ResponseView::success);
143143
}
144144

145+
@Override
146+
public Mono<ResponseView<Boolean>> updateEditState(@PathVariable String applicationId, @RequestBody UpdateEditStateRequest updateEditStateRequest) {
147+
String appId = gidService.convertApplicationIdToObjectId(applicationId);
148+
return applicationApiService.updateEditState(appId, updateEditStateRequest)
149+
.map(ResponseView::success);
150+
}
151+
145152
@Override
146153
public Mono<ResponseView<UserHomepageView>> getUserHomePage(@RequestParam(required = false, defaultValue = "0") int applicationType) {
147154
ApplicationType type = ApplicationType.fromValue(applicationType);

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationEndpoints.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,16 @@ public Mono<ResponseView<ApplicationView>> update(@PathVariable String applicati
137137
@PostMapping("/{applicationId}/publish")
138138
public Mono<ResponseView<ApplicationView>> publish(@PathVariable String applicationId);
139139

140+
@Operation(
141+
tags = TAG_APPLICATION_MANAGEMENT,
142+
operationId = "updateApplicationEditingState",
143+
summary = "Update Application editing state",
144+
description = "Update the editing state of a specific Lowcoder Application identified by its ID."
145+
)
146+
@PutMapping("/editState/{applicationId}")
147+
public Mono<ResponseView<Boolean>> updateEditState(@PathVariable String applicationId,
148+
@RequestBody UpdateEditStateRequest updateEditStateRequest);
149+
140150
@Operation(
141151
tags = TAG_APPLICATION_MANAGEMENT,
142152
operationId = "getUserHomepageApplication",
@@ -285,5 +295,7 @@ public record CreateApplicationRequest(@JsonProperty("orgId") String organizatio
285295
Map<String, Object> editingApplicationDSL,
286296
@Nullable String folderId) {
287297
}
298+
public record UpdateEditStateRequest(Boolean editingFinished) {
299+
}
288300

289301
}

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/view/ApplicationInfoView.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ public class ApplicationInfoView {
3838
private final boolean publicToMarketplace;
3939
private final boolean agencyProfile;
4040

41+
private final String editingUserId;
42+
4143
public long getLastViewTime() {
4244
return lastViewTime == null ? 0 : lastViewTime.toEpochMilli();
4345
}

0 commit comments

Comments
 (0)