Skip to content

Commit

Permalink
Merge pull request #259 from dRAGon-Okinawa/staging
Browse files Browse the repository at this point in the history
UI for Silo Management (#258)
  • Loading branch information
isontheline authored Sep 3, 2024
2 parents aa8c7fd + 6b9a02f commit 106b7db
Show file tree
Hide file tree
Showing 55 changed files with 1,251 additions and 599 deletions.
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
gradle
.gradle
bin
.vscode
.DS_Store
*.class
.pnpm-store
.env.local
.env.local
.vscode/settings.json
21 changes: 21 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "java",
"name": "Run Current File",
"request": "launch",
"mainClass": "${file}"
},
{
"type": "java",
"name": "Launch dRAGon Application",
"request": "launch",
"mainClass": "ai.dragon.DragonApplication",
"projectName": "backend"
}
]
}
67 changes: 67 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Start Backend",
"type": "shell",
"command": "gradle bootRun -x :frontend:pnpmBuild -x :backend:copyWebApp",
"options": {
"cwd": "${workspaceFolder}"
},
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "new",
"group": "groupA"
},
"problemMatcher": []
},
{
"label": "Continuous Backend Build",
"type": "shell",
"command": "gradle backend:bootJar -continuous -xtest -x :frontend:pnpmBuild -x :backend:copyWebApp",
"options": {
"cwd": "${workspaceFolder}"
},
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "new",
"group": "groupA"
},
"problemMatcher": []
},
{
"label": "Start Frontend",
"type": "shell",
"command": "pnpm dev",
"options": {
"cwd": "${workspaceFolder}/frontend"
},
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "new",
"group": "groupA"
},
"problemMatcher": []
},
{
"label": "Launch dRAGon Development Mode",
"dependsOn": [
"Start Backend",
"Continuous Backend Build",
"Start Frontend"
],
"dependsOrder": "parallel",
"group": {
"kind": "none",
"isDefault": true
},
"problemMatcher": []
}
]
}
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ dRAGon is a multi-modal RAG engine which can search over multiple kind of docume

![dRAGon](https://raw.githubusercontent.com/dragon-okinawa/dragon/main/static/img/dragon_okinawa.jpg)

## Screenshots
![dRAGon - Infrastructure - Silos](https://raw.githubusercontent.com/dragon-okinawa/dragon/main/static/tour/dragon-infrastructure-silos.jpg)

## dRAGon is all of us
dRAGon is an open-source project that thrives on community participation. We invite you to fork, extend, and contribute to its development.

Expand Down
2 changes: 1 addition & 1 deletion backend/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ plugins {
id 'jacoco'
id 'checkstyle'
id 'application'
id 'org.springframework.boot' version '3.3.2'
id 'org.springframework.boot' version '3.3.3'
id 'io.spring.dependency-management' version '1.1.6'
id 'org.springdoc.openapi-gradle-plugin' version '1.9.0'
}
Expand Down
19 changes: 19 additions & 0 deletions backend/src/main/java/ai/dragon/config/WebConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package ai.dragon.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.lang.NonNull;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(@NonNull CorsRegistry registry) {
// Allow CORS requests :
registry
.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS")
.allowedHeaders("*");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import java.lang.reflect.Constructor;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.UUID;
import java.util.function.Function;

import org.dizitart.no2.collection.FindOptions;
import org.dizitart.no2.exceptions.UniqueConstraintException;
Expand All @@ -18,6 +18,7 @@

import ai.dragon.entity.AbstractEntity;
import ai.dragon.repository.AbstractRepository;
import ai.dragon.repository.util.Pager;

abstract class AbstractCrudBackendApiController<T extends AbstractEntity> {
protected T update(String uuid, Map<String, Object> fields, AbstractRepository<T> repository) {
Expand Down Expand Up @@ -46,6 +47,30 @@ protected List<T> list(AbstractRepository<T> repository) {
return repository.find().toList();
}

protected long count(AbstractRepository<T> repository) {
return repository.find().size();
}

protected long count(AbstractRepository<T> repository, Filter filter) {
return repository.findWithFilter(filter).size();
}

protected Pager<T> page(AbstractRepository<T> repository, int page, int size) {
return this.page(repository, Filter.ALL, page, size);
}

protected Pager<T> page(AbstractRepository<T> repository, Filter filter, int page, int size) {
Cursor<T> cursorFull = repository.findWithFilter(filter);
Cursor<T> cursorLimit = repository.findWithFilter(filter, FindOptions.skipBy((page - 1) * size).limit(size));
return Pager
.<T>builder()
.page(page)
.size(size)
.total(cursorFull.size())
.data(cursorLimit.toList())
.build();
}

protected T create(AbstractRepository<T> repository) throws Exception {
return create(repository, null);
}
Expand Down Expand Up @@ -84,4 +109,10 @@ protected void delete(String uuid, AbstractRepository<T> repository) {
}
repository.delete(uuid);
}

protected void deleteMultiple(List<String> uuids, AbstractRepository<T> repository) {
for (String uuid : uuids) {
delete(uuid, repository);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,33 @@
package ai.dragon.controller.api.backend.repository;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;

import org.dizitart.no2.filters.Filter;
import org.dizitart.no2.filters.FluentFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.fasterxml.jackson.databind.JsonMappingException;

import ai.dragon.dto.api.DataTableApiResponse;
import ai.dragon.dto.api.GenericApiResponse;
import ai.dragon.dto.api.SuccessApiResponse;
import ai.dragon.dto.api.backend.UUIDsBatchRequest;
import ai.dragon.entity.SiloEntity;
import ai.dragon.repository.SiloRepository;
import ai.dragon.repository.util.Pager;
import ai.dragon.util.UUIDUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
Expand All @@ -33,44 +43,90 @@ public class SiloBackendApiController extends AbstractCrudBackendApiController<S

@GetMapping("/")
@ApiResponse(responseCode = "200", description = "List has been successfully retrieved.")
@Operation(summary = "List all Silos", description = "Returns all Silo entities stored in the database.")
public List<SiloEntity> listSilos() {
return super.list(siloRepository);
@Operation(summary = "Search Silos", description = "Search Silo entities stored in the database.")
public GenericApiResponse searchSilos(@RequestParam(name = "current", defaultValue = "1") int page,
@RequestParam(name = "size", defaultValue = "10") int size,
@RequestParam(name = "uuid", required = false) String uuid,
@RequestParam(name = "name", required = false) String name,
@RequestParam(name = "vectorStore", required = false) String vectorStore) {
Filter filter = FluentFilter
.where("uuid").regex(String.format("^%s", Optional.ofNullable(uuid).orElse("")))
.and(FluentFilter.where("name").regex(Optional.ofNullable(name).orElse(""))
.and(FluentFilter.where("vectorStore").regex(Optional.ofNullable(vectorStore).orElse(""))));
Pager<SiloEntity> pager = super.page(siloRepository, filter, page, size);
return DataTableApiResponse.fromPager(pager);
}

@PostMapping("/")
@ApiResponse(responseCode = "200", description = "Silo has been successfully created.")
@ApiResponse(responseCode = "409", description = "Constraint violation.", content = @Content)
@Operation(summary = "Create a new Silo", description = "Creates one Silo entity in the database.")
public SiloEntity createSilo() throws Exception {
return super.create(siloRepository);
public GenericApiResponse createSilo() throws Exception {
return SuccessApiResponse
.builder()
.data(super.create(siloRepository))
.build();
}

@GetMapping("/{uuid:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}}")
@ApiResponse(responseCode = "200", description = "Silo has been successfully retrieved.")
@ApiResponse(responseCode = "404", description = "Silo not found.", content = @Content)
@Operation(summary = "Retrieve one Silo", description = "Returns one Silo entity from its UUID stored in the database.")
public SiloEntity getSilo(
@PathVariable("uuid") @Parameter(description = "Identifier of the Silo") String uuid) {
return super.get(uuid, siloRepository);
public GenericApiResponse getSilo(
@PathVariable("uuid") @Parameter(description = "Identifier of the Silo", required = true) String uuid) {
return SuccessApiResponse
.builder()
.data(super.get(uuid, siloRepository))
.build();
}

@PatchMapping("/{uuid:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}}")
@ApiResponse(responseCode = "200", description = "Silo has been successfully updated.")
@ApiResponse(responseCode = "404", description = "Silo not found.", content = @Content)
@Operation(summary = "Update a Silo", description = "Updates one Silo entity in the database.")
public SiloEntity updateSilo(
public GenericApiResponse updateSilo(
@PathVariable("uuid") @Parameter(description = "Identifier of the Silo", required = true) String uuid,
@RequestBody Map<String, Object> fields) throws JsonMappingException {
return super.update(uuid, fields, siloRepository);
return SuccessApiResponse
.builder()
.data(super.update(uuid, fields, siloRepository))
.build();
}

@PutMapping("/{uuid:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}}")
@ApiResponse(responseCode = "200", description = "Silo has been successfully updated.")
@ApiResponse(responseCode = "404", description = "Silo not found.", content = @Content)
@Operation(summary = "Upsert a Silo", description = "Upsert one Silo entity in the database.")
public GenericApiResponse upsertSilo(
@PathVariable("uuid") @Parameter(description = "Identifier of the Silo", required = false) String uuid,
@RequestBody Map<String, Object> fields) throws Exception {
if (uuid == null || UUIDUtil.zeroUUIDString().equals(uuid)) {
fields.remove("uuid");
uuid = super.create(siloRepository).getUuid().toString();
}
return SuccessApiResponse
.builder()
.data(super.update(uuid, fields, siloRepository))
.build();
}

@DeleteMapping("/{uuid:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}}")
@ApiResponse(responseCode = "200", description = "Silo has been successfully deleted.")
@ApiResponse(responseCode = "404", description = "Silo not found.", content = @Content)
@Operation(summary = "Delete a Silo", description = "Deletes one Silo entity from its UUID stored in the database.")
public void deleteSilo(@PathVariable("uuid") @Parameter(description = "Identifier of the Silo") UUID uuid)
public GenericApiResponse deleteSilo(
@PathVariable("uuid") @Parameter(description = "Identifier of the Silo") UUID uuid)
throws Exception {
super.delete(uuid, siloRepository);
return SuccessApiResponse.builder().build();
}

@DeleteMapping("/deleteMultiple")
@ApiResponse(responseCode = "200", description = "Silo has been successfully deleted.")
@ApiResponse(responseCode = "404", description = "Silo not found.", content = @Content)
@Operation(summary = "Delete multiple Silos", description = "Deletes one or more Silo entity from their UUID stored in the database.")
public GenericApiResponse deleteMultipleSilos(@RequestBody UUIDsBatchRequest request) throws Exception {
super.deleteMultiple(request.getUuids(), siloRepository);
return SuccessApiResponse.builder().build();
}
}
24 changes: 24 additions & 0 deletions backend/src/main/java/ai/dragon/dto/api/DataTableApiResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package ai.dragon.dto.api;

import ai.dragon.dto.api.backend.PagerTableApiData;
import ai.dragon.repository.util.Pager;
import lombok.Builder;
import lombok.Data;

@Builder
@Data
public class DataTableApiResponse implements GenericApiResponse {
@Builder.Default
private TableApiData data = null;

@Builder.Default
private String code = "0000";

@Builder.Default
private String msg = "OK";

public static DataTableApiResponse fromPager(Pager<?> pager) {
TableApiData data = new PagerTableApiData(pager);
return DataTableApiResponse.builder().data(data).build();
}
}
5 changes: 0 additions & 5 deletions backend/src/main/java/ai/dragon/dto/api/GenericApiData.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package ai.dragon.dto.api;

public interface GenericApiResponse {
public GenericApiData getData();
public Object getData();
public String getCode();
public String getMsg();
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
@Data
public class SuccessApiResponse implements GenericApiResponse {
@Builder.Default
private GenericApiData data = null;
private Object data = null;

@Builder.Default
private String code = "0000";
Expand Down
Loading

0 comments on commit 106b7db

Please sign in to comment.