From 52c81cf3b4f03bb30766beeac89f664054367f29 Mon Sep 17 00:00:00 2001 From: Thomasr Date: Tue, 19 Nov 2024 19:34:29 -0500 Subject: [PATCH 01/28] Increase Heap Size --- deploy/docker/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/deploy/docker/Dockerfile b/deploy/docker/Dockerfile index 2c2bc5c27..5ecbbd579 100644 --- a/deploy/docker/Dockerfile +++ b/deploy/docker/Dockerfile @@ -17,6 +17,7 @@ COPY server/api-service/lowcoder-server/src/main/resources/application.yaml /low # Add bootstrapfile COPY deploy/docker/api-service/entrypoint.sh /lowcoder/api-service/entrypoint.sh COPY deploy/docker/api-service/init.sh /lowcoder/api-service/init.sh +ENV JAVA_OPTS="-Xmx2G -Xms512M" RUN chmod +x /lowcoder/api-service/*.sh ## From 24ba4bdabef1ee01f968455a42cbc1ccd8625254 Mon Sep 17 00:00:00 2001 From: Thomasr Date: Wed, 20 Nov 2024 03:34:25 -0500 Subject: [PATCH 02/28] convert snapshot migration to use aggregation pipeline --- .../runner/migrations/DatabaseChangelog.java | 45 +++++++++++-------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/runner/migrations/DatabaseChangelog.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/runner/migrations/DatabaseChangelog.java index ddf0422ab..2cd26381a 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/runner/migrations/DatabaseChangelog.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/runner/migrations/DatabaseChangelog.java @@ -44,6 +44,7 @@ import java.time.Instant; import java.time.temporal.ChronoUnit; +import java.util.Arrays; import java.util.List; import java.util.Set; @@ -319,35 +320,43 @@ public void addTimeSeriesSnapshotHistory(MongockTemplate mongoTemplate, CommonCo // Create the time-series collection if it doesn't exist if (!mongoTemplate.collectionExists(ApplicationHistorySnapshotTS.class)) { - if(mongoVersion < 5) { + if (mongoVersion < 5) { mongoTemplate.createCollection(ApplicationHistorySnapshotTS.class); } else { mongoTemplate.createCollection(ApplicationHistorySnapshotTS.class, CollectionOptions.empty().timeSeries("createdAt")); } } + Instant thresholdDate = Instant.now().minus(commonConfig.getQuery().getAppSnapshotKeepDuration(), ChronoUnit.DAYS); - List snapshots = mongoTemplate.find(new Query().addCriteria(Criteria.where("createdAt").gte(thresholdDate)), ApplicationHistorySnapshot.class); - snapshots.forEach(snapshot -> { - ApplicationHistorySnapshotTS applicationHistorySnapshotTS = new ApplicationHistorySnapshotTS(); - applicationHistorySnapshotTS.setApplicationId(snapshot.getApplicationId()); - applicationHistorySnapshotTS.setDsl(snapshot.getDsl()); - applicationHistorySnapshotTS.setContext(snapshot.getContext()); - applicationHistorySnapshotTS.setCreatedAt(snapshot.getCreatedAt()); - applicationHistorySnapshotTS.setCreatedBy(snapshot.getCreatedBy()); - applicationHistorySnapshotTS.setModifiedBy(snapshot.getModifiedBy()); - applicationHistorySnapshotTS.setUpdatedAt(snapshot.getUpdatedAt()); - applicationHistorySnapshotTS.setId(snapshot.getId()); - mongoTemplate.insert(applicationHistorySnapshotTS); - mongoTemplate.remove(snapshot); - }); - // Ensure indexes if needed + // Use aggregation to move and transform data + Document match = new Document("$match", + new Document("createdAt", new Document("$gte", thresholdDate))); + + Document project = new Document("$project", new Document() + .append("applicationId", 1) + .append("dsl", 1) + .append("context", 1) + .append("createdAt", 1) + .append("createdBy", 1) + .append("modifiedBy", 1) + .append("updatedAt", 1) + .append("id", "$_id")); // Map MongoDB's default `_id` to `id` if needed. + + Document out = new Document("$out", "applicationHistorySnapshotTS"); // Target collection name + + // Execute the aggregation pipeline + mongoTemplate.getDb() + .getCollection("applicationHistorySnapshot") // Original collection name + .aggregate(Arrays.asList(match, project, out)) + .toCollection(); + ensureIndexes(mongoTemplate, ApplicationHistorySnapshotTS.class, makeIndex("applicationId"), - makeIndex("createdAt") - ); + makeIndex("createdAt")); } + private void addGidField(MongockTemplate mongoTemplate, String collectionName) { // Create a query to match all documents Query query = new Query(); From 0c5c344ea72ce57d26edd093ed468dc8b45c1cd5 Mon Sep 17 00:00:00 2001 From: Thomasr Date: Wed, 20 Nov 2024 03:48:52 -0500 Subject: [PATCH 03/28] delete after copying records --- .../org/lowcoder/runner/migrations/DatabaseChangelog.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/runner/migrations/DatabaseChangelog.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/runner/migrations/DatabaseChangelog.java index 2cd26381a..ba5324923 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/runner/migrations/DatabaseChangelog.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/runner/migrations/DatabaseChangelog.java @@ -4,6 +4,7 @@ import com.github.cloudyrock.mongock.ChangeSet; import com.github.cloudyrock.mongock.driver.mongodb.springdata.v4.decorator.impl.MongockTemplate; import com.github.f4b6a3.uuid.UuidCreator; +import com.mongodb.client.result.DeleteResult; import lombok.extern.slf4j.Slf4j; import org.bson.Document; import org.lowcoder.domain.application.model.Application; @@ -351,6 +352,10 @@ public void addTimeSeriesSnapshotHistory(MongockTemplate mongoTemplate, CommonCo .aggregate(Arrays.asList(match, project, out)) .toCollection(); + // Delete the migrated records + Query deleteQuery = new Query(Criteria.where("createdAt").gte(thresholdDate)); + DeleteResult deleteResult = mongoTemplate.remove(deleteQuery, ApplicationHistorySnapshot.class); + ensureIndexes(mongoTemplate, ApplicationHistorySnapshotTS.class, makeIndex("applicationId"), makeIndex("createdAt")); From 1eca3afffdb63da4ca7b5dca9d673c0a8fd62853 Mon Sep 17 00:00:00 2001 From: Thomasr Date: Wed, 20 Nov 2024 03:58:20 -0500 Subject: [PATCH 04/28] different migration based on mongo version. --- .../runner/migrations/DatabaseChangelog.java | 101 ++++++++++++------ 1 file changed, 68 insertions(+), 33 deletions(-) diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/runner/migrations/DatabaseChangelog.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/runner/migrations/DatabaseChangelog.java index ba5324923..153fd765f 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/runner/migrations/DatabaseChangelog.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/runner/migrations/DatabaseChangelog.java @@ -4,6 +4,8 @@ import com.github.cloudyrock.mongock.ChangeSet; import com.github.cloudyrock.mongock.driver.mongodb.springdata.v4.decorator.impl.MongockTemplate; import com.github.f4b6a3.uuid.UuidCreator; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoCursor; import com.mongodb.client.result.DeleteResult; import lombok.extern.slf4j.Slf4j; import org.bson.Document; @@ -315,47 +317,80 @@ private int getMongoDBVersion(MongockTemplate mongoTemplate) { @ChangeSet(order = "026", id = "add-time-series-snapshot-history", author = "") public void addTimeSeriesSnapshotHistory(MongockTemplate mongoTemplate, CommonConfig commonConfig) { int mongoVersion = getMongoDBVersion(mongoTemplate); - if (mongoVersion < 5) { - log.warn("MongoDB version is below 5. Time-series collections are not supported. Upgrade the MongoDB version."); - } - - // Create the time-series collection if it doesn't exist - if (!mongoTemplate.collectionExists(ApplicationHistorySnapshotTS.class)) { - if (mongoVersion < 5) { - mongoTemplate.createCollection(ApplicationHistorySnapshotTS.class); - } else { - mongoTemplate.createCollection(ApplicationHistorySnapshotTS.class, CollectionOptions.empty().timeSeries("createdAt")); - } - } Instant thresholdDate = Instant.now().minus(commonConfig.getQuery().getAppSnapshotKeepDuration(), ChronoUnit.DAYS); - // Use aggregation to move and transform data - Document match = new Document("$match", - new Document("createdAt", new Document("$gte", thresholdDate))); + if (mongoVersion >= 5) { + // MongoDB version >= 5: Use manual insert query + if (!mongoTemplate.collectionExists(ApplicationHistorySnapshotTS.class)) { + mongoTemplate.createCollection(ApplicationHistorySnapshotTS.class, + CollectionOptions.empty().timeSeries("createdAt")); + } - Document project = new Document("$project", new Document() - .append("applicationId", 1) - .append("dsl", 1) - .append("context", 1) - .append("createdAt", 1) - .append("createdBy", 1) - .append("modifiedBy", 1) - .append("updatedAt", 1) - .append("id", "$_id")); // Map MongoDB's default `_id` to `id` if needed. + // Aggregation pipeline to fetch the records + List aggregationPipeline = Arrays.asList( + new Document("$match", new Document("createdAt", new Document("$gte", thresholdDate))), + new Document("$project", new Document() + .append("applicationId", 1) + .append("dsl", 1) + .append("context", 1) + .append("createdAt", 1) + .append("createdBy", 1) + .append("modifiedBy", 1) + .append("updatedAt", 1) + .append("id", "$_id")) // Map `_id` to `id` if needed + ); + + MongoCollection sourceCollection = mongoTemplate.getDb().getCollection("applicationHistorySnapshot"); + MongoCollection targetCollection = mongoTemplate.getDb().getCollection("applicationHistorySnapshotTS"); + + // Fetch results and insert them into the time-series collection + try (MongoCursor cursor = sourceCollection.aggregate(aggregationPipeline).iterator()) { + while (cursor.hasNext()) { + Document document = cursor.next(); + targetCollection.insertOne(document); // Insert into the time-series collection + } + } - Document out = new Document("$out", "applicationHistorySnapshotTS"); // Target collection name + // Delete the migrated records + Query deleteQuery = new Query(Criteria.where("createdAt").gte(thresholdDate)); + DeleteResult deleteResult = mongoTemplate.remove(deleteQuery, ApplicationHistorySnapshot.class); - // Execute the aggregation pipeline - mongoTemplate.getDb() - .getCollection("applicationHistorySnapshot") // Original collection name - .aggregate(Arrays.asList(match, project, out)) - .toCollection(); + log.info("Deleted {} records from the source collection.", deleteResult.getDeletedCount()); + } else { + // MongoDB version < 5: Use aggregation with $out + if (!mongoTemplate.collectionExists(ApplicationHistorySnapshotTS.class)) { + mongoTemplate.createCollection(ApplicationHistorySnapshotTS.class); // Create a regular collection + } - // Delete the migrated records - Query deleteQuery = new Query(Criteria.where("createdAt").gte(thresholdDate)); - DeleteResult deleteResult = mongoTemplate.remove(deleteQuery, ApplicationHistorySnapshot.class); + // Aggregation pipeline with $out + List aggregationPipeline = Arrays.asList( + new Document("$match", new Document("createdAt", new Document("$gte", thresholdDate))), + new Document("$project", new Document() + .append("applicationId", 1) + .append("dsl", 1) + .append("context", 1) + .append("createdAt", 1) + .append("createdBy", 1) + .append("modifiedBy", 1) + .append("updatedAt", 1) + .append("id", "$_id")), // Map `_id` to `id` if needed + new Document("$out", "applicationHistorySnapshotTS") // Write directly to the target collection + ); + + mongoTemplate.getDb() + .getCollection("applicationHistorySnapshot") + .aggregate(aggregationPipeline) + .toCollection(); + + // Delete the migrated records + Query deleteQuery = new Query(Criteria.where("createdAt").gte(thresholdDate)); + DeleteResult deleteResult = mongoTemplate.remove(deleteQuery, ApplicationHistorySnapshot.class); + + log.info("Deleted {} records from the source collection.", deleteResult.getDeletedCount()); + } + // Ensure indexes on the new collection ensureIndexes(mongoTemplate, ApplicationHistorySnapshotTS.class, makeIndex("applicationId"), makeIndex("createdAt")); From b60590787bb2b8457caecd2a5bbaee2b49191552 Mon Sep 17 00:00:00 2001 From: Thomasr Date: Thu, 21 Nov 2024 08:42:52 -0500 Subject: [PATCH 05/28] modify to use aggregate --- .../runner/task/ArchiveSnapshotTask.java | 138 +++++++++++++++--- 1 file changed, 119 insertions(+), 19 deletions(-) diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/runner/task/ArchiveSnapshotTask.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/runner/task/ArchiveSnapshotTask.java index 2fa516379..1a2559ad9 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/runner/task/ArchiveSnapshotTask.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/runner/task/ArchiveSnapshotTask.java @@ -2,12 +2,8 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.lowcoder.domain.application.model.ApplicationHistorySnapshot; -import org.lowcoder.domain.application.model.ApplicationHistorySnapshotTS; import org.lowcoder.sdk.config.CommonConfig; import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.data.mongodb.core.query.Criteria; -import org.springframework.data.mongodb.core.query.Query; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @@ -16,6 +12,11 @@ import java.util.List; import java.util.concurrent.TimeUnit; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoCursor; +import com.mongodb.client.model.Filters; +import org.bson.Document; + @Slf4j @RequiredArgsConstructor @Component @@ -24,23 +25,122 @@ public class ArchiveSnapshotTask { private final CommonConfig commonConfig; private final MongoTemplate mongoTemplate; - @Scheduled(initialDelay = 1, fixedRate = 1, timeUnit = TimeUnit.DAYS) + @Scheduled(initialDelay = 0, fixedRate = 1, timeUnit = TimeUnit.DAYS) public void archive() { + int mongoVersion = getMongoDBVersion(); Instant thresholdDate = Instant.now().minus(commonConfig.getQuery().getAppSnapshotKeepDuration(), ChronoUnit.DAYS); - List snapshots = mongoTemplate.find(new Query().addCriteria(Criteria.where("createdAt").lte(thresholdDate)), ApplicationHistorySnapshotTS.class); - snapshots.forEach(snapshot -> { - ApplicationHistorySnapshot applicationHistorySnapshot = new ApplicationHistorySnapshot(); - applicationHistorySnapshot.setApplicationId(snapshot.getApplicationId()); - applicationHistorySnapshot.setDsl(snapshot.getDsl()); - applicationHistorySnapshot.setContext(snapshot.getContext()); - applicationHistorySnapshot.setCreatedAt(snapshot.getCreatedAt()); - applicationHistorySnapshot.setCreatedBy(snapshot.getCreatedBy()); - applicationHistorySnapshot.setModifiedBy(snapshot.getModifiedBy()); - applicationHistorySnapshot.setUpdatedAt(snapshot.getUpdatedAt()); - applicationHistorySnapshot.setId(snapshot.getId()); - mongoTemplate.insert(applicationHistorySnapshot); - mongoTemplate.remove(snapshot); - }); + + if (mongoVersion >= 5) { + archiveForVersion5AndAbove(thresholdDate); + } else { + archiveForVersionBelow5(thresholdDate); + } + } + + private int getMongoDBVersion() { + Document buildInfo = mongoTemplate.getDb().runCommand(new Document("buildInfo", 1)); + String version = buildInfo.getString("version"); + return Integer.parseInt(version.split("\\.")[0]); // Parse major version } + private void archiveForVersion5AndAbove(Instant thresholdDate) { + log.info("Running archival for MongoDB version >= 5"); + + MongoCollection sourceCollection = mongoTemplate.getDb().getCollection("applicationHistorySnapshotTS"); + MongoCollection targetCollection = mongoTemplate.getDb().getCollection("applicationHistorySnapshot"); + + long totalDocuments = sourceCollection.countDocuments(Filters.lte("createdAt", thresholdDate)); + log.info("Total documents to archive: {}", totalDocuments); + + long processedCount = 0; + + try (MongoCursor cursor = sourceCollection.find(Filters.lte("createdAt", thresholdDate)).iterator()) { + while (cursor.hasNext()) { + Document document = cursor.next(); + + // Transform the document for the target collection + document.put("id", document.getObjectId("_id")); // Map `_id` to `id` + document.remove("_id"); + + // Insert the document into the target collection + try { + targetCollection.insertOne(document); + } catch (Exception e) { + log.error("Failed to insert document with ID {}. Error: {}", document.getObjectId("id"), e.getMessage()); + continue; + } + + // Remove the document from the source collection + try { + sourceCollection.deleteOne(Filters.eq("_id", document.getObjectId("id"))); + } catch (Exception e) { + log.error("Failed to delete document with ID {}. Error: {}", document.getObjectId("id"), e.getMessage()); + continue; + } + + processedCount++; + log.info("Processed document {} / {}", processedCount, totalDocuments); + } + } catch (Exception e) { + log.error("Failed during archival process. Error: {}", e.getMessage()); + } + + log.info("Archival process completed. Total documents archived: {}", processedCount); + } + + private void archiveForVersionBelow5(Instant thresholdDate) { + log.info("Running archival for MongoDB version < 5"); + + MongoCollection sourceCollection = mongoTemplate.getDb().getCollection("applicationHistorySnapshotTS"); + + long totalDocuments = sourceCollection.countDocuments(Filters.lte("createdAt", thresholdDate)); + log.info("Total documents to archive: {}", totalDocuments); + + long processedCount = 0; + + try (MongoCursor cursor = sourceCollection.find(Filters.lte("createdAt", thresholdDate)).iterator()) { + while (cursor.hasNext()) { + Document document = cursor.next(); + + // Transform the document for the target collection + document.put("id", document.getObjectId("_id")); // Map `_id` to `id` + document.remove("_id"); + + // Use aggregation with $out for the single document + try { + sourceCollection.aggregate(List.of( + Filters.eq("_id", document.getObjectId("id")), + new Document("$project", new Document() + .append("applicationId", document.get("applicationId")) + .append("dsl", document.get("dsl")) + .append("context", document.get("context")) + .append("createdAt", document.get("createdAt")) + .append("createdBy", document.get("createdBy")) + .append("modifiedBy", document.get("modifiedBy")) + .append("updatedAt", document.get("updatedAt")) + .append("id", document.get("id"))), + new Document("$out", "applicationHistorySnapshot") + )).first(); + } catch (Exception e) { + log.error("Failed to aggregate and insert document with ID {}. Error: {}", document.getObjectId("id"), e.getMessage()); + continue; + } + + // Remove the document from the source collection + try { + sourceCollection.deleteOne(Filters.eq("_id", document.getObjectId("id"))); + } catch (Exception e) { + log.error("Failed to delete document with ID {}. Error: {}", document.getObjectId("id"), e.getMessage()); + continue; + } + + processedCount++; + log.info("Processed document {} / {}", processedCount, totalDocuments); + } + } catch (Exception e) { + log.error("Failed during archival process. Error: {}", e.getMessage()); + } + + log.info("Archival process completed. Total documents archived: {}", processedCount); + } } From f7a6179e51f25fd0d5cd8e74fe4e91febf7be2b3 Mon Sep 17 00:00:00 2001 From: Thomasr Date: Thu, 21 Nov 2024 12:42:26 -0500 Subject: [PATCH 06/28] modify snapshot task logic to move from normal collection to timeseries one. --- .../org/lowcoder/runner/migrations/DatabaseChangelog.java | 4 ++-- .../org/lowcoder/runner/task/ArchiveSnapshotTask.java | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/runner/migrations/DatabaseChangelog.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/runner/migrations/DatabaseChangelog.java index 153fd765f..a51a74e09 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/runner/migrations/DatabaseChangelog.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/runner/migrations/DatabaseChangelog.java @@ -329,7 +329,7 @@ public void addTimeSeriesSnapshotHistory(MongockTemplate mongoTemplate, CommonCo // Aggregation pipeline to fetch the records List aggregationPipeline = Arrays.asList( - new Document("$match", new Document("createdAt", new Document("$gte", thresholdDate))), + new Document("$match", new Document("createdAt", new Document("$lte", thresholdDate))), new Document("$project", new Document() .append("applicationId", 1) .append("dsl", 1) @@ -365,7 +365,7 @@ public void addTimeSeriesSnapshotHistory(MongockTemplate mongoTemplate, CommonCo // Aggregation pipeline with $out List aggregationPipeline = Arrays.asList( - new Document("$match", new Document("createdAt", new Document("$gte", thresholdDate))), + new Document("$match", new Document("createdAt", new Document("$lte", thresholdDate))), new Document("$project", new Document() .append("applicationId", 1) .append("dsl", 1) diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/runner/task/ArchiveSnapshotTask.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/runner/task/ArchiveSnapshotTask.java index 1a2559ad9..28108f51a 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/runner/task/ArchiveSnapshotTask.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/runner/task/ArchiveSnapshotTask.java @@ -46,8 +46,8 @@ private int getMongoDBVersion() { private void archiveForVersion5AndAbove(Instant thresholdDate) { log.info("Running archival for MongoDB version >= 5"); - MongoCollection sourceCollection = mongoTemplate.getDb().getCollection("applicationHistorySnapshotTS"); - MongoCollection targetCollection = mongoTemplate.getDb().getCollection("applicationHistorySnapshot"); + MongoCollection sourceCollection = mongoTemplate.getDb().getCollection("applicationHistorySnapshot"); + MongoCollection targetCollection = mongoTemplate.getDb().getCollection("applicationHistorySnapshotTS"); long totalDocuments = sourceCollection.countDocuments(Filters.lte("createdAt", thresholdDate)); log.info("Total documents to archive: {}", totalDocuments); @@ -91,7 +91,7 @@ private void archiveForVersion5AndAbove(Instant thresholdDate) { private void archiveForVersionBelow5(Instant thresholdDate) { log.info("Running archival for MongoDB version < 5"); - MongoCollection sourceCollection = mongoTemplate.getDb().getCollection("applicationHistorySnapshotTS"); + MongoCollection sourceCollection = mongoTemplate.getDb().getCollection("applicationHistorySnapshot"); long totalDocuments = sourceCollection.countDocuments(Filters.lte("createdAt", thresholdDate)); log.info("Total documents to archive: {}", totalDocuments); @@ -119,7 +119,7 @@ private void archiveForVersionBelow5(Instant thresholdDate) { .append("modifiedBy", document.get("modifiedBy")) .append("updatedAt", document.get("updatedAt")) .append("id", document.get("id"))), - new Document("$out", "applicationHistorySnapshot") + new Document("$out", "applicationHistorySnapshotTS") )).first(); } catch (Exception e) { log.error("Failed to aggregate and insert document with ID {}. Error: {}", document.getObjectId("id"), e.getMessage()); From 138ebd86b0707f1a7127bbbb273239aeeb2aa0c1 Mon Sep 17 00:00:00 2001 From: Thomasr Date: Fri, 22 Nov 2024 03:21:05 -0500 Subject: [PATCH 07/28] swap ts and normal collection in api endpoint --- ...tionHistoryArchivedSnapshotRepository.java | 6 ++-- .../ApplicationHistorySnapshotRepository.java | 6 ++-- .../ApplicationHistorySnapshotService.java | 8 ++--- ...ApplicationHistorySnapshotServiceImpl.java | 18 ++++++------ .../ApplicationHistorySnapshotController.java | 29 ++++++++++--------- 5 files changed, 34 insertions(+), 33 deletions(-) diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/repository/ApplicationHistoryArchivedSnapshotRepository.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/repository/ApplicationHistoryArchivedSnapshotRepository.java index dded29c35..548d6e439 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/repository/ApplicationHistoryArchivedSnapshotRepository.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/repository/ApplicationHistoryArchivedSnapshotRepository.java @@ -1,6 +1,6 @@ package org.lowcoder.domain.application.repository; -import org.lowcoder.domain.application.model.ApplicationHistorySnapshot; +import org.lowcoder.domain.application.model.ApplicationHistorySnapshotTS; import org.springframework.data.domain.Pageable; import org.springframework.data.mongodb.repository.Query; import org.springframework.data.mongodb.repository.ReactiveMongoRepository; @@ -11,7 +11,7 @@ import java.time.Instant; @Repository -public interface ApplicationHistoryArchivedSnapshotRepository extends ReactiveMongoRepository { +public interface ApplicationHistoryArchivedSnapshotRepository extends ReactiveMongoRepository { @Query(value = "{ 'applicationId': ?0, $and: [" + "{$or: [ { 'context.operations': { $elemMatch: { 'compName': ?1 } } }, { $expr: { $eq: [?1, null] } } ]}, " + @@ -20,7 +20,7 @@ public interface ApplicationHistoryArchivedSnapshotRepository extends ReactiveMo "{$or: [ { 'createdAt': { $lte: ?4} }, { $expr: { $eq: [?4, null] } } ] } " + "]}", fields = "{applicationId : 1, context: 1, createdBy : 1, createdAt : 1}") - Flux findAllByApplicationId(String applicationId, String compName, String theme, Instant createdAtFrom, Instant createdAtTo, Pageable pageable); + Flux findAllByApplicationId(String applicationId, String compName, String theme, Instant createdAtFrom, Instant createdAtTo, Pageable pageable); Mono countByApplicationId(String applicationId); } diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/repository/ApplicationHistorySnapshotRepository.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/repository/ApplicationHistorySnapshotRepository.java index 809decfd6..eabf2caf6 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/repository/ApplicationHistorySnapshotRepository.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/repository/ApplicationHistorySnapshotRepository.java @@ -1,6 +1,6 @@ package org.lowcoder.domain.application.repository; -import org.lowcoder.domain.application.model.ApplicationHistorySnapshotTS; +import org.lowcoder.domain.application.model.ApplicationHistorySnapshot; import org.springframework.data.domain.Pageable; import org.springframework.data.mongodb.repository.Query; import org.springframework.data.mongodb.repository.ReactiveMongoRepository; @@ -11,7 +11,7 @@ import java.time.Instant; @Repository -public interface ApplicationHistorySnapshotRepository extends ReactiveMongoRepository { +public interface ApplicationHistorySnapshotRepository extends ReactiveMongoRepository { @Query(value = "{ 'applicationId': ?0, $and: [" + "{$or: [ { 'context.operations': { $elemMatch: { 'compName': ?1 } } }, { $expr: { $eq: [?1, null] } } ]}, " + @@ -20,7 +20,7 @@ public interface ApplicationHistorySnapshotRepository extends ReactiveMongoRepos "{$or: [ { 'createdAt': { $lte: ?4} }, { $expr: { $eq: [?4, null] } } ] } " + "]}", fields = "{applicationId : 1, context: 1, createdBy : 1, createdAt : 1}") - Flux findAllByApplicationId(String applicationId, String compName, String theme, Instant createdAtFrom, Instant createdAtTo, Pageable pageable); + Flux findAllByApplicationId(String applicationId, String compName, String theme, Instant createdAtFrom, Instant createdAtTo, Pageable pageable); Mono countByApplicationId(String applicationId); } diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationHistorySnapshotService.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationHistorySnapshotService.java index fd4a79f82..470bb63ff 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationHistorySnapshotService.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationHistorySnapshotService.java @@ -13,12 +13,12 @@ public interface ApplicationHistorySnapshotService { Mono createHistorySnapshot(String applicationId, Map dsl, Map context, String userId); - Mono> listAllHistorySnapshotBriefInfo(String applicationId, String compName, String theme, Instant from, Instant to, PageRequest pageRequest); - Mono> listAllHistorySnapshotBriefInfoArchived(String applicationId, String compName, String theme, Instant from, Instant to, PageRequest pageRequest); + Mono> listAllHistorySnapshotBriefInfo(String applicationId, String compName, String theme, Instant from, Instant to, PageRequest pageRequest); + Mono> listAllHistorySnapshotBriefInfoArchived(String applicationId, String compName, String theme, Instant from, Instant to, PageRequest pageRequest); Mono countByApplicationId(String applicationId); - Mono getHistorySnapshotDetail(String historySnapshotId); + Mono getHistorySnapshotDetail(String historySnapshotId); - Mono getHistorySnapshotDetailArchived(String historySnapshotId); + Mono getHistorySnapshotDetailArchived(String historySnapshotId); } diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/impl/ApplicationHistorySnapshotServiceImpl.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/impl/ApplicationHistorySnapshotServiceImpl.java index c47b39955..f797b9756 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/impl/ApplicationHistorySnapshotServiceImpl.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/impl/ApplicationHistorySnapshotServiceImpl.java @@ -29,24 +29,24 @@ public class ApplicationHistorySnapshotServiceImpl implements ApplicationHistory @Override public Mono createHistorySnapshot(String applicationId, Map dsl, Map context, String userId) { - ApplicationHistorySnapshotTS applicationHistorySnapshotTS = new ApplicationHistorySnapshotTS(); - applicationHistorySnapshotTS.setApplicationId(applicationId); - applicationHistorySnapshotTS.setDsl(dsl); - applicationHistorySnapshotTS.setContext(context); - return repository.save(applicationHistorySnapshotTS) + ApplicationHistorySnapshot applicationHistorySnapshot = new ApplicationHistorySnapshot(); + applicationHistorySnapshot.setApplicationId(applicationId); + applicationHistorySnapshot.setDsl(dsl); + applicationHistorySnapshot.setContext(context); + return repository.save(applicationHistorySnapshot) .thenReturn(true) .onErrorReturn(false); } @Override - public Mono> listAllHistorySnapshotBriefInfo(String applicationId, String compName, String theme, Instant from, Instant to, PageRequest pageRequest) { + public Mono> listAllHistorySnapshotBriefInfo(String applicationId, String compName, String theme, Instant from, Instant to, PageRequest pageRequest) { return repository.findAllByApplicationId(applicationId, compName, theme, from, to, pageRequest.withSort(Direction.DESC, "id")) .collectList() .onErrorMap(Exception.class, e -> ofException(BizError.FETCH_HISTORY_SNAPSHOT_FAILURE, "FETCH_HISTORY_SNAPSHOT_FAILURE")); } @Override - public Mono> listAllHistorySnapshotBriefInfoArchived(String applicationId, String compName, String theme, Instant from, Instant to, PageRequest pageRequest) { + public Mono> listAllHistorySnapshotBriefInfoArchived(String applicationId, String compName, String theme, Instant from, Instant to, PageRequest pageRequest) { return repositoryArchived.findAllByApplicationId(applicationId, compName, theme, from, to, pageRequest.withSort(Direction.DESC, "id")) .collectList() .onErrorMap(Exception.class, e -> ofException(BizError.FETCH_HISTORY_SNAPSHOT_FAILURE, "FETCH_HISTORY_SNAPSHOT_FAILURE")); @@ -61,14 +61,14 @@ public Mono countByApplicationId(String applicationId) { @Override - public Mono getHistorySnapshotDetail(String historySnapshotId) { + public Mono getHistorySnapshotDetail(String historySnapshotId) { return repository.findById(historySnapshotId) .switchIfEmpty(deferredError(INVALID_HISTORY_SNAPSHOT, "INVALID_HISTORY_SNAPSHOT", historySnapshotId)); } @Override - public Mono getHistorySnapshotDetailArchived(String historySnapshotId) { + public Mono getHistorySnapshotDetailArchived(String historySnapshotId) { return repositoryArchived.findById(historySnapshotId) .switchIfEmpty(deferredError(INVALID_HISTORY_SNAPSHOT, "INVALID_HISTORY_SNAPSHOT", historySnapshotId)); } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationHistorySnapshotController.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationHistorySnapshotController.java index 6b6d94a51..682f60ae0 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationHistorySnapshotController.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationHistorySnapshotController.java @@ -13,6 +13,7 @@ import org.lowcoder.domain.application.service.ApplicationService; import org.lowcoder.domain.permission.model.ResourceAction; import org.lowcoder.domain.permission.service.ResourcePermissionService; +import org.lowcoder.domain.user.model.User; import org.lowcoder.domain.user.service.UserService; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; @@ -69,15 +70,15 @@ public Mono>> listAllHistorySnapshotBriefInfo(@ .flatMap(__ -> applicationHistorySnapshotService.listAllHistorySnapshotBriefInfo(applicationId, compName, theme, from, to, pagination.toPageRequest())) .flatMap(snapshotList -> { Mono> snapshotBriefInfoList = multiBuild(snapshotList, - ApplicationHistorySnapshotTS::getCreatedBy, + ApplicationHistorySnapshot::getCreatedBy, userService::getByIds, - (applicationHistorySnapshotTS, user) -> new ApplicationHistorySnapshotBriefInfo( - applicationHistorySnapshotTS.getId(), - applicationHistorySnapshotTS.getContext(), - applicationHistorySnapshotTS.getCreatedBy(), + (applicationHistorySnapshot, user) -> new ApplicationHistorySnapshotBriefInfo( + applicationHistorySnapshot.getId(), + applicationHistorySnapshot.getContext(), + applicationHistorySnapshot.getCreatedBy(), user.getName(), user.getAvatarUrl(), - applicationHistorySnapshotTS.getCreatedAt().toEpochMilli() + applicationHistorySnapshot.getCreatedAt().toEpochMilli() ) ); @@ -106,15 +107,15 @@ public Mono>> listAllHistorySnapshotBriefInfoAr .flatMap(__ -> applicationHistorySnapshotService.listAllHistorySnapshotBriefInfoArchived(applicationId, compName, theme, from, to, pagination.toPageRequest())) .flatMap(snapshotList -> { Mono> snapshotBriefInfoList = multiBuild(snapshotList, - ApplicationHistorySnapshot::getCreatedBy, + ApplicationHistorySnapshotTS::getCreatedBy, userService::getByIds, - (applicationHistorySnapshot, user) -> new ApplicationHistorySnapshotBriefInfo( - applicationHistorySnapshot.getId(), - applicationHistorySnapshot.getContext(), - applicationHistorySnapshot.getCreatedBy(), + (applicationHistorySnapshotTS, user) -> new ApplicationHistorySnapshotBriefInfo( + applicationHistorySnapshotTS.getId(), + applicationHistorySnapshotTS.getContext(), + applicationHistorySnapshotTS.getCreatedBy(), user.getName(), user.getAvatarUrl(), - applicationHistorySnapshot.getCreatedAt().toEpochMilli() + applicationHistorySnapshotTS.getCreatedAt().toEpochMilli() ) ); @@ -133,7 +134,7 @@ public Mono> getHistorySnapshotDsl(@PathVar .delayUntil(visitor -> resourcePermissionService.checkResourcePermissionWithError(visitor, applicationId, ResourceAction.EDIT_APPLICATIONS)) .flatMap(__ -> applicationHistorySnapshotService.getHistorySnapshotDetail(snapshotId)) - .map(ApplicationHistorySnapshotTS::getDsl) + .map(ApplicationHistorySnapshot::getDsl) .zipWhen(applicationService::getAllDependentModulesFromDsl) .map(tuple -> { Map applicationDsl = tuple.getT1(); @@ -155,7 +156,7 @@ public Mono> getHistorySnapshotDslArchived( .delayUntil(visitor -> resourcePermissionService.checkResourcePermissionWithError(visitor, applicationId, ResourceAction.EDIT_APPLICATIONS)) .flatMap(__ -> applicationHistorySnapshotService.getHistorySnapshotDetailArchived(snapshotId)) - .map(ApplicationHistorySnapshot::getDsl) + .map(ApplicationHistorySnapshotTS::getDsl) .zipWhen(applicationService::getAllDependentModulesFromDsl) .map(tuple -> { Map applicationDsl = tuple.getT1(); From a28b90f24b14edaae74c0caf38ef96e6ff182a6b Mon Sep 17 00:00:00 2001 From: Thomasr Date: Fri, 22 Nov 2024 03:50:46 -0500 Subject: [PATCH 08/28] application snapshot history count logic fix --- .../service/ApplicationHistorySnapshotService.java | 1 + .../impl/ApplicationHistorySnapshotServiceImpl.java | 7 +++++++ .../application/ApplicationHistorySnapshotController.java | 6 +++--- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationHistorySnapshotService.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationHistorySnapshotService.java index 470bb63ff..f4e5b3fcf 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationHistorySnapshotService.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationHistorySnapshotService.java @@ -17,6 +17,7 @@ public interface ApplicationHistorySnapshotService { Mono> listAllHistorySnapshotBriefInfoArchived(String applicationId, String compName, String theme, Instant from, Instant to, PageRequest pageRequest); Mono countByApplicationId(String applicationId); + Mono countByApplicationIdArchived(String applicationId); Mono getHistorySnapshotDetail(String historySnapshotId); diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/impl/ApplicationHistorySnapshotServiceImpl.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/impl/ApplicationHistorySnapshotServiceImpl.java index f797b9756..2d4aba44a 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/impl/ApplicationHistorySnapshotServiceImpl.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/impl/ApplicationHistorySnapshotServiceImpl.java @@ -59,6 +59,13 @@ public Mono countByApplicationId(String applicationId) { e -> ofException(BizError.FETCH_HISTORY_SNAPSHOT_COUNT_FAILURE, "FETCH_HISTORY_SNAPSHOT_COUNT_FAILURE")); } + @Override + public Mono countByApplicationIdArchived(String applicationId) { + return repositoryArchived.countByApplicationId(applicationId) + .onErrorMap(Exception.class, + e -> ofException(BizError.FETCH_HISTORY_SNAPSHOT_COUNT_FAILURE, "FETCH_HISTORY_SNAPSHOT_COUNT_FAILURE")); + } + @Override public Mono getHistorySnapshotDetail(String historySnapshotId) { diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationHistorySnapshotController.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationHistorySnapshotController.java index 682f60ae0..b5a6381d7 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationHistorySnapshotController.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationHistorySnapshotController.java @@ -55,7 +55,7 @@ public Mono> create(@RequestBody ApplicationHistorySnapsho @Override public Mono>> listAllHistorySnapshotBriefInfo(@PathVariable String applicationId, - @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "10") int size, @RequestParam String compName, @RequestParam String theme, @@ -92,7 +92,7 @@ public Mono>> listAllHistorySnapshotBriefInfo(@ @Override public Mono>> listAllHistorySnapshotBriefInfoArchived(@PathVariable String applicationId, - @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "10") int size, @RequestParam String compName, @RequestParam String theme, @@ -119,7 +119,7 @@ public Mono>> listAllHistorySnapshotBriefInfoAr ) ); - Mono applicationHistorySnapshotCount = applicationHistorySnapshotService.countByApplicationId(applicationId); + Mono applicationHistorySnapshotCount = applicationHistorySnapshotService.countByApplicationIdArchived(applicationId); return Mono.zip(snapshotBriefInfoList, applicationHistorySnapshotCount) .map(tuple -> ImmutableMap.of("list", tuple.getT1(), "count", tuple.getT2())); From 311bae778d2a730a5c7584f0831976c044918b9d Mon Sep 17 00:00:00 2001 From: Thomasr Date: Fri, 22 Nov 2024 03:55:27 -0500 Subject: [PATCH 09/28] page number start from 1 --- .../org/lowcoder/api/application/ApplicationController.java | 4 ++-- .../org/lowcoder/api/application/ApplicationEndpoints.java | 2 +- .../main/java/org/lowcoder/api/bundle/BundleController.java | 2 +- .../main/java/org/lowcoder/api/bundle/BundleEndpoints.java | 2 +- .../src/main/java/org/lowcoder/api/home/FolderController.java | 4 ++-- .../src/main/java/org/lowcoder/api/home/FolderEndpoints.java | 2 +- .../java/org/lowcoder/api/usermanagement/GroupController.java | 4 ++-- .../java/org/lowcoder/api/usermanagement/GroupEndpoints.java | 2 +- .../lowcoder/api/usermanagement/OrganizationController.java | 2 +- .../lowcoder/api/usermanagement/OrganizationEndpoints.java | 2 +- .../src/main/java/org/lowcoder/api/util/Pagination.java | 2 +- 11 files changed, 14 insertions(+), 14 deletions(-) diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationController.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationController.java index ed7079598..3c91f7ce7 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationController.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationController.java @@ -162,12 +162,12 @@ public Mono>> getApplications(@RequestPar @RequestParam(required = false) ApplicationStatus applicationStatus, @RequestParam(defaultValue = "true") boolean withContainerSize, @RequestParam(required = false) String name, - @RequestParam(required = false, defaultValue = "0") Integer pageNum, + @RequestParam(required = false, defaultValue = "1") Integer pageNum, @RequestParam(required = false, defaultValue = "0") Integer pageSize) { ApplicationType applicationTypeEnum = applicationType == null ? null : ApplicationType.fromValue(applicationType); var flux = userHomeApiService.getAllAuthorisedApplications4CurrentOrgMember(applicationTypeEnum, applicationStatus, withContainerSize, name).cache(); Mono countMono = flux.count(); - var flux1 = flux.skip((long) pageNum * pageSize); + var flux1 = flux.skip((long) (pageNum - 1) * pageSize); if(pageSize > 0) flux1 = flux1.take(pageSize); return flux1.collectList().zipWith(countMono) .map(tuple -> PageResponseView.success(tuple.getT1(), pageNum, pageSize, Math.toIntExact(tuple.getT2()))); diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationEndpoints.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationEndpoints.java index 4eed69ee2..cef119847 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationEndpoints.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationEndpoints.java @@ -167,7 +167,7 @@ public Mono>> getApplications(@RequestPar @RequestParam(required = false) ApplicationStatus applicationStatus, @RequestParam(defaultValue = "true") boolean withContainerSize, @RequestParam(required = false) String name, - @RequestParam(required = false, defaultValue = "0") Integer pageNum, + @RequestParam(required = false, defaultValue = "1") Integer pageNum, @RequestParam(required = false, defaultValue = "0") Integer pageSize); @Operation( diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/bundle/BundleController.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/bundle/BundleController.java index 254e78037..cb0df9241 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/bundle/BundleController.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/bundle/BundleController.java @@ -106,7 +106,7 @@ public Mono>> getRecycledBundles() { @Override public Mono> getElements(@PathVariable String bundleId, @RequestParam(value = "applicationType", required = false) ApplicationType applicationType, - @RequestParam(required = false, defaultValue = "0") Integer pageNum, + @RequestParam(required = false, defaultValue = "1") Integer pageNum, @RequestParam(required = false, defaultValue = "0") Integer pageSize) { String objectId = gidService.convertBundleIdToObjectId(bundleId); var flux = bundleApiService.getElements(objectId, applicationType).cache(); diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/bundle/BundleEndpoints.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/bundle/BundleEndpoints.java index 8674c62b5..8d668c1b7 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/bundle/BundleEndpoints.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/bundle/BundleEndpoints.java @@ -123,7 +123,7 @@ public interface BundleEndpoints @GetMapping("/{bundleId}/elements") public Mono> getElements(@PathVariable String bundleId, @RequestParam(value = "applicationType", required = false) ApplicationType applicationType, - @RequestParam(required = false, defaultValue = "0") Integer pageNum, + @RequestParam(required = false, defaultValue = "1") Integer pageNum, @RequestParam(required = false, defaultValue = "0") Integer pageSize); @Operation( diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/home/FolderController.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/home/FolderController.java index 31cf49494..24a77dd29 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/home/FolderController.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/home/FolderController.java @@ -70,12 +70,12 @@ public Mono> update(@RequestBody Folder folder) { public Mono> getElements(@RequestParam(value = "id", required = false) String folderId, @RequestParam(value = "applicationType", required = false) ApplicationType applicationType, @RequestParam(required = false) String name, - @RequestParam(required = false, defaultValue = "0") Integer pageNum, + @RequestParam(required = false, defaultValue = "1") Integer pageNum, @RequestParam(required = false, defaultValue = "0") Integer pageSize) { String objectId = gidService.convertFolderIdToObjectId(folderId); var flux = folderApiService.getElements(objectId, applicationType, name).cache(); var countMono = flux.count(); - var flux1 = flux.skip((long) pageNum * pageSize); + var flux1 = flux.skip((long) (pageNum - 1) * pageSize); if(pageSize > 0) flux1 = flux1.take(pageSize); return flux1.collectList() .delayUntil(__ -> folderApiService.upsertLastViewTime(objectId)) diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/home/FolderEndpoints.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/home/FolderEndpoints.java index 43e5ce785..2c6279084 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/home/FolderEndpoints.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/home/FolderEndpoints.java @@ -71,7 +71,7 @@ public interface FolderEndpoints public Mono> getElements(@RequestParam(value = "id", required = false) String folderId, @RequestParam(value = "applicationType", required = false) ApplicationType applicationType, @RequestParam(required = false) String name, - @RequestParam(required = false, defaultValue = "0") Integer pageNum, + @RequestParam(required = false, defaultValue = "1") Integer pageNum, @RequestParam(required = false, defaultValue = "0") Integer pageSize); @Operation( diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupController.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupController.java index d478bcfc2..4e7facb99 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupController.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupController.java @@ -75,7 +75,7 @@ public Mono> delete(@PathVariable String groupId) { } @Override - public Mono>> getOrgGroups(@RequestParam(required = false, defaultValue = "0") Integer pageNum, + public Mono>> getOrgGroups(@RequestParam(required = false, defaultValue = "1") Integer pageNum, @RequestParam(required = false, defaultValue = "0") Integer pageSize) { return groupApiService.getGroups().flatMap(groupList -> { if(groupList.isEmpty()) return Mono.just(new GroupListResponseView<>(ResponseView.SUCCESS, @@ -99,7 +99,7 @@ public Mono>> getOrgGroups(@RequestParam(r .filter(orgMember -> !orgMember.isAdmin() && !orgMember.isSuperAdmin() && devMembers.stream().noneMatch(devMember -> devMember.getUserId().equals(orgMember.getUserId()))).toList().size(); - var subList = groupList.subList(pageNum * pageSize, pageSize <= 0?groupList.size():pageNum * pageSize + pageSize); + var subList = groupList.subList((pageNum - 1) * pageSize, pageSize <= 0?groupList.size():pageNum * pageSize); return new GroupListResponseView<>(ResponseView.SUCCESS, "", subList, diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupEndpoints.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupEndpoints.java index 4f0825333..e2f8bfa7a 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupEndpoints.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupEndpoints.java @@ -63,7 +63,7 @@ public Mono> update(@PathVariable String groupId, description = "Retrieve a list of User Groups within Lowcoder, providing an overview of available groups, based on the access rights of the currently impersonated User." ) @GetMapping("/list") - public Mono>> getOrgGroups(@RequestParam(required = false, defaultValue = "0") Integer pageNum, + public Mono>> getOrgGroups(@RequestParam(required = false, defaultValue = "1") Integer pageNum, @RequestParam(required = false, defaultValue = "0") Integer pageSize); @Operation( diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrganizationController.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrganizationController.java index b0acc8cf1..2b2a9dd75 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrganizationController.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrganizationController.java @@ -50,7 +50,7 @@ public class OrganizationController implements OrganizationEndpoints @Override public Mono> getOrganizationByUser(@PathVariable String email, - @RequestParam(required = false, defaultValue = "0") Integer pageNum, + @RequestParam(required = false, defaultValue = "1") Integer pageNum, @RequestParam(required = false, defaultValue = "0") Integer pageSize) { var flux = userService.findByEmailDeep(email).flux().flatMap(user -> orgMemberService.getAllActiveOrgs(user.getId())) .flatMap(orgMember -> organizationService.getById(orgMember.getOrgId())) diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrganizationEndpoints.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrganizationEndpoints.java index 734012033..38332e892 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrganizationEndpoints.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrganizationEndpoints.java @@ -46,7 +46,7 @@ public interface OrganizationEndpoints ) @GetMapping("/byuser/{email}") public Mono> getOrganizationByUser(@PathVariable String email, - @RequestParam(required = false, defaultValue = "0") Integer pageNum, + @RequestParam(required = false, defaultValue = "1") Integer pageNum, @RequestParam(required = false, defaultValue = "0") Integer pageSize); @Operation( diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/util/Pagination.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/util/Pagination.java index 051c3e006..03141d6bb 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/util/Pagination.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/util/Pagination.java @@ -64,7 +64,7 @@ public int size() { @NotNull public static Mono> fluxToPageResponseView(Integer pageNum, Integer pageSize, Flux flux) { var countMono = flux.count(); - var flux1 = flux.skip((long) pageNum * pageSize); + var flux1 = flux.skip((long) (pageNum - 1) * pageSize); if(pageSize > 0) flux1 = flux1.take(pageSize); return flux1.collectList().zipWith(countMono) .map(tuple -> PageResponseView.success(tuple.getT1(), pageNum, pageSize, Math.toIntExact(tuple.getT2()))); From 570e35cdf95d844c96068c31d63596592a2e76bd Mon Sep 17 00:00:00 2001 From: Thomasr Date: Fri, 22 Nov 2024 12:04:20 -0500 Subject: [PATCH 10/28] #1284 Fixed duplicate key error for currentUser endpoint when logging to duplicate keycloak --- .../java/org/lowcoder/domain/user/service/UserServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/service/UserServiceImpl.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/service/UserServiceImpl.java index 6b800720c..981000caf 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/service/UserServiceImpl.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/service/UserServiceImpl.java @@ -418,7 +418,7 @@ protected Map convertConnections(Set connections) { return connections.stream() .filter(connection -> !AuthSourceConstants.EMAIL.equals(connection.getSource()) && !AuthSourceConstants.PHONE.equals(connection.getSource())) - .collect(Collectors.toMap(Connection::getSource, Connection::getRawUserInfo)); + .collect(Collectors.toMap(Connection::getAuthId, Connection::getRawUserInfo)); } protected String convertEmail(Set connections) { From d6d7a88789682a824788f44bf44303a6ab32ccf2 Mon Sep 17 00:00:00 2001 From: Thomasr Date: Fri, 22 Nov 2024 13:57:27 -0500 Subject: [PATCH 11/28] fix test compile issue --- .../impl/ApplicationHistorySnapshotServiceTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/api-service/lowcoder-server/src/test/java/org/lowcoder/api/service/impl/ApplicationHistorySnapshotServiceTest.java b/server/api-service/lowcoder-server/src/test/java/org/lowcoder/api/service/impl/ApplicationHistorySnapshotServiceTest.java index fb7109134..81c0cb56d 100644 --- a/server/api-service/lowcoder-server/src/test/java/org/lowcoder/api/service/impl/ApplicationHistorySnapshotServiceTest.java +++ b/server/api-service/lowcoder-server/src/test/java/org/lowcoder/api/service/impl/ApplicationHistorySnapshotServiceTest.java @@ -4,7 +4,7 @@ import lombok.extern.slf4j.Slf4j; import org.junit.Test; import org.junit.runner.RunWith; -import org.lowcoder.domain.application.model.ApplicationHistorySnapshotTS; +import org.lowcoder.domain.application.model.ApplicationHistorySnapshot; import org.lowcoder.domain.application.service.ApplicationHistorySnapshotService; import org.lowcoder.sdk.models.HasIdAndAuditing; import org.springframework.beans.factory.annotation.Autowired; @@ -47,8 +47,8 @@ public void testServiceMethods() { .assertNext(list -> { assertEquals(2, list.size()); - ApplicationHistorySnapshotTS first = list.get(0); - ApplicationHistorySnapshotTS second = list.get(1); + ApplicationHistorySnapshot first = list.get(0); + ApplicationHistorySnapshot second = list.get(1); assertTrue(first.getCreatedAt().isAfter(second.getCreatedAt())); assertNull(first.getDsl()); @@ -66,7 +66,7 @@ public void testServiceMethods() { StepVerifier.create(service.listAllHistorySnapshotBriefInfo(applicationId, null, null, null, null, PageRequest.of(1, 1))) .assertNext(list -> { assertEquals(1, list.size()); - ApplicationHistorySnapshotTS one = list.get(0); + ApplicationHistorySnapshot one = list.get(0); assertNull(one.getDsl()); assertEquals(ImmutableMap.of("context", "context1"), one.getContext()); assertEquals(applicationId, one.getApplicationId()); From a740d0f973fde05308c566f3a2f56e844dec2a3b Mon Sep 17 00:00:00 2001 From: Imiss-U1025 Date: Tue, 19 Nov 2024 04:47:53 -0500 Subject: [PATCH 12/28] Added tree structure basically. --- .../src/pages/editor/right/ModulePanel.tsx | 620 +++++++++++++++--- 1 file changed, 518 insertions(+), 102 deletions(-) diff --git a/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx b/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx index dc4ad3cc9..7655ad57b 100644 --- a/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx +++ b/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx @@ -1,80 +1,163 @@ -import CreateAppButton from "components/CreateAppButton"; -import { EmptyContent } from "components/EmptyContent"; -import { ApplicationMeta, AppTypeEnum } from "constants/applicationConstants"; -import { APPLICATION_VIEW_URL } from "constants/routesURL"; +import { ApplicationMeta, AppTypeEnum, FolderMeta } from "constants/applicationConstants"; import { - ActiveTextColor, - BorderActiveShadowColor, - BorderColor, - GreyTextColor, + BorderActiveColor, + NormalMenuIconColor, } from "constants/style"; -import { ModuleDocIcon } from "lowcoder-design"; +import { APPLICATION_VIEW_URL } from "constants/routesURL"; +import { RightContext } from "./rightContext"; +import { + EditPopover, + EditText, + FoldedIcon, + ModuleDocIcon, + PointIcon, + PopupCard, + UnfoldIcon, + FileFolderIcon +} from "lowcoder-design"; import { trans } from "i18n"; import { draggingUtils } from "layout/draggingUtils"; -import { useContext, useEffect } from "react"; +import {CSSProperties, useContext, useEffect, useState} from "react"; import { useDispatch, useSelector } from "react-redux"; import { fetchAllModules } from "redux/reduxActions/applicationActions"; import styled from "styled-components"; +import CreateAppButton from "components/CreateAppButton"; import { TransparentImg } from "util/commonUtils"; -import { ExternalEditorContext } from "util/context/ExternalEditorContext"; -import { formatTimestamp } from "util/dateTimeUtils"; -import { RightContext } from "./rightContext"; -import { modulesSelector } from "../../../redux/selectors/applicationSelector"; -import { ComListTitle, ExtensionContentWrapper } from "./styledComponent"; - +import { ComListTitle } from "./styledComponent"; +import {folderElementsSelector} from "@lowcoder-ee/redux/selectors/folderSelector"; +import {DraggableTree} from "@lowcoder-ee/components/DraggableTree/DraggableTree"; +import {EditorContext} from "lowcoder-sdk"; +import {showAppSnapshotSelector} from "@lowcoder-ee/redux/selectors/appSnapshotSelector"; +import {DraggableTreeNode, DraggableTreeNodeItemRenderProps} from "@lowcoder-ee/components/DraggableTree/types"; +import RefTreeComp from "@lowcoder-ee/comps/comps/refTreeComp"; +import { EmptyContent } from "components/EmptyContent"; const ItemWrapper = styled.div` + display: flex; + flex-direction: row; + &:last-child { + margin-bottom: 0; + } + .module-icon { + display: flex; - flex-direction: row; - margin-bottom: 12px; - &:last-child { - margin-bottom: 0; + justify-content: center; + align-items: center; + margin: 4px; + } + .module-content { + flex: 1; + display: flex; + flex-direction: column; + justify-content: space-around; + overflow: hidden; + } + .module-name { + line-height: 1.5; + font-size: 13px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } +`; + +type NodeType = { + name: string; + id: string; + isFolder: boolean; + containerSize?: { height: number; width: number }; + module?: ApplicationMeta; + children: NodeType[]; + rename: (val: string) => string + checkName: (val: string) => string +}; + + + +function buildTree(elementRecord: Record>): NodeType { + const elements = elementRecord[""]; + const elementMap: Record = {}; + let rootNode: NodeType = { + name: "", + id: "", + isFolder: true, + children: [], + rename: val => rootNode.name = val, + checkName: val => val } - &:hover { - cursor: grab; - .module-icon { - box-shadow: 0 0 5px 0 rgba(49, 94, 251, 0.15); - border-color: ${BorderActiveShadowColor}; - transform: scale(1.2); - } - .module-name { - color: ${ActiveTextColor}; + + // Initialize all folders and applications as NodeType + for (const element of elements) { + if (element.folder) { + elementMap[element.folderId] = { + name: element.name, + id: element.folderId, + isFolder: true, + children: [], + rename: val => elementMap[element.folderId].name = val, + checkName: val => val + }; + + // Process subapplications inside the folder + for (const app of element.subApplications || []) { + if (app.applicationType === AppTypeEnum.Module) { + const appNode: NodeType = { + name: app.name, + id: app.applicationId, + containerSize: app.containerSize, + isFolder: false, + children: [], + module: app, + rename: val => appNode.name = val, + checkName: val => val + }; + elementMap[element.folderId].children.push(appNode); // Add applications as children of the folder + } + } + } else { + if (element.applicationType === AppTypeEnum.Module) { + elementMap[element.applicationId] = { + name: element.name, + containerSize: element.containerSize, + id: element.applicationId, + isFolder: false, + children: [], + module: element, + rename: val => elementMap[element.applicationId].name = val, + checkName: val => val + }; + } } } - .module-icon { - transition: all 200ms linear; - margin-right: 8px; - width: 40px; - height: 40px; - display: flex; - justify-content: center; - align-items: center; - border: 1px solid ${BorderColor}; - border-radius: 4px; - } - .module-content { - flex: 1; - display: flex; - flex-direction: column; - justify-content: space-around; - overflow: hidden; - } - .module-name { - line-height: 1.5; - font-size: 13px; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - } - .module-desc { - line-height: 1.5; - font-size: 12px; - color: ${GreyTextColor}; + + // Build the tree structure + for (const element of elements) { + if (element.folder) { + const parentId = element.parentFolderId; + if (parentId && elementMap[parentId]) { + elementMap[parentId].children.push(elementMap[element.folderId]); + } else { + rootNode.children.push(elementMap[element.folderId]); + } + } else if (elementMap[element.applicationId]) { + rootNode.children.push(elementMap[element.applicationId]); + } } -`; + console.log(rootNode.children.sort((a, b) => { + if (a.isFolder && !b.isFolder) { + return -1; // a is a isFolder and should come first + } else if (!a.isFolder && b.isFolder) { + return 1; // b is a folder and should come first + } else { + return 0; // both are folders or both are not, keep original order + } + })); + return rootNode; +} + interface ModuleItemProps { - meta: ApplicationMeta; - onDrag: (type: string) => void; + meta: ApplicationMeta; + onDrag: (type: string) => void; } function ModuleItem(props: ModuleItemProps) { @@ -84,6 +167,7 @@ function ModuleItem(props: ModuleItemProps) { { + console.log(meta); e.dataTransfer.setData("compType", compType); e.dataTransfer.setDragImage(TransparentImg, 0, 0); draggingUtils.setData("compType", compType); @@ -100,57 +184,389 @@ function ModuleItem(props: ModuleItemProps) { }} >
- +
{props.meta.name}
-
{formatTimestamp(props.meta.createAt)}
); } -export default function ModulePanel() { - const dispatch = useDispatch(); - const modules = useSelector(modulesSelector); - const { onDrag, searchValue } = useContext(RightContext); - const { applicationId } = useContext(ExternalEditorContext); - - useEffect(() => { - dispatch(fetchAllModules({})); - }, [dispatch]); - - const filteredModules = modules.filter((i) => { - if (i.applicationId === applicationId || i.applicationType !== AppTypeEnum.Module) { - return false; +const HighlightBorder = styled.div<{ $active: boolean; $foldable: boolean; $level: number }>` + max-width: 100%; + flex: 1; + display: flex; + padding-left: ${(props) => props.$level * 20 + (props.$foldable ? 0 : 14)}px; + border-radius: 4px; + border: 1px solid ${(props) => (props.$active ? BorderActiveColor : "transparent")}; + align-items: center; + justify-content: center; +`; + +interface ColumnDivProps { + $color?: boolean; + $isOverlay: boolean; +} + +const ColumnDiv = styled.div` + width: 100%; + height: 25px; + display: flex; + user-select: none; + padding-left: 2px; + padding-right: 15px; + /* background-color: #ffffff; */ + /* margin: 2px 0; */ + background-color: ${(props) => (props.$isOverlay ? "rgba(255, 255, 255, 0.11)" : "")}; + + &&& { + background-color: ${(props) => (props.$color && !props.$isOverlay ? "#f2f7fc" : null)}; + } + + &:hover { + background-color: #f2f7fc80; + cursor: pointer; + } + + .taco-edit-text-wrapper { + width: 100%; + height: 21px; + line-height: 21px; + color: #222222; + margin-left: 0; + font-size: 13px; + padding-left: 0; + + &:hover { + background-color: transparent; + } + } + + .taco-edit-text-input { + width: 100%; + height: 21px; + line-height: 21px; + color: #222222; + margin-left: 0; + font-size: 13px; + background-color: #fdfdfd; + border: 1px solid #3377ff; + border-radius: 2px; + + &:focus { + border-color: #3377ff; + box-shadow: 0 0 0 2px #d6e4ff; + } + } +`; + +const FoldIconBtn = styled.div` + width: 12px; + height: 12px; + display: flex; + margin-right: 2px; +`; + +const Icon = styled(PointIcon)` + width: 16px; + height: 16px; + cursor: pointer; + flex-shrink: 0; + color: ${NormalMenuIconColor}; + + &:hover { + color: #315efb; + } +`; + +interface ModuleSidebarItemProps extends DraggableTreeNodeItemRenderProps { + id: string; + resComp: NodeType; + onCopy: () => void; + onSelect: () => void; + onDelete: () => void; + onToggleFold: () => void; +} + +const empty = ( + +

{trans("rightPanel.emptyModules")}

+ { + const appId = app.applicationInfoView.applicationId; + const url = APPLICATION_VIEW_URL(appId, "edit"); + window.open(url); + }} + /> + } - return i.name?.toLowerCase()?.includes(searchValue.trim()?.toLowerCase()) || !searchValue?.trim(); - }); - - const items = filteredModules.map((i) => ( - - )); - const empty = ( - -

{trans("rightPanel.emptyModules")}

- { - const appId = app.applicationInfoView.applicationId; - const url = APPLICATION_VIEW_URL(appId, "edit"); - window.open(url); - }} - /> - + /> +); + +function ModuleSidebarItem(props: ModuleSidebarItemProps) { + const { + id, + resComp, + isOver, + isOverlay, + path, + isFolded, + onDelete, + onCopy, + onSelect, + onToggleFold, + } = props; + const { onDrag } = useContext(RightContext); + const [error, setError] = useState(undefined); + const [editing, setEditing] = useState(false); + const editorState = useContext(EditorContext); + const readOnly = useSelector(showAppSnapshotSelector); + const [selectedModuleResName, setSelectedModuleResName] = useState(""); + const [selectedModuleResType, setSelectedModuleResType] = useState(false); + const level = path.length - 1; + const type = resComp.isFolder; + const name = resComp.name; + const icon = resComp.isFolder? : ; + const isSelected = type === selectedModuleResType && id === selectedModuleResName; + const isFolder = type; + + const handleFinishRename = (value: string) => { + let success = false; + let compId = name; + if (resComp.rename) { + compId = resComp.rename(value); + success = !!compId; + } else { + compId = name; + success = true; + } + if (success) { + setSelectedModuleResName(compId); + setSelectedModuleResType(type); + setError(undefined); + } + }; + + const handleNameChange = (value: string) => { + let err = ""; + if (resComp.checkName) { + err = resComp.checkName(value); + } else { + err = editorState.checkRename(name, value); + } + setError(err); + }; + + const handleClickItem = () => { + if (isFolder) { + onToggleFold(); + } + onSelect(); + }; + + return ( + + + {isFolder && {!isFolded ? : }} + {isFolder ? + <> + +
+ setEditing(editing)} + /> + +
: } - /> + {!readOnly && !isOverlay && ( + + + + )} +
+
); +} + +export default function ModulePanel() { + const dispatch = useDispatch(); + const elements = useSelector(folderElementsSelector); + const { onDrag, searchValue } = useContext(RightContext); + + useEffect(() => { + dispatch(fetchAllModules({})); + }, [dispatch]); + + + //Convert elements into tree + const tree = buildTree(elements); + const getByIdFromNode = (root: NodeType | null, id: string): NodeType | undefined => { + if (!root) { + return; + } + + if (root.id === id) { + return root; + } + + for (const child of root.children) { + const result = getByIdFromNode(child, id); + if (result) { + return result; + } + } + return; + } + + const getById = (id: string): NodeType | undefined => getByIdFromNode(tree, id); + const convertRefTree = (treeNode: NodeType) => { + const moduleResComp = getById(treeNode.id); + const currentNodeType = moduleResComp?.isFolder; + const childrenItems = treeNode.children + .map((i) => convertRefTree(i as NodeType)) + .filter((i): i is DraggableTreeNode => !!i); + const node: DraggableTreeNode = { + id: moduleResComp?.id, + canDropBefore: (source) => { + if (currentNodeType) { + return source?.isFolder!; + } + + return !source?.isFolder; + }, + canDropAfter: (source) => { + if ( + !currentNodeType && + source?.isFolder + ) { + return false; + } + return true; + }, + canDropIn: (source) => { + if (!currentNodeType) { + return false; + } + if (!source) { + return true; + } + if (source.isFolder) { + return false; + } + return true; + }, + items: childrenItems, + data: moduleResComp, + addSubItem(value) { + console.log("addSubItem", node.id, value, node); + // const pushAction = node.items.pushAction({ value: value.id() }); + // node.items.dispatch(pushAction); + }, + deleteItem(index) { + console.log("deleteItem", node.id, index); + // const deleteAction = node.children.items.deleteAction(index); + // node.children.items.dispatch(deleteAction); + }, + addItem(value) { + console.log("addItem", node.id, value); + // const pushAction = node.children.items.pushAction({ value: value.id() }); + // node.children.items.dispatch(pushAction); + }, + moveItem(from, to) { + console.log("node", node); + // const moveAction = node.children.items.arrayMoveAction(from, to); + // node.children.items.dispatch(moveAction); + }, + }; + + if ( + searchValue && + moduleResComp && + !moduleResComp.name.toLowerCase().includes(searchValue.toLowerCase()) && + childrenItems.length === 0 + ) { + return; + } + return node; + }; + + const node = convertRefTree(tree); + + function onCopy(type: boolean, id: string) { + console.log("onCopy", type, id); + } + + function onSelect(type: boolean, id: string, meta: any) { + console.log("onSelect", type, id, meta) + return + } + + function onDelete(type: boolean, id: string) { + console.log("onDelete", type, id); + return true; + } + return ( - <> - {trans("rightPanel.moduleListTitle")} - {items.length > 0 ? items : empty} - - ); + <> + {trans("rightPanel.moduleListTitle")} + {node ? + node={node!} + disable={!!searchValue} + unfoldAll={!!searchValue} + showSubInDragOverlay={false} + showDropInPositionLine={false} + showPositionLineDot + positionLineDotDiameter={4} + positionLineHeight={1} + itemHeight={25} + positionLineIndent={(path, dropInAsSub) => { + const indent = 2 + (path.length - 1) * 30; + if (dropInAsSub) { + return indent + 12; + } + return indent; + }} + renderItemContent={(params) => { + const { node, onToggleFold, onDelete: onDeleteTreeItem, ...otherParams } = params; + const resComp = node.data; + if (!resComp) { + return null; + } + const id = resComp.id; + const isFolder = resComp.isFolder; + return ( + onCopy(isFolder, id)} + onSelect={() => onSelect(isFolder, id, resComp)} + onDelete={() => { + if (onDelete(isFolder, id)) { + onDeleteTreeItem(); + } + }} + {...otherParams} + /> + ); + }} + /> : empty} + + ); } From 69c741568e53d25824ed47abf6e726aacf35103f Mon Sep 17 00:00:00 2001 From: Imiss-U1025 Date: Thu, 21 Nov 2024 05:13:45 -0500 Subject: [PATCH 13/28] Added Movefolder in redux. --- .../src/constants/reduxActionConstants.ts | 2 +- .../reducers/uiReducers/folderReducer.ts | 40 ++++++++++++++++++- .../src/redux/reduxActions/folderActions.ts | 1 + .../lowcoder/src/redux/sagas/folderSagas.ts | 6 ++- 4 files changed, 45 insertions(+), 4 deletions(-) diff --git a/client/packages/lowcoder/src/constants/reduxActionConstants.ts b/client/packages/lowcoder/src/constants/reduxActionConstants.ts index be3cd6271..6df5991f2 100644 --- a/client/packages/lowcoder/src/constants/reduxActionConstants.ts +++ b/client/packages/lowcoder/src/constants/reduxActionConstants.ts @@ -9,7 +9,7 @@ export const ReduxActionTypes = { FETCH_RAW_CURRENT_USER_SUCCESS: "FETCH_RAW_CURRENT_USER_SUCCESS", FETCH_API_KEYS: "FETCH_API_KEYS", FETCH_API_KEYS_SUCCESS: "FETCH_API_KEYS_SUCCESS", - + MOVE_TO_FOLDER2_SUCCESS: "MOVE_TO_FOLDER2_SUCCESS", /* plugin RELATED */ FETCH_DATA_SOURCE_TYPES: "FETCH_DATA_SOURCE_TYPES", diff --git a/client/packages/lowcoder/src/redux/reducers/uiReducers/folderReducer.ts b/client/packages/lowcoder/src/redux/reducers/uiReducers/folderReducer.ts index c27cb8d50..21cc2bfa1 100644 --- a/client/packages/lowcoder/src/redux/reducers/uiReducers/folderReducer.ts +++ b/client/packages/lowcoder/src/redux/reducers/uiReducers/folderReducer.ts @@ -107,7 +107,7 @@ export const folderReducer = createReducer(initialState, { state: FolderReduxState, action: ReduxAction ): FolderReduxState => { - const elements = { ...state.folderElements }; + let elements = { ...state.folderElements }; elements[action.payload.sourceFolderId ?? ""] = elements[ action.payload.sourceFolderId ?? "" ]?.filter( @@ -120,6 +120,44 @@ export const folderReducer = createReducer(initialState, { folderElements: elements, }; }, + [ReduxActionTypes.MOVE_TO_FOLDER2_SUCCESS]: ( + state: FolderReduxState, + action: ReduxAction + ): FolderReduxState => { + let elements = { ...state.folderElements }; + let tempIndex: number | undefined; + let tempNode: any; + let temp = elements[""].map((item, index) => { + if (item.folderId === action.payload.sourceFolderId && item.folder) { + + const tempSubApplications = item.subApplications?.filter(e => + (e.folder && e.folderId !== action.payload.sourceId) || + (!e.folder && e.applicationId !== action.payload.sourceId) + ); + tempNode = item.subApplications?.filter(e => + (e.folder && e.folderId === action.payload.sourceId) || + (!e.folder && e.applicationId === action.payload.sourceId) + ); + return { ...item, subApplications: tempSubApplications }; + } + if (item.folderId === action.payload.folderId && item.folder) { + tempIndex = index; + return item; + } + return item; + }); + if (tempIndex !== undefined) { + const targetItem = temp[tempIndex]; + if (targetItem.folder && Array.isArray(targetItem.subApplications)) { + targetItem.subApplications.push(tempNode[0]); + } + } + elements[""] = temp; + return { + ...state, + folderElements: elements, + }; + }, [ReduxActionTypes.DELETE_FOLDER_SUCCESS]: ( state: FolderReduxState, action: ReduxAction diff --git a/client/packages/lowcoder/src/redux/reduxActions/folderActions.ts b/client/packages/lowcoder/src/redux/reduxActions/folderActions.ts index ba288b89a..5c00aafe6 100644 --- a/client/packages/lowcoder/src/redux/reduxActions/folderActions.ts +++ b/client/packages/lowcoder/src/redux/reduxActions/folderActions.ts @@ -58,6 +58,7 @@ export interface MoveToFolderPayload { sourceFolderId: string; sourceId: string; folderId: string; + moveFlag?: boolean; } export const moveToFolder = ( diff --git a/client/packages/lowcoder/src/redux/sagas/folderSagas.ts b/client/packages/lowcoder/src/redux/sagas/folderSagas.ts index 65a39f030..62b74659e 100644 --- a/client/packages/lowcoder/src/redux/sagas/folderSagas.ts +++ b/client/packages/lowcoder/src/redux/sagas/folderSagas.ts @@ -84,14 +84,16 @@ export function* deleteFolderSaga(action: ReduxActionWithCallbacks) { try { + const { moveFlag } = action.payload; + delete action.payload.moveFlag; const response: AxiosResponse> = yield FolderApi.moveToFolder( action.payload ); const isValidResponse: boolean = validateResponse(response); - + const type = moveFlag ? ReduxActionTypes.MOVE_TO_FOLDER2_SUCCESS : ReduxActionTypes.MOVE_TO_FOLDER_SUCCESS; if (isValidResponse) { yield put({ - type: ReduxActionTypes.MOVE_TO_FOLDER_SUCCESS, + type, payload: action.payload, }); action.onSuccessCallback && action.onSuccessCallback(response); From b6e07d55815abd7eeaebbf8d08dc19a47af7e155 Mon Sep 17 00:00:00 2001 From: Imiss-U1025 Date: Thu, 21 Nov 2024 11:56:59 -0500 Subject: [PATCH 14/28] Made be possible Drag and Drop in extension. --- .../DraggableTree/DraggableItem.tsx | 2 +- .../DraggableTree/DroppableMenuItem.tsx | 52 +++++++++++-------- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/client/packages/lowcoder/src/components/DraggableTree/DraggableItem.tsx b/client/packages/lowcoder/src/components/DraggableTree/DraggableItem.tsx index c8a0f093e..4d827381c 100644 --- a/client/packages/lowcoder/src/components/DraggableTree/DraggableItem.tsx +++ b/client/packages/lowcoder/src/components/DraggableTree/DraggableItem.tsx @@ -15,7 +15,7 @@ const Wrapper = styled.div<{ $itemHeight?: number; }>` position: relative; - width: 100%; + width: auto; height: ${(props) => props.$itemHeight ?? 30}px; /* border: 1px solid #d7d9e0; */ border-radius: 4px; diff --git a/client/packages/lowcoder/src/components/DraggableTree/DroppableMenuItem.tsx b/client/packages/lowcoder/src/components/DraggableTree/DroppableMenuItem.tsx index 68c355ec3..3d49e438a 100644 --- a/client/packages/lowcoder/src/components/DraggableTree/DroppableMenuItem.tsx +++ b/client/packages/lowcoder/src/components/DraggableTree/DroppableMenuItem.tsx @@ -6,6 +6,7 @@ import { DraggableTreeContext } from "./DraggableTreeContext"; import DroppablePlaceholder from "./DroppablePlaceHolder"; import { DraggableTreeNode, DraggableTreeNodeItemRenderProps, IDragData, IDropData } from "./types"; import { checkDroppableFlag } from "./util"; +import { Flex } from "antd"; const DraggableMenuItemWrapper = styled.div` position: relative; @@ -88,29 +89,34 @@ export default function DraggableMenuItem(props: IDraggableMenuItemProps) { disabled={isDragging || disabled} /> )} - { - setDragNodeRef(node); - setDropNodeRef(node); - }} - {...dragListeners} - > - {renderContent?.({ - node: item, - isOver, - path, - isOverlay, - hasChildren: items.length > 0, - dragging: !!(isDragging || parentDragging), - isFolded: isFold, - onDelete: () => onDelete?.(path), - onToggleFold: () => context.toggleFold(id), - }) || null} - + + { + setDragNodeRef(node); + setDropNodeRef(node); + }} + {...dragListeners} + > + + +
+ {renderContent?.({ + node: item, + isOver, + path, + isOverlay, + hasChildren: items.length > 0, + dragging: !!(isDragging || parentDragging), + isFolded: isFold, + onDelete: () => onDelete?.(path), + onToggleFold: () => context.toggleFold(id), + }) || null} +
+
{items.length > 0 && !isFold && (
From 63534caada12c8fb5f85ee05c97621a8fda03d55 Mon Sep 17 00:00:00 2001 From: Imiss-U1025 Date: Thu, 21 Nov 2024 16:34:11 -0500 Subject: [PATCH 15/28] Added removing module. --- .../src/pages/editor/right/ModulePanel.tsx | 189 ++++++++++++++---- .../reducers/uiReducers/folderReducer.ts | 20 +- 2 files changed, 163 insertions(+), 46 deletions(-) diff --git a/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx b/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx index 7655ad57b..7951a36e3 100644 --- a/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx +++ b/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx @@ -13,13 +13,13 @@ import { PointIcon, PopupCard, UnfoldIcon, - FileFolderIcon + FileFolderIcon, messageInstance, CustomModal } from "lowcoder-design"; -import { trans } from "i18n"; +import {trans, transToNode} from "i18n"; import { draggingUtils } from "layout/draggingUtils"; -import {CSSProperties, useContext, useEffect, useState} from "react"; +import React, {CSSProperties, useContext, useEffect, useState} from "react"; import { useDispatch, useSelector } from "react-redux"; -import { fetchAllModules } from "redux/reduxActions/applicationActions"; +import {fetchAllModules, recycleApplication} from "redux/reduxActions/applicationActions"; import styled from "styled-components"; import CreateAppButton from "components/CreateAppButton"; import { TransparentImg } from "util/commonUtils"; @@ -31,12 +31,20 @@ import {showAppSnapshotSelector} from "@lowcoder-ee/redux/selectors/appSnapshotS import {DraggableTreeNode, DraggableTreeNodeItemRenderProps} from "@lowcoder-ee/components/DraggableTree/types"; import RefTreeComp from "@lowcoder-ee/comps/comps/refTreeComp"; import { EmptyContent } from "components/EmptyContent"; +import {moveToFolder} from "@lowcoder-ee/redux/reduxActions/folderActions"; +import {HomeResInfo} from "@lowcoder-ee/util/homeResUtils"; const ItemWrapper = styled.div` display: flex; flex-direction: row; &:last-child { margin-bottom: 0; } + .module-container { + //width: 70px; + display: flex; + justify-content: space-between; + text-align: left; + } .module-icon { display: flex; @@ -52,6 +60,8 @@ const ItemWrapper = styled.div` overflow: hidden; } .module-name { + //flex-grow: 1; + //margin-right: 8px; line-height: 1.5; font-size: 13px; overflow: hidden; @@ -77,8 +87,8 @@ function buildTree(elementRecord: Record = {}; let rootNode: NodeType = { - name: "", - id: "", + name: "root", + id: "root", isFolder: true, children: [], rename: val => rootNode.name = val, @@ -99,7 +109,7 @@ function buildTree(elementRecord: Record { + rootNode.children.sort((a, b) => { if (a.isFolder && !b.isFolder) { return -1; // a is a isFolder and should come first } else if (!a.isFolder && b.isFolder) { @@ -150,7 +160,7 @@ function buildTree(elementRecord: Record { console.log(meta); + e.stopPropagation(); e.dataTransfer.setData("compType", compType); e.dataTransfer.setDragImage(TransparentImg, 0, 0); draggingUtils.setData("compType", compType); @@ -183,11 +194,13 @@ function ModuleItem(props: ModuleItemProps) { props.onDrag(compType); }} > -
- -
-
-
{props.meta.name}
+
+
+ +
+
+
{props.meta.name}
+
); @@ -372,28 +385,29 @@ function ModuleSidebarItem(props: ModuleSidebarItemProps) { {isFolder && {!isFolded ? : }} - {isFolder ? - <> - -
- setEditing(editing)} - /> - -
: - } + { isFolder ? + <> + +
+ setEditing(editing)} + /> + +
+ : + } {!readOnly && !isOverlay && ( - + onDelete()}> )} @@ -404,9 +418,10 @@ function ModuleSidebarItem(props: ModuleSidebarItemProps) { export default function ModulePanel() { const dispatch = useDispatch(); - const elements = useSelector(folderElementsSelector); + let elements = useSelector(folderElementsSelector); + // const reload = () => elements = useSelector(folderElementsSelector); const { onDrag, searchValue } = useContext(RightContext); - + const [deleteFlag, setDeleteFlag] = useState(false); useEffect(() => { dispatch(fetchAllModules({})); }, [dispatch]); @@ -433,9 +448,12 @@ export default function ModulePanel() { } const getById = (id: string): NodeType | undefined => getByIdFromNode(tree, id); + let popedItem : DraggableTreeNode[] = []; + let popedItemSourceId = "" const convertRefTree = (treeNode: NodeType) => { const moduleResComp = getById(treeNode.id); const currentNodeType = moduleResComp?.isFolder; + const childrenItems = treeNode.children .map((i) => convertRefTree(i as NodeType)) .filter((i): i is DraggableTreeNode => !!i); @@ -473,21 +491,73 @@ export default function ModulePanel() { data: moduleResComp, addSubItem(value) { console.log("addSubItem", node.id, value, node); + // node.items.push(value) // const pushAction = node.items.pushAction({ value: value.id() }); // node.items.dispatch(pushAction); }, deleteItem(index) { - console.log("deleteItem", node.id, index); + console.log("deleteItem", node, index); + popedItemSourceId = node.id!; + if(!deleteFlag){ + popedItem = node.items.splice(index, 1); + console.log(popedItem); + } + // const deleteAction = node.children.items.deleteAction(index); // node.children.items.dispatch(deleteAction); }, addItem(value) { - console.log("addItem", node.id, value); + console.log("additem", "value", value, node); + node.items.push(popedItem[0]) + popedItem = []; // const pushAction = node.children.items.pushAction({ value: value.id() }); // node.children.items.dispatch(pushAction); + // if (popedItem[0]){ + // dispatch( + // moveToFolder( + // { + // sourceFolderId: popedItemSourceId, + // sourceId: popedItem[0].id!, + // folderId: node.id!, + // moveFlag: true + // }, + // () => { + // + // + // }, + // () => {} + // ) + // ); + // node.items.push(popedItem[0]); + // popedItemSourceId = ""; + // popedItem = []; + // } }, moveItem(from, to) { - console.log("node", node); + console.log("moveItem", node, from, to, node.id); + if (popedItem[0]){ + node.items.push(popedItem[0]); + + dispatch( + moveToFolder( + { + sourceFolderId: popedItemSourceId, + sourceId: popedItem[0].id!, + folderId: node.id!, + moveFlag: true + }, + () => { + + + }, + () => {} + ) + ); + popedItemSourceId = ""; + popedItem = []; + + } + // popedItem = []; // const moveAction = node.children.items.arrayMoveAction(from, to); // node.children.items.dispatch(moveAction); }, @@ -505,18 +575,51 @@ export default function ModulePanel() { }; const node = convertRefTree(tree); - + console.log("started!!!!", node) function onCopy(type: boolean, id: string) { console.log("onCopy", type, id); } function onSelect(type: boolean, id: string, meta: any) { console.log("onSelect", type, id, meta) - return + // return } function onDelete(type: boolean, id: string) { - console.log("onDelete", type, id); + setDeleteFlag(true); + console.log("1111111111111111111111111", type, id, node); + if (type) { + alert(1); + } + else { + CustomModal.confirm({ + title: trans("home.moveToTrash"), + content: transToNode("home.moveToTrashSubTitle", { + type: "", + name: "This file", + }), + onConfirm: () => { + dispatch( + recycleApplication( + { + applicationId: id, + folderId: popedItemSourceId, + }, + () => { + messageInstance.success(trans("success")) + + }, + () => { + } + ) + ) + setDeleteFlag(false) + }, + confirmBtnType: "delete", + okText: trans("home.moveToTrash"), + onCancel: () => setDeleteFlag(false) + }); + } return true; } diff --git a/client/packages/lowcoder/src/redux/reducers/uiReducers/folderReducer.ts b/client/packages/lowcoder/src/redux/reducers/uiReducers/folderReducer.ts index 21cc2bfa1..4d1562811 100644 --- a/client/packages/lowcoder/src/redux/reducers/uiReducers/folderReducer.ts +++ b/client/packages/lowcoder/src/redux/reducers/uiReducers/folderReducer.ts @@ -37,10 +37,24 @@ export const folderReducer = createReducer(initialState, { state: FolderReduxState, action: ReduxAction ): FolderReduxState => { + const deleteArray : number[] = []; const elements = { ...state.folderElements }; - elements[action.payload.folderId ?? ""] = elements[action.payload.folderId ?? ""]?.filter( - (e) => e.folder || (!e.folder && e.applicationId !== action.payload.applicationId) - ); + elements[""] = elements[""].map((item, index) => { + if(item.folder) { + const tempSubApplications = item.subApplications?.filter(e => e.applicationId !== action.payload.applicationId); + return { ...item, subApplications: tempSubApplications }; + } else { + if (item.applicationId !== action.payload.applicationId) + return item; + else { + deleteArray.push(index); + return item; + } + } + }); + deleteArray.map(item => { + elements[""].splice(item, 1); + }) return { ...state, folderElements: elements, From c8daa8dd36b84ca17efd20a2e8ddcb52362822a1 Mon Sep 17 00:00:00 2001 From: Imiss-U1025 Date: Fri, 22 Nov 2024 01:16:35 -0500 Subject: [PATCH 16/28] Added removing folder. --- .../packages/lowcoder/src/i18n/locales/en.ts | 1 + .../src/pages/editor/right/ModulePanel.tsx | 81 ++++++++++++------- 2 files changed, 52 insertions(+), 30 deletions(-) diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index a4672903e..999890d01 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -2785,6 +2785,7 @@ export const en = { "switch": "Switch Component: " }, "module": { + "folderNotEmpty": "Folder is not empty", "emptyText": "No Data", "docLink": "Read More About Modules...", "documentationText" : "Modules are complete Applications, that can get included and repeated in other Applications and it functions just like a single component. As modules can get embedded, they need to be able to interact with your outside apps or websites. This four settings help to support communication with a Module.", diff --git a/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx b/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx index 7951a36e3..07e3a91a4 100644 --- a/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx +++ b/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx @@ -31,7 +31,7 @@ import {showAppSnapshotSelector} from "@lowcoder-ee/redux/selectors/appSnapshotS import {DraggableTreeNode, DraggableTreeNodeItemRenderProps} from "@lowcoder-ee/components/DraggableTree/types"; import RefTreeComp from "@lowcoder-ee/comps/comps/refTreeComp"; import { EmptyContent } from "components/EmptyContent"; -import {moveToFolder} from "@lowcoder-ee/redux/reduxActions/folderActions"; +import {deleteFolder, moveToFolder} from "@lowcoder-ee/redux/reduxActions/folderActions"; import {HomeResInfo} from "@lowcoder-ee/util/homeResUtils"; const ItemWrapper = styled.div` display: flex; @@ -585,42 +585,65 @@ export default function ModulePanel() { // return } - function onDelete(type: boolean, id: string) { + function onDelete(type: boolean, id: string, node: NodeType) { setDeleteFlag(true); console.log("1111111111111111111111111", type, id, node); if (type) { - alert(1); - } - else { - CustomModal.confirm({ - title: trans("home.moveToTrash"), - content: transToNode("home.moveToTrashSubTitle", { - type: "", - name: "This file", - }), - onConfirm: () => { + if (node.children.length) { + messageInstance.error(trans("module.folderNotEmpty")) + } else { + try { dispatch( - recycleApplication( - { - applicationId: id, - folderId: popedItemSourceId, - }, + deleteFolder( + {folderId: id, parentFolderId: ""}, () => { - messageInstance.success(trans("success")) - + messageInstance.success(trans("home.deleteSuccessMsg")); }, () => { + messageInstance.error(trans("error")) } ) - ) - setDeleteFlag(false) - }, - confirmBtnType: "delete", - okText: trans("home.moveToTrash"), - onCancel: () => setDeleteFlag(false) - }); + ); + } catch (error) { + console.error("Error: Delete module in extension:", error); + throw error; + } + } + } else { + try { + CustomModal.confirm({ + title: trans("home.moveToTrash"), + content: transToNode("home.moveToTrashSubTitle", { + type: "", + name: "This file", + }), + onConfirm: () => { + dispatch( + recycleApplication( + { + applicationId: id, + folderId: popedItemSourceId, + }, + () => { + messageInstance.success(trans("success")); + + }, + () => { + messageInstance.error(trans("error")); + } + ) + ) + setDeleteFlag(false) + }, + confirmBtnType: "delete", + okText: trans("home.moveToTrash"), + onCancel: () => setDeleteFlag(false) + }); + } catch (error) { + console.error("Error: Delete module in extension:", error); + throw error; + } } - return true; } return ( @@ -661,9 +684,7 @@ export default function ModulePanel() { onCopy={() => onCopy(isFolder, id)} onSelect={() => onSelect(isFolder, id, resComp)} onDelete={() => { - if (onDelete(isFolder, id)) { - onDeleteTreeItem(); - } + (onDelete(isFolder, id, resComp)) }} {...otherParams} /> From 39dbd40d966692f3a08219227a9e66d865616d76 Mon Sep 17 00:00:00 2001 From: Imiss-U1025 Date: Fri, 22 Nov 2024 04:19:43 -0500 Subject: [PATCH 17/28] Added Renaming folders. --- .../src/pages/editor/right/ModulePanel.tsx | 38 +++++++++++-------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx b/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx index 07e3a91a4..bf66584cb 100644 --- a/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx +++ b/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx @@ -31,7 +31,7 @@ import {showAppSnapshotSelector} from "@lowcoder-ee/redux/selectors/appSnapshotS import {DraggableTreeNode, DraggableTreeNodeItemRenderProps} from "@lowcoder-ee/components/DraggableTree/types"; import RefTreeComp from "@lowcoder-ee/comps/comps/refTreeComp"; import { EmptyContent } from "components/EmptyContent"; -import {deleteFolder, moveToFolder} from "@lowcoder-ee/redux/reduxActions/folderActions"; +import {deleteFolder, moveToFolder, updateFolder} from "@lowcoder-ee/redux/reduxActions/folderActions"; import {HomeResInfo} from "@lowcoder-ee/util/homeResUtils"; const ItemWrapper = styled.div` display: flex; @@ -300,6 +300,10 @@ interface ModuleSidebarItemProps extends DraggableTreeNodeItemRenderProps { onSelect: () => void; onDelete: () => void; onToggleFold: () => void; + selectedID: string; + setSelectedID: (id: string) => void; + selectedType: boolean; + setSelectedType: (id: boolean) => void; } const empty = ( @@ -321,6 +325,7 @@ const empty = ( ); function ModuleSidebarItem(props: ModuleSidebarItemProps) { + const dispatch = useDispatch(); const { id, resComp, @@ -328,6 +333,10 @@ function ModuleSidebarItem(props: ModuleSidebarItemProps) { isOverlay, path, isFolded, + selectedID, + setSelectedID, + selectedType, + setSelectedType, onDelete, onCopy, onSelect, @@ -338,13 +347,11 @@ function ModuleSidebarItem(props: ModuleSidebarItemProps) { const [editing, setEditing] = useState(false); const editorState = useContext(EditorContext); const readOnly = useSelector(showAppSnapshotSelector); - const [selectedModuleResName, setSelectedModuleResName] = useState(""); - const [selectedModuleResType, setSelectedModuleResType] = useState(false); const level = path.length - 1; const type = resComp.isFolder; const name = resComp.name; const icon = resComp.isFolder? : ; - const isSelected = type === selectedModuleResType && id === selectedModuleResName; + const isSelected = type === selectedType && id === selectedID; const isFolder = type; const handleFinishRename = (value: string) => { @@ -358,20 +365,15 @@ function ModuleSidebarItem(props: ModuleSidebarItemProps) { success = true; } if (success) { - setSelectedModuleResName(compId); - setSelectedModuleResType(type); + setSelectedID(compId); + setSelectedType(type); setError(undefined); + dispatch(updateFolder({ id: selectedID, name: value })); } }; const handleNameChange = (value: string) => { - let err = ""; - if (resComp.checkName) { - err = resComp.checkName(value); - } else { - err = editorState.checkRename(name, value); - } - setError(err); + value === "" ? setError("Cannot Be Empty") : setError(""); }; const handleClickItem = () => { @@ -422,6 +424,8 @@ export default function ModulePanel() { // const reload = () => elements = useSelector(folderElementsSelector); const { onDrag, searchValue } = useContext(RightContext); const [deleteFlag, setDeleteFlag] = useState(false); + const [selectedID, setSelectedID] = useState(""); + const [selectedType, setSelectedType] = useState(false); useEffect(() => { dispatch(fetchAllModules({})); }, [dispatch]); @@ -575,14 +579,14 @@ export default function ModulePanel() { }; const node = convertRefTree(tree); - console.log("started!!!!", node) function onCopy(type: boolean, id: string) { console.log("onCopy", type, id); } function onSelect(type: boolean, id: string, meta: any) { + setSelectedID(id); + setSelectedType(type); console.log("onSelect", type, id, meta) - // return } function onDelete(type: boolean, id: string, node: NodeType) { @@ -683,6 +687,10 @@ export default function ModulePanel() { onToggleFold={onToggleFold} onCopy={() => onCopy(isFolder, id)} onSelect={() => onSelect(isFolder, id, resComp)} + selectedID={selectedID} + setSelectedID={setSelectedID} + selectedType={selectedType} + setSelectedType={setSelectedType} onDelete={() => { (onDelete(isFolder, id, resComp)) }} From 521370f0e6cc65536c490cba935cd5db317592d0 Mon Sep 17 00:00:00 2001 From: Imiss-U1025 Date: Fri, 22 Nov 2024 09:06:27 -0500 Subject: [PATCH 18/28] Added removing modules --- .../src/pages/editor/right/ModulePanel.tsx | 99 +++++++++++++++++-- .../reducers/uiReducers/folderReducer.ts | 9 ++ 2 files changed, 100 insertions(+), 8 deletions(-) diff --git a/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx b/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx index bf66584cb..a5ef3f989 100644 --- a/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx +++ b/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx @@ -19,7 +19,7 @@ import {trans, transToNode} from "i18n"; import { draggingUtils } from "layout/draggingUtils"; import React, {CSSProperties, useContext, useEffect, useState} from "react"; import { useDispatch, useSelector } from "react-redux"; -import {fetchAllModules, recycleApplication} from "redux/reduxActions/applicationActions"; +import {fetchAllModules, recycleApplication, updateAppMetaAction} from "redux/reduxActions/applicationActions"; import styled from "styled-components"; import CreateAppButton from "components/CreateAppButton"; import { TransparentImg } from "util/commonUtils"; @@ -27,7 +27,7 @@ import { ComListTitle } from "./styledComponent"; import {folderElementsSelector} from "@lowcoder-ee/redux/selectors/folderSelector"; import {DraggableTree} from "@lowcoder-ee/components/DraggableTree/DraggableTree"; import {EditorContext} from "lowcoder-sdk"; -import {showAppSnapshotSelector} from "@lowcoder-ee/redux/selectors/appSnapshotSelector"; +import {getSelectedAppSnapshot, showAppSnapshotSelector} from "@lowcoder-ee/redux/selectors/appSnapshotSelector"; import {DraggableTreeNode, DraggableTreeNodeItemRenderProps} from "@lowcoder-ee/components/DraggableTree/types"; import RefTreeComp from "@lowcoder-ee/comps/comps/refTreeComp"; import { EmptyContent } from "components/EmptyContent"; @@ -168,11 +168,65 @@ function buildTree(elementRecord: Record void; + isOverlay: boolean; + selectedID: string; + setSelectedID: (id: string) => void; + selectedType: boolean; + setSelectedType: (id: boolean) => void; + resComp: NodeType; + id: string; } function ModuleItem(props: ModuleItemProps) { const compType = "module"; - const { meta } = props; + const { + meta , + isOverlay, + selectedID, + setSelectedID, + selectedType, + setSelectedType, + resComp, + id + } = props; + const dispatch = useDispatch(); + const type = resComp.isFolder; + const name = resComp.name; + const [error, setError] = useState(undefined); + const [editing, setEditing] = useState(false); + const editorState = useContext(EditorContext); + const readOnly = useSelector(showAppSnapshotSelector); + const isSelected = type === selectedType && id === selectedID; + const handleFinishRename = (value: string) => { + let success = false; + let compId = name; + if (resComp.rename) { + compId = resComp.rename(value); + success = !!compId; + } else { + compId = name; + success = true; + } + if (success) { + console.log(selectedID, value); + setSelectedID(compId); + setSelectedType(type); + setError(undefined); + try{ + dispatch(updateAppMetaAction({ + applicationId: selectedID, + name: value + })); + } catch (error) { + console.error("Error: Delete module in extension:", error); + throw error; + } + } + }; + + const handleNameChange = (value: string) => { + value === "" ? setError("Cannot Be Empty") : setError(""); + }; return (
-
-
{props.meta.name}
+ +
+ setEditing(editing)} + /> +
@@ -368,7 +436,13 @@ function ModuleSidebarItem(props: ModuleSidebarItemProps) { setSelectedID(compId); setSelectedType(type); setError(undefined); - dispatch(updateFolder({ id: selectedID, name: value })); + try{ + dispatch(updateFolder({ id: selectedID, name: value })); + } catch (error) { + console.error("Error: Delete module in extension:", error); + throw error; + } + } }; @@ -407,7 +481,17 @@ function ModuleSidebarItem(props: ModuleSidebarItemProps) { />
: - } + } {!readOnly && !isOverlay && ( onDelete()}> @@ -421,7 +505,6 @@ function ModuleSidebarItem(props: ModuleSidebarItemProps) { export default function ModulePanel() { const dispatch = useDispatch(); let elements = useSelector(folderElementsSelector); - // const reload = () => elements = useSelector(folderElementsSelector); const { onDrag, searchValue } = useContext(RightContext); const [deleteFlag, setDeleteFlag] = useState(false); const [selectedID, setSelectedID] = useState(""); diff --git a/client/packages/lowcoder/src/redux/reducers/uiReducers/folderReducer.ts b/client/packages/lowcoder/src/redux/reducers/uiReducers/folderReducer.ts index 4d1562811..4ad02e446 100644 --- a/client/packages/lowcoder/src/redux/reducers/uiReducers/folderReducer.ts +++ b/client/packages/lowcoder/src/redux/reducers/uiReducers/folderReducer.ts @@ -69,6 +69,15 @@ export const folderReducer = createReducer(initialState, { elements[action.payload.folderId ?? ""] = elements[action.payload.folderId ?? ""]?.map((e) => { if (!e.folder && e.applicationId === action.payload.applicationId) { return { ...e, ...action.payload }; + } else { + if (e.folder) { + // console.log(e.subApplications); + if (e.subApplications?.map(item => { + if (item.applicationId === action.payload.applicationId) + item.name = action.payload.name + })){ + } + } } return e; }); From fdc01456321016875d70a486b006435ba91fd28e Mon Sep 17 00:00:00 2001 From: Imiss-U1025 Date: Fri, 22 Nov 2024 09:46:41 -0500 Subject: [PATCH 19/28] Fixed UI. --- .../src/pages/editor/right/ModulePanel.tsx | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx b/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx index a5ef3f989..5c7dea317 100644 --- a/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx +++ b/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx @@ -40,17 +40,12 @@ const ItemWrapper = styled.div` margin-bottom: 0; } .module-container { - //width: 70px; display: flex; - justify-content: space-between; - text-align: left; } .module-icon { - - display: flex; - justify-content: center; - align-items: center; - margin: 4px; + margin-right: 4px; + width:19px; + height: 19px; } .module-content { flex: 1; @@ -249,10 +244,7 @@ function ModuleItem(props: ModuleItemProps) { }} >
-
- -
- +
(props.$active ? BorderActiveColor : "transparent")}; align-items: center; - justify-content: center; + justify-content: space-between; `; interface ColumnDivProps { @@ -463,7 +455,7 @@ function ModuleSidebarItem(props: ModuleSidebarItemProps) { {isFolder && {!isFolded ? : }} { isFolder ? <> - +
Date: Fri, 22 Nov 2024 11:57:01 -0500 Subject: [PATCH 20/28] Fxied ability to module drag and drop in right panel. --- .../src/pages/editor/right/ModulePanel.tsx | 126 ++++++++---------- .../reducers/uiReducers/folderReducer.ts | 66 +++++---- 2 files changed, 94 insertions(+), 98 deletions(-) diff --git a/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx b/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx index 5c7dea317..7510bad67 100644 --- a/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx +++ b/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx @@ -83,7 +83,7 @@ function buildTree(elementRecord: Record = {}; let rootNode: NodeType = { name: "root", - id: "root", + id: "", isFolder: true, children: [], rename: val => rootNode.name = val, @@ -498,16 +498,54 @@ export default function ModulePanel() { const dispatch = useDispatch(); let elements = useSelector(folderElementsSelector); const { onDrag, searchValue } = useContext(RightContext); - const [deleteFlag, setDeleteFlag] = useState(false); const [selectedID, setSelectedID] = useState(""); const [selectedType, setSelectedType] = useState(false); + let sourceFolderId : string = ""; + let sourceId : string = ""; + let folderId : string = ""; + const tree = buildTree(elements); + const getById = (id: string): NodeType | undefined => getByIdFromNode(tree, id); + let popedItem : DraggableTreeNode[] = []; + let popedItemSourceId = ""; + useEffect(() => { - dispatch(fetchAllModules({})); + dispatch(fetchAllModules({})); }, [dispatch]); + const moveModule = () => { + console.log({sourceFolderId: sourceFolderId, + sourceId: sourceId, + folderId: folderId, + moveFlag: true}) + try{ + if (sourceId !== "") { + dispatch( + moveToFolder( + { + sourceFolderId: sourceFolderId!, + sourceId: sourceId!, + folderId: folderId!, + moveFlag: true + }, + () => { + + + }, + () => {} + ) + ); + } + } catch (error) { + console.error("Error: Delete module in extension:", error); + throw error; + } finally { + folderId = ""; + sourceId = ""; + sourceFolderId = ""; + } + + } - //Convert elements into tree - const tree = buildTree(elements); const getByIdFromNode = (root: NodeType | null, id: string): NodeType | undefined => { if (!root) { return; @@ -525,11 +563,7 @@ export default function ModulePanel() { } return; } - - const getById = (id: string): NodeType | undefined => getByIdFromNode(tree, id); - let popedItem : DraggableTreeNode[] = []; - let popedItemSourceId = "" - const convertRefTree = (treeNode: NodeType) => { + const convertRefTree = (treeNode: NodeType) => { //Convert elements into tree const moduleResComp = getById(treeNode.id); const currentNodeType = moduleResComp?.isFolder; @@ -570,75 +604,25 @@ export default function ModulePanel() { data: moduleResComp, addSubItem(value) { console.log("addSubItem", node.id, value, node); + folderId = node.id!; + moveModule(); // node.items.push(value) // const pushAction = node.items.pushAction({ value: value.id() }); // node.items.dispatch(pushAction); }, deleteItem(index) { - console.log("deleteItem", node, index); - popedItemSourceId = node.id!; - if(!deleteFlag){ - popedItem = node.items.splice(index, 1); - console.log(popedItem); - } + console.log("deleteItem", index, node); + sourceFolderId = node.id!; + sourceId = node.items[index].id!; - // const deleteAction = node.children.items.deleteAction(index); - // node.children.items.dispatch(deleteAction); }, addItem(value) { - console.log("additem", "value", value, node); - node.items.push(popedItem[0]) - popedItem = []; - // const pushAction = node.children.items.pushAction({ value: value.id() }); - // node.children.items.dispatch(pushAction); - // if (popedItem[0]){ - // dispatch( - // moveToFolder( - // { - // sourceFolderId: popedItemSourceId, - // sourceId: popedItem[0].id!, - // folderId: node.id!, - // moveFlag: true - // }, - // () => { - // - // - // }, - // () => {} - // ) - // ); - // node.items.push(popedItem[0]); - // popedItemSourceId = ""; - // popedItem = []; - // } + console.log("additem", "value", value, "node", node); + folderId = node.id!; + moveModule(); }, moveItem(from, to) { console.log("moveItem", node, from, to, node.id); - if (popedItem[0]){ - node.items.push(popedItem[0]); - - dispatch( - moveToFolder( - { - sourceFolderId: popedItemSourceId, - sourceId: popedItem[0].id!, - folderId: node.id!, - moveFlag: true - }, - () => { - - - }, - () => {} - ) - ); - popedItemSourceId = ""; - popedItem = []; - - } - // popedItem = []; - // const moveAction = node.children.items.arrayMoveAction(from, to); - // node.children.items.dispatch(moveAction); }, }; @@ -652,7 +636,6 @@ export default function ModulePanel() { } return node; }; - const node = convertRefTree(tree); function onCopy(type: boolean, id: string) { console.log("onCopy", type, id); @@ -665,8 +648,8 @@ export default function ModulePanel() { } function onDelete(type: boolean, id: string, node: NodeType) { - setDeleteFlag(true); console.log("1111111111111111111111111", type, id, node); + if (type) { if (node.children.length) { messageInstance.error(trans("module.folderNotEmpty")) @@ -712,11 +695,10 @@ export default function ModulePanel() { } ) ) - setDeleteFlag(false) }, confirmBtnType: "delete", okText: trans("home.moveToTrash"), - onCancel: () => setDeleteFlag(false) + onCancel: () => {} }); } catch (error) { console.error("Error: Delete module in extension:", error); diff --git a/client/packages/lowcoder/src/redux/reducers/uiReducers/folderReducer.ts b/client/packages/lowcoder/src/redux/reducers/uiReducers/folderReducer.ts index 4ad02e446..e4ca19920 100644 --- a/client/packages/lowcoder/src/redux/reducers/uiReducers/folderReducer.ts +++ b/client/packages/lowcoder/src/redux/reducers/uiReducers/folderReducer.ts @@ -71,7 +71,6 @@ export const folderReducer = createReducer(initialState, { return { ...e, ...action.payload }; } else { if (e.folder) { - // console.log(e.subApplications); if (e.subApplications?.map(item => { if (item.applicationId === action.payload.applicationId) item.name = action.payload.name @@ -148,34 +147,49 @@ export const folderReducer = createReducer(initialState, { action: ReduxAction ): FolderReduxState => { let elements = { ...state.folderElements }; - let tempIndex: number | undefined; - let tempNode: any; - let temp = elements[""].map((item, index) => { - if (item.folderId === action.payload.sourceFolderId && item.folder) { - - const tempSubApplications = item.subApplications?.filter(e => - (e.folder && e.folderId !== action.payload.sourceId) || - (!e.folder && e.applicationId !== action.payload.sourceId) - ); - tempNode = item.subApplications?.filter(e => - (e.folder && e.folderId === action.payload.sourceId) || - (!e.folder && e.applicationId === action.payload.sourceId) - ); - return { ...item, subApplications: tempSubApplications }; - } - if (item.folderId === action.payload.folderId && item.folder) { - tempIndex = index; + const { sourceId, folderId, sourceFolderId } = action.payload; + if(sourceFolderId === "") { + const tempItem = elements[""]?.find(e => + !e.folder && e.applicationId === sourceId + ); + elements[""] = elements[""]?.filter(e => e.folder || (e.applicationId !== sourceId)); + elements[""] = elements[""].map(item => { + if(item.folder && item.folderId === folderId && tempItem !== undefined && !tempItem.folder) { + item.subApplications?.push(tempItem); + } return item; + }) + } else{ + let tempIndex: number | undefined; + let tempNode: any; + let temp = elements[""].map((item, index) => { + if (item.folderId === sourceFolderId && item.folder) { + const tempSubApplications = item.subApplications?.filter(e => + (e.folder && e.folderId !== sourceId) || + (!e.folder && e.applicationId !== sourceId) + ); + tempNode = item.subApplications?.filter(e => + (e.folder && e.folderId === sourceId) || + (!e.folder && e.applicationId === sourceId) + ); + return { ...item, subApplications: tempSubApplications }; + } + if (item.folderId === folderId && item.folder) { + tempIndex = index; + return item; + } + return item; + }); + if (tempIndex !== undefined) { + const targetItem = temp[tempIndex]; + if (targetItem.folder && Array.isArray(targetItem.subApplications)) { + targetItem.subApplications.push(tempNode[0]); + } + } else { + temp.push(tempNode[0]); } - return item; - }); - if (tempIndex !== undefined) { - const targetItem = temp[tempIndex]; - if (targetItem.folder && Array.isArray(targetItem.subApplications)) { - targetItem.subApplications.push(tempNode[0]); - } + elements[""] = temp; } - elements[""] = temp; return { ...state, folderElements: elements, From 4e4e9064035e4b99ba767bd32203b1980b417f23 Mon Sep 17 00:00:00 2001 From: Imiss-U1025 Date: Fri, 22 Nov 2024 14:52:07 -0500 Subject: [PATCH 21/28] Fixed an issue where subApplications are hidden when rename a folder. --- .../src/pages/editor/right/ModulePanel.tsx | 396 +++++++++--------- .../reducers/uiReducers/folderReducer.ts | 2 +- 2 files changed, 189 insertions(+), 209 deletions(-) diff --git a/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx b/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx index 7510bad67..3110647a4 100644 --- a/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx +++ b/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx @@ -17,7 +17,7 @@ import { } from "lowcoder-design"; import {trans, transToNode} from "i18n"; import { draggingUtils } from "layout/draggingUtils"; -import React, {CSSProperties, useContext, useEffect, useState} from "react"; +import React, { useContext, useEffect, useState} from "react"; import { useDispatch, useSelector } from "react-redux"; import {fetchAllModules, recycleApplication, updateAppMetaAction} from "redux/reduxActions/applicationActions"; import styled from "styled-components"; @@ -26,13 +26,10 @@ import { TransparentImg } from "util/commonUtils"; import { ComListTitle } from "./styledComponent"; import {folderElementsSelector} from "@lowcoder-ee/redux/selectors/folderSelector"; import {DraggableTree} from "@lowcoder-ee/components/DraggableTree/DraggableTree"; -import {EditorContext} from "lowcoder-sdk"; -import {getSelectedAppSnapshot, showAppSnapshotSelector} from "@lowcoder-ee/redux/selectors/appSnapshotSelector"; +import { showAppSnapshotSelector} from "@lowcoder-ee/redux/selectors/appSnapshotSelector"; import {DraggableTreeNode, DraggableTreeNodeItemRenderProps} from "@lowcoder-ee/components/DraggableTree/types"; -import RefTreeComp from "@lowcoder-ee/comps/comps/refTreeComp"; import { EmptyContent } from "components/EmptyContent"; import {deleteFolder, moveToFolder, updateFolder} from "@lowcoder-ee/redux/reduxActions/folderActions"; -import {HomeResInfo} from "@lowcoder-ee/util/homeResUtils"; const ItemWrapper = styled.div` display: flex; flex-direction: row; @@ -161,15 +158,15 @@ function buildTree(elementRecord: Record void; - isOverlay: boolean; - selectedID: string; - setSelectedID: (id: string) => void; - selectedType: boolean; - setSelectedType: (id: boolean) => void; - resComp: NodeType; - id: string; + meta: ApplicationMeta; + onDrag: (type: string) => void; + isOverlay: boolean; + selectedID: string; + setSelectedID: (id: string) => void; + selectedType: boolean; + setSelectedType: (id: boolean) => void; + resComp: NodeType; + id: string; } function ModuleItem(props: ModuleItemProps) { @@ -189,44 +186,45 @@ function ModuleItem(props: ModuleItemProps) { const name = resComp.name; const [error, setError] = useState(undefined); const [editing, setEditing] = useState(false); - const editorState = useContext(EditorContext); const readOnly = useSelector(showAppSnapshotSelector); const isSelected = type === selectedType && id === selectedID; const handleFinishRename = (value: string) => { - let success = false; - let compId = name; - if (resComp.rename) { - compId = resComp.rename(value); - success = !!compId; - } else { - compId = name; - success = true; - } - if (success) { - console.log(selectedID, value); - setSelectedID(compId); - setSelectedType(type); - setError(undefined); - try{ - dispatch(updateAppMetaAction({ - applicationId: selectedID, - name: value - })); - } catch (error) { - console.error("Error: Delete module in extension:", error); - throw error; + if (value !== "") { + let success = false; + let compId = name; + if (resComp.rename) { + compId = resComp.rename(value); + success = !!compId; + } else { + compId = name; + success = true; } + if (success) { + setSelectedID(compId); + setSelectedType(type); + setError(undefined); + try { + dispatch(updateAppMetaAction({ + applicationId: selectedID, + name: value + })); + } catch (error) { + console.error("Error: Rename module in extension:", error); + throw error; + } + } + setError(undefined); } + setError(undefined); }; const handleNameChange = (value: string) => { - value === "" ? setError("Cannot Be Empty") : setError(""); + value === "" ? setError("Cannot Be Empty") : setError(undefined); }; return ( { - console.log(meta); e.stopPropagation(); e.dataTransfer.setData("compType", compType); e.dataTransfer.setDragImage(TransparentImg, 0, 0); @@ -244,7 +242,7 @@ function ModuleItem(props: ModuleItemProps) { }} >
- +
` user-select: none; padding-left: 2px; padding-right: 15px; - /* background-color: #ffffff; */ - /* margin: 2px 0; */ background-color: ${(props) => (props.$isOverlay ? "rgba(255, 255, 255, 0.11)" : "")}; &&& { @@ -405,41 +401,42 @@ function ModuleSidebarItem(props: ModuleSidebarItemProps) { const { onDrag } = useContext(RightContext); const [error, setError] = useState(undefined); const [editing, setEditing] = useState(false); - const editorState = useContext(EditorContext); const readOnly = useSelector(showAppSnapshotSelector); const level = path.length - 1; const type = resComp.isFolder; const name = resComp.name; - const icon = resComp.isFolder? : ; const isSelected = type === selectedType && id === selectedID; const isFolder = type; const handleFinishRename = (value: string) => { - let success = false; - let compId = name; - if (resComp.rename) { - compId = resComp.rename(value); - success = !!compId; - } else { - compId = name; - success = true; - } - if (success) { - setSelectedID(compId); - setSelectedType(type); - setError(undefined); - try{ - dispatch(updateFolder({ id: selectedID, name: value })); - } catch (error) { - console.error("Error: Delete module in extension:", error); - throw error; + if (value !== ""){ + let success = false; + let compId = name; + if (resComp.rename) { + compId = resComp.rename(value); + success = !!compId; + } else { + compId = name; + success = true; } + if (success) { + setSelectedID(compId); + setSelectedType(type); + setError(undefined); + try{ + dispatch(updateFolder({ id: selectedID, name: value })); + } catch (error) { + console.error("Error: Delete module in extension:", error); + throw error; + } + } + setError(undefined); } }; const handleNameChange = (value: string) => { - value === "" ? setError("Cannot Be Empty") : setError(""); + value === "" ? setError("Cannot Be Empty") : setError(undefined); }; const handleClickItem = () => { @@ -453,39 +450,39 @@ function ModuleSidebarItem(props: ModuleSidebarItemProps) { {isFolder && {!isFolded ? : }} - { isFolder ? - <> - -
- setEditing(editing)} - /> - -
- : - } + { isFolder ? + <> + +
+ setEditing(editing)} + /> + +
+ : + } {!readOnly && !isOverlay && ( - onDelete()}> + onDelete()}> )} @@ -495,56 +492,51 @@ function ModuleSidebarItem(props: ModuleSidebarItemProps) { } export default function ModulePanel() { - const dispatch = useDispatch(); - let elements = useSelector(folderElementsSelector); - const { onDrag, searchValue } = useContext(RightContext); - const [selectedID, setSelectedID] = useState(""); - const [selectedType, setSelectedType] = useState(false); - let sourceFolderId : string = ""; - let sourceId : string = ""; - let folderId : string = ""; - const tree = buildTree(elements); - const getById = (id: string): NodeType | undefined => getByIdFromNode(tree, id); - let popedItem : DraggableTreeNode[] = []; - let popedItemSourceId = ""; - - useEffect(() => { - dispatch(fetchAllModules({})); - }, [dispatch]); - - const moveModule = () => { - console.log({sourceFolderId: sourceFolderId, - sourceId: sourceId, - folderId: folderId, - moveFlag: true}) - try{ - if (sourceId !== "") { - dispatch( - moveToFolder( - { - sourceFolderId: sourceFolderId!, - sourceId: sourceId!, - folderId: folderId!, - moveFlag: true - }, - () => { - - - }, - () => {} - ) - ); - } - } catch (error) { - console.error("Error: Delete module in extension:", error); - throw error; - } finally { - folderId = ""; - sourceId = ""; - sourceFolderId = ""; - } + const dispatch = useDispatch(); + let elements = useSelector(folderElementsSelector); + const { searchValue } = useContext(RightContext); + const [selectedID, setSelectedID] = useState(""); + const [selectedType, setSelectedType] = useState(false); + let sourceFolderId : string = ""; + let sourceId : string = ""; + let folderId : string = ""; + const tree = buildTree(elements); + const getById = (id: string): NodeType | undefined => getByIdFromNode(tree, id); + let popedItemSourceId = ""; + + useEffect(() => { + dispatch(fetchAllModules({})); + }, [dispatch]); + + const moveModule = () => { + try{ + if (sourceId !== "") { + dispatch( + moveToFolder( + { + sourceFolderId: sourceFolderId!, + sourceId: sourceId!, + folderId: folderId!, + moveFlag: true + }, + () => { + + + }, + () => {} + ) + ); + } + } catch (error) { + console.error("Error: Move module in extension:", error); + throw error; + } finally { + folderId = ""; + sourceId = ""; + sourceFolderId = ""; + } - } + } const getByIdFromNode = (root: NodeType | null, id: string): NodeType | undefined => { if (!root) { @@ -603,26 +595,19 @@ export default function ModulePanel() { items: childrenItems, data: moduleResComp, addSubItem(value) { - console.log("addSubItem", node.id, value, node); folderId = node.id!; moveModule(); - // node.items.push(value) - // const pushAction = node.items.pushAction({ value: value.id() }); - // node.items.dispatch(pushAction); }, deleteItem(index) { - console.log("deleteItem", index, node); sourceFolderId = node.id!; sourceId = node.items[index].id!; }, addItem(value) { - console.log("additem", "value", value, "node", node); folderId = node.id!; moveModule(); }, moveItem(from, to) { - console.log("moveItem", node, from, to, node.id); }, }; @@ -638,18 +623,14 @@ export default function ModulePanel() { }; const node = convertRefTree(tree); function onCopy(type: boolean, id: string) { - console.log("onCopy", type, id); } function onSelect(type: boolean, id: string, meta: any) { setSelectedID(id); setSelectedType(type); - console.log("onSelect", type, id, meta) } function onDelete(type: boolean, id: string, node: NodeType) { - console.log("1111111111111111111111111", type, id, node); - if (type) { if (node.children.length) { messageInstance.error(trans("module.folderNotEmpty")) @@ -667,7 +648,7 @@ export default function ModulePanel() { ) ); } catch (error) { - console.error("Error: Delete module in extension:", error); + console.error("Error: Remove folder in extension:", error); throw error; } } @@ -701,61 +682,60 @@ export default function ModulePanel() { onCancel: () => {} }); } catch (error) { - console.error("Error: Delete module in extension:", error); + console.error("Error: Remove module in extension:", error); throw error; } } } - return ( - <> - {trans("rightPanel.moduleListTitle")} - {node ? - node={node!} - disable={!!searchValue} - unfoldAll={!!searchValue} - showSubInDragOverlay={false} - showDropInPositionLine={false} - showPositionLineDot - positionLineDotDiameter={4} - positionLineHeight={1} - itemHeight={25} - positionLineIndent={(path, dropInAsSub) => { - const indent = 2 + (path.length - 1) * 30; - if (dropInAsSub) { - return indent + 12; - } - return indent; - }} - renderItemContent={(params) => { - const { node, onToggleFold, onDelete: onDeleteTreeItem, ...otherParams } = params; - const resComp = node.data; - if (!resComp) { - return null; - } - const id = resComp.id; - const isFolder = resComp.isFolder; - return ( - onCopy(isFolder, id)} - onSelect={() => onSelect(isFolder, id, resComp)} - selectedID={selectedID} - setSelectedID={setSelectedID} - selectedType={selectedType} - setSelectedType={setSelectedType} - onDelete={() => { - (onDelete(isFolder, id, resComp)) - }} - {...otherParams} - /> - ); - }} - /> : empty} - - ); + <> + {trans("rightPanel.moduleListTitle")} + {node?.items.length ? + node={node!} + disable={!!searchValue} + unfoldAll={!!searchValue} + showSubInDragOverlay={false} + showDropInPositionLine={false} + showPositionLineDot + positionLineDotDiameter={4} + positionLineHeight={1} + itemHeight={25} + positionLineIndent={(path, dropInAsSub) => { + const indent = 2 + (path.length - 1) * 30; + if (dropInAsSub) { + return indent + 12; + } + return indent; + }} + renderItemContent={(params) => { + const { node, onToggleFold, onDelete: onDeleteTreeItem, ...otherParams } = params; + const resComp = node.data; + if (!resComp) { + return null; + } + const id = resComp.id; + const isFolder = resComp.isFolder; + return ( + onCopy(isFolder, id)} + onSelect={() => onSelect(isFolder, id, resComp)} + selectedID={selectedID} + setSelectedID={setSelectedID} + selectedType={selectedType} + setSelectedType={setSelectedType} + onDelete={() => { + (onDelete(isFolder, id, resComp)) + }} + {...otherParams} + /> + ); + }} + /> : empty} + + ); } diff --git a/client/packages/lowcoder/src/redux/reducers/uiReducers/folderReducer.ts b/client/packages/lowcoder/src/redux/reducers/uiReducers/folderReducer.ts index e4ca19920..4326cb2ec 100644 --- a/client/packages/lowcoder/src/redux/reducers/uiReducers/folderReducer.ts +++ b/client/packages/lowcoder/src/redux/reducers/uiReducers/folderReducer.ts @@ -110,7 +110,7 @@ export const folderReducer = createReducer(initialState, { action.payload.parentFolderId ?? "" ]?.map((e) => { if (e.folder && e.folderId === action.payload.folderId) { - return { ...action.payload, name: action.payload.name }; + return { ...e, name: action.payload.name}; } return e; }); From 4871649494ac76631d9e682e86ec5feea0e638ae Mon Sep 17 00:00:00 2001 From: Imiss-U1025 Date: Sat, 23 Nov 2024 08:51:21 -0500 Subject: [PATCH 22/28] Fixed an issue miss loading-indicator. --- client/packages/lowcoder/index.html | 2 ++ client/packages/lowcoder/src/comps/comps/rootComp.tsx | 3 ++- client/packages/lowcoder/src/index.ts | 4 ++-- .../lowcoder/src/pages/ApplicationV2/index.tsx | 3 ++- client/packages/lowcoder/src/pages/userAuth/index.tsx | 3 ++- client/packages/lowcoder/src/util/hideLoading.tsx | 10 ++++++++++ 6 files changed, 20 insertions(+), 5 deletions(-) create mode 100644 client/packages/lowcoder/src/util/hideLoading.tsx diff --git a/client/packages/lowcoder/index.html b/client/packages/lowcoder/index.html index f3019a0cd..b9f940e01 100644 --- a/client/packages/lowcoder/index.html +++ b/client/packages/lowcoder/index.html @@ -28,6 +28,8 @@ display: flex; pointer-events: none; flex-direction: column; + top: 0; + z-index: 10000; } #loading svg { animation: breath 1s linear infinite; diff --git a/client/packages/lowcoder/src/comps/comps/rootComp.tsx b/client/packages/lowcoder/src/comps/comps/rootComp.tsx index 5fede0b07..83fe577c9 100644 --- a/client/packages/lowcoder/src/comps/comps/rootComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/rootComp.tsx @@ -34,7 +34,7 @@ import { ExternalEditorContext } from "util/context/ExternalEditorContext"; import { useUserViewMode } from "util/hooks"; import React from "react"; import { isEqual } from "lodash"; - +import {LoadingBarHideTrigger} from "@lowcoder-ee/util/hideLoading"; const EditorView = lazy( () => import("pages/editor/editorView"), ); @@ -138,6 +138,7 @@ const RootView = React.memo((props: RootViewProps) => {
{comp.children.queries.children[key].getView()}
))} + diff --git a/client/packages/lowcoder/src/index.ts b/client/packages/lowcoder/src/index.ts index 086d19d0e..2072fc849 100644 --- a/client/packages/lowcoder/src/index.ts +++ b/client/packages/lowcoder/src/index.ts @@ -24,7 +24,7 @@ if (!window.ResizeObserver) { window.ResizeObserver = ResizeObserver; } -function hideLoading() { +export function hideLoading() { // hide loading const node = document.getElementById("loading"); if (node) { @@ -42,7 +42,7 @@ debug(`REACT_APP_LOG_LEVEL:, ${REACT_APP_LOG_LEVEL}`); try { bootstrap(); - hideLoading(); + // hideLoading(); } catch (e) { log.error(e); } diff --git a/client/packages/lowcoder/src/pages/ApplicationV2/index.tsx b/client/packages/lowcoder/src/pages/ApplicationV2/index.tsx index c6fd5f91f..fc2f7536a 100644 --- a/client/packages/lowcoder/src/pages/ApplicationV2/index.tsx +++ b/client/packages/lowcoder/src/pages/ApplicationV2/index.tsx @@ -73,7 +73,7 @@ import AppEditor from "../editor/AppEditor"; import { fetchDeploymentIdAction } from "@lowcoder-ee/redux/reduxActions/configActions"; import { getDeploymentId } from "@lowcoder-ee/redux/selectors/configSelectors"; import { SimpleSubscriptionContextProvider } from '@lowcoder-ee/util/context/SimpleSubscriptionContext'; - +import {LoadingBarHideTrigger} from "@lowcoder-ee/util/hideLoading"; const TabLabel = styled.div` font-weight: 500; `; @@ -222,6 +222,7 @@ export default function ApplicationHome() { return ( + (); @@ -50,6 +50,7 @@ export default function UserAuth() { fetchUserAfterAuthSuccess, }} > + diff --git a/client/packages/lowcoder/src/util/hideLoading.tsx b/client/packages/lowcoder/src/util/hideLoading.tsx new file mode 100644 index 000000000..f4c12c345 --- /dev/null +++ b/client/packages/lowcoder/src/util/hideLoading.tsx @@ -0,0 +1,10 @@ +import {useEffect} from "react"; +import {hideLoading} from "@lowcoder-ee/index"; + +export const LoadingBarHideTrigger = function(props: any) { + useEffect(() => { + setTimeout(() => hideLoading(), 300); + }, []); + + return <> +}; \ No newline at end of file From 9e5a05f2dfa1cfbed77915e61bfdc356e3ed3fc3 Mon Sep 17 00:00:00 2001 From: FalkWolsky Date: Sat, 23 Nov 2024 15:51:16 +0100 Subject: [PATCH 23/28] Excluding local definition for EE --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 8758dff24..1dcb36aaa 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ application-dev-localhost.yaml server/api-service/lowcoder-server/src/main/resources/application-local-dev.yaml translations/locales/node_modules/ .vscode/settings.json +server/api-service/lowcoder-server/src/main/resources/application-local-dev-ee.yaml From 297ae81346109c5e6b4a0cdada410d628df22cb5 Mon Sep 17 00:00:00 2001 From: Imiss-U1025 Date: Sat, 23 Nov 2024 16:24:44 -0500 Subject: [PATCH 24/28] Fixed folder or content title overflow in module panel and applied it on bottomContent. --- .../DraggableTree/DroppableMenuItem.tsx | 2 +- .../src/pages/editor/bottom/BottomSidebar.tsx | 2 +- .../src/pages/editor/right/ModulePanel.tsx | 15 ++++++++++----- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/client/packages/lowcoder/src/components/DraggableTree/DroppableMenuItem.tsx b/client/packages/lowcoder/src/components/DraggableTree/DroppableMenuItem.tsx index 3d49e438a..7c9eac729 100644 --- a/client/packages/lowcoder/src/components/DraggableTree/DroppableMenuItem.tsx +++ b/client/packages/lowcoder/src/components/DraggableTree/DroppableMenuItem.tsx @@ -103,7 +103,7 @@ export default function DraggableMenuItem(props: IDraggableMenuItemProps) { > -
+
{renderContent?.({ node: item, isOver, diff --git a/client/packages/lowcoder/src/pages/editor/bottom/BottomSidebar.tsx b/client/packages/lowcoder/src/pages/editor/bottom/BottomSidebar.tsx index 1e75ec141..03ff67c75 100644 --- a/client/packages/lowcoder/src/pages/editor/bottom/BottomSidebar.tsx +++ b/client/packages/lowcoder/src/pages/editor/bottom/BottomSidebar.tsx @@ -323,7 +323,7 @@ const HighlightBorder = styled.div<{ $active: boolean; $foldable: boolean; $leve max-width: 100%; flex: 1; display: flex; - padding-left: ${(props) => props.$level * 20 + (props.$foldable ? 0 : 14)}px; + padding-left: ${(props) => props.$level * 10 + (props.$foldable ? 0 : 14)}px; border-radius: 4px; border: 1px solid ${(props) => (props.$active ? BorderActiveColor : "transparent")}; align-items: center; diff --git a/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx b/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx index 3110647a4..a24b787d2 100644 --- a/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx +++ b/client/packages/lowcoder/src/pages/editor/right/ModulePanel.tsx @@ -38,6 +38,7 @@ const ItemWrapper = styled.div` } .module-container { display: flex; + width: 195px; } .module-icon { margin-right: 4px; @@ -167,6 +168,7 @@ interface ModuleItemProps { setSelectedType: (id: boolean) => void; resComp: NodeType; id: string; + $level: number; } function ModuleItem(props: ModuleItemProps) { @@ -179,7 +181,8 @@ function ModuleItem(props: ModuleItemProps) { selectedType, setSelectedType, resComp, - id + id, + $level, } = props; const dispatch = useDispatch(); const type = resComp.isFolder; @@ -243,8 +246,9 @@ function ModuleItem(props: ModuleItemProps) { >
-
- + props.$level * 20 + (props.$foldable ? 0 : 14)}px; + padding-left: ${(props) => props.$level * 10 + (props.$foldable ? 0 : 14)}px; border-radius: 4px; border: 1px solid ${(props) => (props.$active ? BorderActiveColor : "transparent")}; align-items: center; @@ -479,7 +483,8 @@ function ModuleSidebarItem(props: ModuleSidebarItemProps) { selectedType={selectedType} setSelectedType={setSelectedType} resComp = {resComp} - id = {id} + id={id} + $level={level} />} {!readOnly && !isOverlay && ( onDelete()}> From 895e184975af64c40d574bfeec4c03bb52da39cf Mon Sep 17 00:00:00 2001 From: Thomasr Date: Tue, 26 Nov 2024 09:33:11 -0500 Subject: [PATCH 25/28] Fixed enterprise login issue for newcomers --- .../domain/organization/service/OrganizationServiceImpl.java | 3 --- .../runner/migrations/job/MigrateAuthConfigJobImpl.java | 3 ++- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/organization/service/OrganizationServiceImpl.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/organization/service/OrganizationServiceImpl.java index 9a2bb24cc..a1358b39f 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/organization/service/OrganizationServiceImpl.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/organization/service/OrganizationServiceImpl.java @@ -91,9 +91,6 @@ public Mono createDefault(User user, boolean isSuperAdmin) { if (Boolean.TRUE.equals(join)) { return Mono.empty(); } - OrganizationDomain organizationDomain = new OrganizationDomain(); - organizationDomain.setConfigs(List.of(DEFAULT_AUTH_CONFIG)); - organization.setOrganizationDomain(organizationDomain); return create(organization, user.getId(), isSuperAdmin); }); }); diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/runner/migrations/job/MigrateAuthConfigJobImpl.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/runner/migrations/job/MigrateAuthConfigJobImpl.java index d86615959..a89eb4480 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/runner/migrations/job/MigrateAuthConfigJobImpl.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/runner/migrations/job/MigrateAuthConfigJobImpl.java @@ -8,6 +8,7 @@ import org.lowcoder.sdk.auth.AbstractAuthConfig; import org.lowcoder.sdk.config.AuthProperties; import org.lowcoder.sdk.config.CommonConfig; +import org.lowcoder.sdk.constants.AuthSourceConstants; import org.lowcoder.sdk.constants.WorkspaceMode; import org.lowcoder.sdk.util.IDUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -57,6 +58,6 @@ protected void setAuthConfigs2OrganizationDomain(Organization organization, List organization.setOrganizationDomain(domain); } authConfigs.forEach(abstractAuthConfig -> abstractAuthConfig.setId(IDUtils.generate())); - domain.setConfigs(authConfigs); + domain.setConfigs(authConfigs.stream().filter(authConfig -> !authConfig.getSource().equals(AuthSourceConstants.EMAIL)).toList()); } } From 837fa891c9ab71d3b003b46f8770c2695320ee18 Mon Sep 17 00:00:00 2001 From: Thomasr Date: Tue, 26 Nov 2024 10:53:27 -0500 Subject: [PATCH 26/28] change default page num to 1 --- .../org/lowcoder/api/datasource/DatasourceController.java | 6 +++--- .../org/lowcoder/api/datasource/DatasourceEndpoints.java | 6 +++--- .../java/org/lowcoder/api/query/LibraryQueryController.java | 2 +- .../java/org/lowcoder/api/query/LibraryQueryEndpoints.java | 2 +- .../lowcoder/api/query/LibraryQueryRecordController.java | 2 +- .../org/lowcoder/api/query/LibraryQueryRecordEndpoints.java | 2 +- .../org/lowcoder/api/usermanagement/GroupController.java | 2 +- .../org/lowcoder/api/usermanagement/GroupEndpoints.java | 2 +- .../lowcoder/api/usermanagement/OrganizationController.java | 2 +- .../lowcoder/api/usermanagement/OrganizationEndpoints.java | 2 +- 10 files changed, 14 insertions(+), 14 deletions(-) diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/datasource/DatasourceController.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/datasource/DatasourceController.java index 4d0071639..05476fbd7 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/datasource/DatasourceController.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/datasource/DatasourceController.java @@ -119,7 +119,7 @@ public Mono> getStructure(@PathVariable String */ @Override public Mono> listJsDatasourcePlugins(@RequestParam("appId") String applicationId, @RequestParam(required = false) String name, @RequestParam(required = false) String type, - @RequestParam(required = false, defaultValue = "0") int pageNum, + @RequestParam(required = false, defaultValue = "1s") int pageNum, @RequestParam(required = false, defaultValue = "0") int pageSize) { String objectId = gidService.convertApplicationIdToObjectId(applicationId); return fluxToPageResponseView(pageNum, pageSize, datasourceApiService.listJsDatasourcePlugins(objectId, name, type)); @@ -142,7 +142,7 @@ public Mono>> getPluginDynamicConfig( @SneakyThrows @Override public Mono> listOrgDataSources(@RequestParam(name = "orgId") String orgId, @RequestParam(required = false) String name, @RequestParam(required = false) String type, - @RequestParam(required = false, defaultValue = "0") int pageNum, + @RequestParam(required = false, defaultValue = "1") int pageNum, @RequestParam(required = false, defaultValue = "0") int pageSize) { if (StringUtils.isBlank(orgId)) { return ofError(BizError.INVALID_PARAMETER, "ORG_ID_EMPTY"); @@ -153,7 +153,7 @@ public Mono> listOrgDataSources(@RequestParam(name = "orgId" @Override public Mono> listAppDataSources(@RequestParam(name = "appId") String applicationId, @RequestParam(required = false) String name, @RequestParam(required = false) String type, - @RequestParam(required = false, defaultValue = "0") int pageNum, + @RequestParam(required = false, defaultValue = "1") int pageNum, @RequestParam(required = false, defaultValue = "0") int pageSize) { if (StringUtils.isBlank(applicationId)) { return ofError(BizError.INVALID_PARAMETER, "INVALID_APP_ID"); diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/datasource/DatasourceEndpoints.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/datasource/DatasourceEndpoints.java index d3608533d..775d70229 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/datasource/DatasourceEndpoints.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/datasource/DatasourceEndpoints.java @@ -101,7 +101,7 @@ public Mono> getStructure(@PathVariable String ) @GetMapping("/jsDatasourcePlugins") public Mono> listJsDatasourcePlugins(@RequestParam("appId") String applicationId, @RequestParam(required = false) String name, @RequestParam(required = false) String type, - @RequestParam(required = false, defaultValue = "0") int pageNum, + @RequestParam(required = false, defaultValue = "1") int pageNum, @RequestParam(required = false, defaultValue = "0") int pageSize); /** @@ -127,7 +127,7 @@ public Mono>> getPluginDynamicConfig( @JsonView(JsonViews.Public.class) @GetMapping("/listByOrg") public Mono> listOrgDataSources(@RequestParam(name = "orgId") String orgId, @RequestParam String name, @RequestParam String type, - @RequestParam(required = false, defaultValue = "0") int pageNum, + @RequestParam(required = false, defaultValue = "1") int pageNum, @RequestParam(required = false, defaultValue = "0") int pageSize); @Operation( @@ -140,7 +140,7 @@ public Mono> listOrgDataSources(@RequestParam(name = "orgId" @JsonView(JsonViews.Public.class) @GetMapping("/listByApp") public Mono> listAppDataSources(@RequestParam(name = "appId") String applicationId, @RequestParam String name, @RequestParam String type, - @RequestParam(required = false, defaultValue = "0") int pageNum, + @RequestParam(required = false, defaultValue = "1") int pageNum, @RequestParam(required = false, defaultValue = "0") int pageSize); @Operation( diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/query/LibraryQueryController.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/query/LibraryQueryController.java index be0e7de68..a7a5a320d 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/query/LibraryQueryController.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/query/LibraryQueryController.java @@ -46,7 +46,7 @@ public Mono>> dropDownList(@Request @Override public Mono> list(@RequestParam(required = false, defaultValue = "") String name, - @RequestParam(required = false, defaultValue = "0") int pageNum, + @RequestParam(required = false, defaultValue = "1") int pageNum, @RequestParam(required = false, defaultValue = "100") int pageSize) { var flux = libraryQueryApiService.listLibraryQueries(name) .flatMapMany(Flux::fromIterable); diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/query/LibraryQueryEndpoints.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/query/LibraryQueryEndpoints.java index c4acd3749..bf4b8f161 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/query/LibraryQueryEndpoints.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/query/LibraryQueryEndpoints.java @@ -40,7 +40,7 @@ public interface LibraryQueryEndpoints ) @GetMapping("/listByOrg") public Mono> list(@RequestParam(required = false, defaultValue = "") String name, - @RequestParam(required = false, defaultValue = "0") int pageNum, + @RequestParam(required = false, defaultValue = "1") int pageNum, @RequestParam(required = false, defaultValue = "100") int pageSize); @Operation( diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/query/LibraryQueryRecordController.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/query/LibraryQueryRecordController.java index 31a1b8b4d..9db6a9ea2 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/query/LibraryQueryRecordController.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/query/LibraryQueryRecordController.java @@ -30,7 +30,7 @@ public Mono delete(@PathVariable String libraryQueryRecordId) { @Override public Mono> getByLibraryQueryId(@RequestParam(name = "libraryQueryId") String libraryQueryId, - @RequestParam(required = false, defaultValue = "0") int pageNum, + @RequestParam(required = false, defaultValue = "1") int pageNum, @RequestParam(required = false, defaultValue = "100") int pageSize) { return fluxToPageResponseView(pageNum, pageSize, libraryQueryRecordApiService.getByLibraryQueryId(libraryQueryId).flatMapMany(Flux::fromIterable)); } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/query/LibraryQueryRecordEndpoints.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/query/LibraryQueryRecordEndpoints.java index 7fb642fb0..9f41f380d 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/query/LibraryQueryRecordEndpoints.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/query/LibraryQueryRecordEndpoints.java @@ -41,7 +41,7 @@ public interface LibraryQueryRecordEndpoints ) @GetMapping("/listByLibraryQueryId") public Mono> getByLibraryQueryId(@RequestParam(name = "libraryQueryId") String libraryQueryId, - @RequestParam(required = false, defaultValue = "0") int pageNum, + @RequestParam(required = false, defaultValue = "1") int pageNum, @RequestParam(required = false, defaultValue = "100") int pageSize); @Operation( diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupController.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupController.java index 4e7facb99..a3ed463f7 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupController.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupController.java @@ -119,7 +119,7 @@ public Mono>> getOrgGroups(@RequestParam(r @Override public Mono> getGroupMembers(@PathVariable String groupId, - @RequestParam(required = false, defaultValue = "0") int pageNum, + @RequestParam(required = false, defaultValue = "1") int pageNum, @RequestParam(required = false, defaultValue = "100") int pageSize) { String objectId = gidService.convertGroupIdToObjectId(groupId); return groupApiService.getGroupMembers(objectId, pageNum, pageSize) diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupEndpoints.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupEndpoints.java index e2f8bfa7a..89e294628 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupEndpoints.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupEndpoints.java @@ -74,7 +74,7 @@ public Mono>> getOrgGroups(@RequestParam(r ) @GetMapping("/{groupId}/members") public Mono> getGroupMembers(@PathVariable String groupId, - @RequestParam(required = false, defaultValue = "0") int pageNum, + @RequestParam(required = false, defaultValue = "1") int pageNum, @RequestParam(required = false, defaultValue = "100") int pageSize); @Operation( diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrganizationController.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrganizationController.java index 2b2a9dd75..d43676ba5 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrganizationController.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrganizationController.java @@ -90,7 +90,7 @@ public Mono> deleteLogo(@PathVariable String orgId) { @Override public Mono> getOrgMembers(@PathVariable String orgId, - @RequestParam(required = false, defaultValue = "0") int pageNum, + @RequestParam(required = false, defaultValue = "1") int pageNum, @RequestParam(required = false, defaultValue = "1000") int pageSize) { String id = gidService.convertOrganizationIdToObjectId(orgId); return orgApiService.getOrganizationMembers(id, pageNum, pageSize) diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrganizationEndpoints.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrganizationEndpoints.java index 38332e892..8fc9d5598 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrganizationEndpoints.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrganizationEndpoints.java @@ -95,7 +95,7 @@ public Mono> uploadLogo(@PathVariable String orgId, ) @GetMapping("/{orgId}/members") public Mono> getOrgMembers(@PathVariable String orgId, - @RequestParam(required = false, defaultValue = "0") int pageNum, + @RequestParam(required = false, defaultValue = "1") int pageNum, @RequestParam(required = false, defaultValue = "1000") int pageSize); @Operation( From 91215b2780b7411316398670c3b3317bf6ac0b79 Mon Sep 17 00:00:00 2001 From: Thomasr Date: Tue, 26 Nov 2024 13:22:30 -0500 Subject: [PATCH 27/28] fix default value --- .../java/org/lowcoder/api/datasource/DatasourceController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/datasource/DatasourceController.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/datasource/DatasourceController.java index 05476fbd7..695245c41 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/datasource/DatasourceController.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/datasource/DatasourceController.java @@ -119,7 +119,7 @@ public Mono> getStructure(@PathVariable String */ @Override public Mono> listJsDatasourcePlugins(@RequestParam("appId") String applicationId, @RequestParam(required = false) String name, @RequestParam(required = false) String type, - @RequestParam(required = false, defaultValue = "1s") int pageNum, + @RequestParam(required = false, defaultValue = "1") int pageNum, @RequestParam(required = false, defaultValue = "0") int pageSize) { String objectId = gidService.convertApplicationIdToObjectId(applicationId); return fluxToPageResponseView(pageNum, pageSize, datasourceApiService.listJsDatasourcePlugins(objectId, name, type)); From 18be56b76d51502bf6d6158875879c207950dd32 Mon Sep 17 00:00:00 2001 From: Thomasr Date: Wed, 27 Nov 2024 02:13:34 -0500 Subject: [PATCH 28/28] #1322: Fix object comparing using Objects.equals() --- .../authentication/service/AuthenticationApiServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiServiceImpl.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiServiceImpl.java index b4e3e2c4d..df1c9e1d1 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiServiceImpl.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiServiceImpl.java @@ -228,7 +228,7 @@ protected Connection getAuthConnection(AuthUser authUser, User user) { return user.getConnections() .stream() .filter(connection -> authUser.getSource().equals(connection.getSource()) - && connection.getRawId().equals(authUser.getUid())) + && Objects.equals(connection.getRawId(), authUser.getUid())) .findFirst() .get(); }