diff --git a/.semgrepignore b/.semgrepignore index 1c19645e3..5b374e053 100644 --- a/.semgrepignore +++ b/.semgrepignore @@ -4,6 +4,7 @@ vuu/src/main/resources/www/ws-example.html vuu/src/main/scala/org/finos/vuu/provider/simulation/SimulatedBigInstrumentsProvider.scala vuu-ui/packages/vuu-data/src/array-data-source/group-utils.ts vuu-ui/packages/vuu-datagrid-extras/src/column-expression-input/column-language-parser/walkExpressionTree.ts +vuu-ui/packages/vuu-layout/src/layout-persistence/RemoteLayoutPersistenceManager.ts vuu-ui/packages/vuu-popups/src/menu/useContextMenu.tsx vuu-ui/packages/vuu-table-extras/src/cell-edit-validators/PatternValidator.ts vuu-ui/packages/vuu-ui-controls/src/list/Highlighter.tsx diff --git a/layout-server/src/main/java/org/finos/vuu/layoutserver/CorsConfig.java b/layout-server/src/main/java/org/finos/vuu/layoutserver/CorsConfig.java new file mode 100644 index 000000000..7950487b4 --- /dev/null +++ b/layout-server/src/main/java/org/finos/vuu/layoutserver/CorsConfig.java @@ -0,0 +1,15 @@ +package org.finos.vuu.layoutserver; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class CorsConfig implements WebMvcConfigurer { + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedOrigins("http://127.0.0.1:5173") + .allowedMethods("GET", "POST", "PUT", "DELETE"); + } +} diff --git a/layout-server/src/main/java/org/finos/vuu/layoutserver/config/MappingConfig.java b/layout-server/src/main/java/org/finos/vuu/layoutserver/config/MappingConfig.java index d5cb02432..546d38ca7 100644 --- a/layout-server/src/main/java/org/finos/vuu/layoutserver/config/MappingConfig.java +++ b/layout-server/src/main/java/org/finos/vuu/layoutserver/config/MappingConfig.java @@ -1,7 +1,7 @@ package org.finos.vuu.layoutserver.config; import lombok.RequiredArgsConstructor; -import org.finos.vuu.layoutserver.dto.request.LayoutRequestDTO; +import org.finos.vuu.layoutserver.dto.request.LayoutRequestDto; import org.finos.vuu.layoutserver.model.Layout; import org.modelmapper.ModelMapper; import org.springframework.context.annotation.Bean; @@ -15,9 +15,9 @@ public class MappingConfig { public ModelMapper modelMapper() { ModelMapper mapper = new ModelMapper(); - mapper.typeMap(LayoutRequestDTO.class, Layout.class) + mapper.typeMap(LayoutRequestDto.class, Layout.class) .addMappings(m -> m.skip(Layout::setId)); return mapper; } -} \ No newline at end of file +} diff --git a/layout-server/src/main/java/org/finos/vuu/layoutserver/controller/ApplicationLayoutController.java b/layout-server/src/main/java/org/finos/vuu/layoutserver/controller/ApplicationLayoutController.java new file mode 100644 index 000000000..cec6ed70a --- /dev/null +++ b/layout-server/src/main/java/org/finos/vuu/layoutserver/controller/ApplicationLayoutController.java @@ -0,0 +1,55 @@ +package org.finos.vuu.layoutserver.controller; + +import com.fasterxml.jackson.databind.JsonNode; +import lombok.RequiredArgsConstructor; +import org.finos.vuu.layoutserver.dto.response.ApplicationLayoutDto; +import org.finos.vuu.layoutserver.service.ApplicationLayoutService; +import org.modelmapper.ModelMapper; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; + +@RequiredArgsConstructor +@RestController +@RequestMapping("/application-layouts") +public class ApplicationLayoutController { + + private final ApplicationLayoutService service; + private final ModelMapper mapper; + + /** + * Gets the persisted application layout for the requesting user. If the requesting user does not have an + * application layout persisted, a default layout with a null username is returned instead. No more than one + * application layout can be persisted for a given user. + * + * @return the application layout + */ + @ResponseStatus(HttpStatus.OK) + @GetMapping + public ApplicationLayoutDto getApplicationLayout(@RequestHeader("username") String username) { + return mapper.map(service.getApplicationLayout(username), ApplicationLayoutDto.class); + } + + /** + * Creates or updates the unique application layout for the requesting user. + * + * @param layoutDefinition JSON representation of the application layout to be created + * @param username the user making the request + */ + @ResponseStatus(HttpStatus.CREATED) + @PutMapping + public void persistApplicationLayout(@RequestHeader("username") String username, @RequestBody JsonNode layoutDefinition) { + service.persistApplicationLayout(username, layoutDefinition); + } + + /** + * Deletes the application layout for the requesting user. A 404 will be returned if there is no existing + * application layout. + * + * @param username the user making the request + */ + @ResponseStatus(HttpStatus.NO_CONTENT) + @DeleteMapping + public void deleteApplicationLayout(@RequestHeader("username") String username) { + service.deleteApplicationLayout(username); + } +} diff --git a/layout-server/src/main/java/org/finos/vuu/layoutserver/controller/GlobalExceptionHandler.java b/layout-server/src/main/java/org/finos/vuu/layoutserver/controller/GlobalExceptionHandler.java deleted file mode 100644 index f543ba473..000000000 --- a/layout-server/src/main/java/org/finos/vuu/layoutserver/controller/GlobalExceptionHandler.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.finos.vuu.layoutserver.controller; - -import java.util.List; -import java.util.NoSuchElementException; -import java.util.stream.Collectors; -import org.springframework.http.ResponseEntity; -import org.springframework.http.converter.HttpMessageNotReadableException; -import org.springframework.web.bind.MethodArgumentNotValidException; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; - -@ControllerAdvice -public class GlobalExceptionHandler { - - @ExceptionHandler(NoSuchElementException.class) - public ResponseEntity handleNotFound(NoSuchElementException ex) { - return new ResponseEntity<>(ex.getMessage(), org.springframework.http.HttpStatus.NOT_FOUND); - } - - @ExceptionHandler(MethodArgumentNotValidException.class) - public ResponseEntity handleMethodArgumentNotValid(MethodArgumentNotValidException ex) { - List errors = ex.getFieldErrors().stream() - .map(fieldError -> fieldError.getField() + ": " + fieldError.getDefaultMessage()) - .collect(Collectors.toList()); - - return new ResponseEntity<>(errors.toString(), - org.springframework.http.HttpStatus.BAD_REQUEST); - } - - @ExceptionHandler(MethodArgumentTypeMismatchException.class) - public ResponseEntity handleMethodArgumentTypeMismatchException( - MethodArgumentTypeMismatchException ex) { - return new ResponseEntity<>(ex.getMessage(), - org.springframework.http.HttpStatus.BAD_REQUEST); - } - - @ExceptionHandler(HttpMessageNotReadableException.class) - public ResponseEntity handleHttpMessageNotReadableException( - HttpMessageNotReadableException ex) { - return new ResponseEntity<>(ex.getMessage(), - org.springframework.http.HttpStatus.BAD_REQUEST); - } -} diff --git a/layout-server/src/main/java/org/finos/vuu/layoutserver/controller/LayoutController.java b/layout-server/src/main/java/org/finos/vuu/layoutserver/controller/LayoutController.java index 82c7d38ed..315f04c62 100644 --- a/layout-server/src/main/java/org/finos/vuu/layoutserver/controller/LayoutController.java +++ b/layout-server/src/main/java/org/finos/vuu/layoutserver/controller/LayoutController.java @@ -1,27 +1,20 @@ package org.finos.vuu.layoutserver.controller; -import java.util.List; -import java.util.UUID; -import javax.validation.Valid; import lombok.RequiredArgsConstructor; -import org.finos.vuu.layoutserver.dto.request.LayoutRequestDTO; -import org.finos.vuu.layoutserver.dto.response.LayoutResponseDTO; -import org.finos.vuu.layoutserver.dto.response.MetadataResponseDTO; +import org.finos.vuu.layoutserver.dto.request.LayoutRequestDto; +import org.finos.vuu.layoutserver.dto.response.LayoutResponseDto; +import org.finos.vuu.layoutserver.dto.response.MetadataResponseDto; import org.finos.vuu.layoutserver.model.Layout; import org.finos.vuu.layoutserver.service.LayoutService; import org.finos.vuu.layoutserver.service.MetadataService; import org.modelmapper.ModelMapper; import org.springframework.http.HttpStatus; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -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.ResponseStatus; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; +import java.util.UUID; @RequiredArgsConstructor @RestController @@ -41,8 +34,8 @@ public class LayoutController { */ @ResponseStatus(HttpStatus.OK) @GetMapping("/{id}") - public LayoutResponseDTO getLayout(@PathVariable UUID id) { - return mapper.map(layoutService.getLayout(id), LayoutResponseDTO.class); + public LayoutResponseDto getLayout(@PathVariable UUID id) { + return mapper.map(layoutService.getLayout(id), LayoutResponseDto.class); } /** @@ -52,12 +45,12 @@ public LayoutResponseDTO getLayout(@PathVariable UUID id) { */ @ResponseStatus(HttpStatus.OK) @GetMapping("/metadata") - public List getMetadata() { + public List getMetadata() { return metadataService.getMetadata() - .stream() - .map(metadata -> mapper.map(metadata, MetadataResponseDTO.class)) - .collect(java.util.stream.Collectors.toList()); + .stream() + .map(metadata -> mapper.map(metadata, MetadataResponseDto.class)) + .collect(java.util.stream.Collectors.toList()); } /** @@ -68,21 +61,21 @@ public List getMetadata() { */ @ResponseStatus(HttpStatus.CREATED) @PostMapping - public LayoutResponseDTO createLayout(@Valid @RequestBody LayoutRequestDTO layoutToCreate) { + public LayoutResponseDto createLayout(@RequestBody @Valid LayoutRequestDto layoutToCreate) { Layout layout = mapper.map(layoutToCreate, Layout.class); - return mapper.map(layoutService.createLayout(layout), LayoutResponseDTO.class); + return mapper.map(layoutService.createLayout(layout), LayoutResponseDto.class); } /** * Updates the specified layout * - * @param id ID of the layout to update + * @param id ID of the layout to update * @param layout the new layout */ @ResponseStatus(HttpStatus.NO_CONTENT) @PutMapping("/{id}") - public void updateLayout(@PathVariable UUID id, @Valid @RequestBody LayoutRequestDTO layout) { + public void updateLayout(@PathVariable UUID id, @RequestBody @Valid LayoutRequestDto layout) { Layout newLayout = mapper.map(layout, Layout.class); layoutService.updateLayout(id, newLayout); diff --git a/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/request/LayoutRequestDTO.java b/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/request/LayoutRequestDto.java similarity index 89% rename from layout-server/src/main/java/org/finos/vuu/layoutserver/dto/request/LayoutRequestDTO.java rename to layout-server/src/main/java/org/finos/vuu/layoutserver/dto/request/LayoutRequestDto.java index 60d50af11..6255692b1 100644 --- a/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/request/LayoutRequestDTO.java +++ b/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/request/LayoutRequestDto.java @@ -1,12 +1,13 @@ package org.finos.vuu.layoutserver.dto.request; import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; -import lombok.Data; @Data -public class LayoutRequestDTO { +public class LayoutRequestDto { /** * The definition of the layout as a string (e.g. stringified JSON structure containing @@ -18,5 +19,5 @@ public class LayoutRequestDTO { @JsonProperty(value = "metadata", required = true) @NotNull(message = "Metadata must not be null") - private MetadataRequestDTO metadata; + private MetadataRequestDto metadata; } diff --git a/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/request/MetadataRequestDTO.java b/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/request/MetadataRequestDto.java similarity index 87% rename from layout-server/src/main/java/org/finos/vuu/layoutserver/dto/request/MetadataRequestDTO.java rename to layout-server/src/main/java/org/finos/vuu/layoutserver/dto/request/MetadataRequestDto.java index 30bb62e9a..abbf99430 100644 --- a/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/request/MetadataRequestDTO.java +++ b/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/request/MetadataRequestDto.java @@ -5,7 +5,7 @@ import org.finos.vuu.layoutserver.model.BaseMetadata; @Data -public class MetadataRequestDTO { +public class MetadataRequestDto { @JsonUnwrapped BaseMetadata baseMetadata; diff --git a/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/response/ApplicationLayoutDto.java b/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/response/ApplicationLayoutDto.java new file mode 100644 index 000000000..2b34c6151 --- /dev/null +++ b/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/response/ApplicationLayoutDto.java @@ -0,0 +1,10 @@ +package org.finos.vuu.layoutserver.dto.response; + +import com.fasterxml.jackson.databind.JsonNode; +import lombok.Data; + +@Data +public class ApplicationLayoutDto { + private String username; + private JsonNode definition; +} diff --git a/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/response/ErrorResponse.java b/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/response/ErrorResponse.java new file mode 100644 index 000000000..0daf9168c --- /dev/null +++ b/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/response/ErrorResponse.java @@ -0,0 +1,24 @@ +package org.finos.vuu.layoutserver.dto.response; + +import lombok.Data; +import org.springframework.http.HttpStatus; + +import javax.servlet.http.HttpServletRequest; +import java.util.Date; +import java.util.List; + +@Data +public class ErrorResponse { + private Date timestamp = new Date(); + private int status; + private String error; + private List messages; + private String path; + + public ErrorResponse(HttpServletRequest request, List messages, HttpStatus status) { + this.status = status.value(); + this.error = status.getReasonPhrase(); + this.path = request.getRequestURI(); + this.messages = messages; + } +} diff --git a/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/response/LayoutResponseDTO.java b/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/response/LayoutResponseDto.java similarity index 79% rename from layout-server/src/main/java/org/finos/vuu/layoutserver/dto/response/LayoutResponseDTO.java rename to layout-server/src/main/java/org/finos/vuu/layoutserver/dto/response/LayoutResponseDto.java index 93d725e2a..9c689833b 100644 --- a/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/response/LayoutResponseDTO.java +++ b/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/response/LayoutResponseDto.java @@ -5,7 +5,7 @@ import java.util.UUID; @Data -public class LayoutResponseDTO { +public class LayoutResponseDto { private UUID id; @@ -15,5 +15,5 @@ public class LayoutResponseDTO { */ private String definition; - private MetadataResponseDTO metadata; + private MetadataResponseDto metadata; } diff --git a/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/response/MetadataResponseDTO.java b/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/response/MetadataResponseDto.java similarity index 69% rename from layout-server/src/main/java/org/finos/vuu/layoutserver/dto/response/MetadataResponseDTO.java rename to layout-server/src/main/java/org/finos/vuu/layoutserver/dto/response/MetadataResponseDto.java index 3aa772286..236034c1c 100644 --- a/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/response/MetadataResponseDTO.java +++ b/layout-server/src/main/java/org/finos/vuu/layoutserver/dto/response/MetadataResponseDto.java @@ -1,19 +1,20 @@ package org.finos.vuu.layoutserver.dto.response; import com.fasterxml.jackson.annotation.JsonUnwrapped; -import java.util.Date; -import java.util.UUID; import lombok.Data; import org.finos.vuu.layoutserver.model.BaseMetadata; +import java.time.LocalDate; +import java.util.UUID; + @Data -public class MetadataResponseDTO { +public class MetadataResponseDto { private UUID id; @JsonUnwrapped BaseMetadata baseMetadata; - private Date created; - private Date updated; + private LocalDate created; + private LocalDate updated; } diff --git a/layout-server/src/main/java/org/finos/vuu/layoutserver/exceptions/GlobalExceptionHandler.java b/layout-server/src/main/java/org/finos/vuu/layoutserver/exceptions/GlobalExceptionHandler.java new file mode 100644 index 000000000..e0dd4b5c8 --- /dev/null +++ b/layout-server/src/main/java/org/finos/vuu/layoutserver/exceptions/GlobalExceptionHandler.java @@ -0,0 +1,50 @@ +package org.finos.vuu.layoutserver.exceptions; + +import org.finos.vuu.layoutserver.dto.response.ErrorResponse; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; + +import javax.servlet.http.HttpServletRequest; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.stream.Collectors; + +@ControllerAdvice +public class GlobalExceptionHandler { + + @ExceptionHandler(NoSuchElementException.class) + public ResponseEntity handleNotFound(HttpServletRequest request, Exception ex) { + HttpStatus status = HttpStatus.NOT_FOUND; + return new ResponseEntity<>(new ErrorResponse(request, List.of(ex.getMessage()), status), status); + } + + @ExceptionHandler({ + HttpMessageNotReadableException.class, + MethodArgumentTypeMismatchException.class}) + public ResponseEntity handleBadRequest(HttpServletRequest request, Exception ex) { + HttpStatus status = HttpStatus.BAD_REQUEST; + return new ResponseEntity<>(new ErrorResponse(request, List.of(ex.getMessage()), status), status); + } + + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity handleMethodArgumentNotValid(HttpServletRequest request, MethodArgumentNotValidException ex) { + HttpStatus status = HttpStatus.BAD_REQUEST; + List errors = ex.getFieldErrors() + .stream() + .map(fieldError -> fieldError.getField() + ": " + fieldError.getDefaultMessage()) + .collect(Collectors.toList()); + return new ResponseEntity<>(new ErrorResponse(request, errors, status), status); + } + + @ExceptionHandler(InternalServerErrorException.class) + public ResponseEntity handleInternalServerError(HttpServletRequest request, Exception ex) { + HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR; + return new ResponseEntity<>(new ErrorResponse(request, List.of(ex.getMessage()), status), status); + + } +} diff --git a/layout-server/src/main/java/org/finos/vuu/layoutserver/exceptions/InternalServerErrorException.java b/layout-server/src/main/java/org/finos/vuu/layoutserver/exceptions/InternalServerErrorException.java new file mode 100644 index 000000000..b1164eab6 --- /dev/null +++ b/layout-server/src/main/java/org/finos/vuu/layoutserver/exceptions/InternalServerErrorException.java @@ -0,0 +1,7 @@ +package org.finos.vuu.layoutserver.exceptions; + +public class InternalServerErrorException extends RuntimeException { + public InternalServerErrorException(String message) { + super(message); + } +} diff --git a/layout-server/src/main/java/org/finos/vuu/layoutserver/model/ApplicationLayout.java b/layout-server/src/main/java/org/finos/vuu/layoutserver/model/ApplicationLayout.java new file mode 100644 index 000000000..a8cef5ad6 --- /dev/null +++ b/layout-server/src/main/java/org/finos/vuu/layoutserver/model/ApplicationLayout.java @@ -0,0 +1,25 @@ +package org.finos.vuu.layoutserver.model; + +import com.fasterxml.jackson.databind.JsonNode; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.RequiredArgsConstructor; +import org.finos.vuu.layoutserver.utils.JsonNodeConverter; + +import javax.persistence.Column; +import javax.persistence.Convert; +import javax.persistence.Entity; +import javax.persistence.Id; + +@Data +@Entity +@RequiredArgsConstructor +@AllArgsConstructor +public class ApplicationLayout { + @Id + private String username; + + @Convert(converter = JsonNodeConverter.class) + @Column(columnDefinition = "JSON") + private JsonNode definition; +} diff --git a/layout-server/src/main/java/org/finos/vuu/layoutserver/model/BaseMetadata.java b/layout-server/src/main/java/org/finos/vuu/layoutserver/model/BaseMetadata.java index 05389012b..2500eb247 100644 --- a/layout-server/src/main/java/org/finos/vuu/layoutserver/model/BaseMetadata.java +++ b/layout-server/src/main/java/org/finos/vuu/layoutserver/model/BaseMetadata.java @@ -1,8 +1,9 @@ package org.finos.vuu.layoutserver.model; +import lombok.Data; + import javax.persistence.Embeddable; import javax.persistence.Lob; -import lombok.Data; @Data @Embeddable diff --git a/layout-server/src/main/java/org/finos/vuu/layoutserver/model/Layout.java b/layout-server/src/main/java/org/finos/vuu/layoutserver/model/Layout.java index 8054799b0..2a55da5bd 100644 --- a/layout-server/src/main/java/org/finos/vuu/layoutserver/model/Layout.java +++ b/layout-server/src/main/java/org/finos/vuu/layoutserver/model/Layout.java @@ -1,14 +1,10 @@ package org.finos.vuu.layoutserver.model; -import java.util.UUID; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.OneToOne; import lombok.Data; +import javax.persistence.*; +import java.util.UUID; + @Data @Entity public class Layout { diff --git a/layout-server/src/main/java/org/finos/vuu/layoutserver/model/Metadata.java b/layout-server/src/main/java/org/finos/vuu/layoutserver/model/Metadata.java index 4929c291e..1e5abb00b 100644 --- a/layout-server/src/main/java/org/finos/vuu/layoutserver/model/Metadata.java +++ b/layout-server/src/main/java/org/finos/vuu/layoutserver/model/Metadata.java @@ -1,19 +1,16 @@ package org.finos.vuu.layoutserver.model; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + import javax.persistence.Column; -import java.util.Date; -import java.util.UUID; import javax.persistence.Embedded; import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; import javax.persistence.Id; - -import lombok.Data; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.NoArgsConstructor; +import java.time.LocalDate; +import java.util.UUID; @Data @Builder @@ -29,7 +26,7 @@ public class Metadata { @Embedded private BaseMetadata baseMetadata; - private final Date created = new Date(); + private final LocalDate created = LocalDate.now(); - private Date updated; + private LocalDate updated; } diff --git a/layout-server/src/main/java/org/finos/vuu/layoutserver/repository/ApplicationLayoutRepository.java b/layout-server/src/main/java/org/finos/vuu/layoutserver/repository/ApplicationLayoutRepository.java new file mode 100644 index 000000000..c553e7751 --- /dev/null +++ b/layout-server/src/main/java/org/finos/vuu/layoutserver/repository/ApplicationLayoutRepository.java @@ -0,0 +1,9 @@ +package org.finos.vuu.layoutserver.repository; + +import org.finos.vuu.layoutserver.model.ApplicationLayout; +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface ApplicationLayoutRepository extends CrudRepository { +} diff --git a/layout-server/src/main/java/org/finos/vuu/layoutserver/repository/LayoutRepository.java b/layout-server/src/main/java/org/finos/vuu/layoutserver/repository/LayoutRepository.java index d57af4897..19f294ac1 100644 --- a/layout-server/src/main/java/org/finos/vuu/layoutserver/repository/LayoutRepository.java +++ b/layout-server/src/main/java/org/finos/vuu/layoutserver/repository/LayoutRepository.java @@ -7,4 +7,4 @@ import java.util.UUID; @Repository -public interface LayoutRepository extends CrudRepository {} +public interface LayoutRepository extends CrudRepository {} \ No newline at end of file diff --git a/layout-server/src/main/java/org/finos/vuu/layoutserver/repository/MetadataRepository.java b/layout-server/src/main/java/org/finos/vuu/layoutserver/repository/MetadataRepository.java index 50cbe6288..a97f3e488 100644 --- a/layout-server/src/main/java/org/finos/vuu/layoutserver/repository/MetadataRepository.java +++ b/layout-server/src/main/java/org/finos/vuu/layoutserver/repository/MetadataRepository.java @@ -1,9 +1,12 @@ package org.finos.vuu.layoutserver.repository; -import java.util.UUID; import org.finos.vuu.layoutserver.model.Metadata; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; +import java.util.UUID; + + @Repository -public interface MetadataRepository extends CrudRepository {} +public interface MetadataRepository extends CrudRepository { +} diff --git a/layout-server/src/main/java/org/finos/vuu/layoutserver/service/ApplicationLayoutService.java b/layout-server/src/main/java/org/finos/vuu/layoutserver/service/ApplicationLayoutService.java new file mode 100644 index 000000000..8c9a2c622 --- /dev/null +++ b/layout-server/src/main/java/org/finos/vuu/layoutserver/service/ApplicationLayoutService.java @@ -0,0 +1,41 @@ +package org.finos.vuu.layoutserver.service; + +import com.fasterxml.jackson.databind.JsonNode; +import lombok.RequiredArgsConstructor; +import org.finos.vuu.layoutserver.model.ApplicationLayout; +import org.finos.vuu.layoutserver.repository.ApplicationLayoutRepository; +import org.finos.vuu.layoutserver.utils.DefaultApplicationLayoutLoader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.stereotype.Service; + +import java.util.NoSuchElementException; + +@RequiredArgsConstructor +@Service +public class ApplicationLayoutService { + + private static final Logger logger = LoggerFactory.getLogger(ApplicationLayoutService.class); + private final ApplicationLayoutRepository repository; + private final DefaultApplicationLayoutLoader defaultLoader; + + public void persistApplicationLayout(String username, JsonNode layoutDefinition) { + repository.save(new ApplicationLayout(username, layoutDefinition)); + } + + public ApplicationLayout getApplicationLayout(String username) { + return repository.findById(username).orElseGet(() -> { + logger.info("No application layout for user, returning default"); + return defaultLoader.getDefaultLayout(); + }); + } + + public void deleteApplicationLayout(String username) { + try { + repository.deleteById(username); + } catch (EmptyResultDataAccessException e) { + throw new NoSuchElementException("No layout found for user: " + username); + } + } +} diff --git a/layout-server/src/main/java/org/finos/vuu/layoutserver/service/LayoutService.java b/layout-server/src/main/java/org/finos/vuu/layoutserver/service/LayoutService.java index 3127fe661..2d691728b 100644 --- a/layout-server/src/main/java/org/finos/vuu/layoutserver/service/LayoutService.java +++ b/layout-server/src/main/java/org/finos/vuu/layoutserver/service/LayoutService.java @@ -1,29 +1,24 @@ package org.finos.vuu.layoutserver.service; -import java.util.Date; -import java.util.UUID; -import java.util.List; -import java.util.NoSuchElementException; import lombok.RequiredArgsConstructor; import org.finos.vuu.layoutserver.model.Layout; import org.finos.vuu.layoutserver.model.Metadata; import org.finos.vuu.layoutserver.repository.LayoutRepository; import org.springframework.stereotype.Service; +import java.time.LocalDate; +import java.util.NoSuchElementException; +import java.util.UUID; + @RequiredArgsConstructor @Service public class LayoutService { private final LayoutRepository layoutRepository; - private final MetadataService metadataService; public Layout getLayout(UUID id) { return layoutRepository.findById(id) - .orElseThrow(() -> new NoSuchElementException("Layout with ID '" + id + "' not found")); - } - - public List getMetadata() { - return metadataService.getMetadata(); + .orElseThrow(() -> new NoSuchElementException("Layout with ID '" + id + "' not found")); } public Layout createLayout(Layout layout) { @@ -39,10 +34,10 @@ public void updateLayout(UUID layoutId, Layout newLayout) { Metadata newMetadata = newLayout.getMetadata(); Metadata updatedMetadata = Metadata.builder() - .baseMetadata(newMetadata.getBaseMetadata()) - .updated(new Date()) - .id(layoutToUpdate.getMetadata().getId()) - .build(); + .baseMetadata(newMetadata.getBaseMetadata()) + .updated(LocalDate.now()) + .id(layoutToUpdate.getMetadata().getId()) + .build(); layoutToUpdate.setDefinition(newLayout.getDefinition()); layoutToUpdate.setMetadata(updatedMetadata); diff --git a/layout-server/src/main/java/org/finos/vuu/layoutserver/service/MetadataService.java b/layout-server/src/main/java/org/finos/vuu/layoutserver/service/MetadataService.java index de3eb095e..08398edc4 100644 --- a/layout-server/src/main/java/org/finos/vuu/layoutserver/service/MetadataService.java +++ b/layout-server/src/main/java/org/finos/vuu/layoutserver/service/MetadataService.java @@ -1,12 +1,13 @@ package org.finos.vuu.layoutserver.service; -import java.util.ArrayList; -import java.util.List; import lombok.RequiredArgsConstructor; import org.finos.vuu.layoutserver.model.Metadata; import org.finos.vuu.layoutserver.repository.MetadataRepository; import org.springframework.stereotype.Service; +import java.util.ArrayList; +import java.util.List; + @RequiredArgsConstructor @Service public class MetadataService { diff --git a/layout-server/src/main/java/org/finos/vuu/layoutserver/utils/DefaultApplicationLayoutLoader.java b/layout-server/src/main/java/org/finos/vuu/layoutserver/utils/DefaultApplicationLayoutLoader.java new file mode 100644 index 000000000..0921acebf --- /dev/null +++ b/layout-server/src/main/java/org/finos/vuu/layoutserver/utils/DefaultApplicationLayoutLoader.java @@ -0,0 +1,40 @@ +package org.finos.vuu.layoutserver.utils; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.finos.vuu.layoutserver.exceptions.InternalServerErrorException; +import org.finos.vuu.layoutserver.model.ApplicationLayout; +import org.springframework.context.annotation.Bean; +import org.springframework.core.io.ClassPathResource; +import org.springframework.stereotype.Component; + +import java.io.IOException; + +@Component +public class DefaultApplicationLayoutLoader { + private static final String DEFAULT_LAYOUT_FILE = "defaultApplicationLayout.json"; + private static ApplicationLayout defaultLayout; + + @Bean + public ApplicationLayout getDefaultLayout() { + if (defaultLayout == null) { + loadDefaultLayout(); + } + return defaultLayout; + } + + private void loadDefaultLayout() { + JsonNode definition = loadDefaultLayoutJsonFile(); + defaultLayout = new ApplicationLayout(null, definition); + } + + private JsonNode loadDefaultLayoutJsonFile() { + ObjectMapper objectMapper = new ObjectMapper(); + ClassPathResource resource = new ClassPathResource(DEFAULT_LAYOUT_FILE); + try { + return objectMapper.readTree(resource.getInputStream()); + } catch (IOException e) { + throw new InternalServerErrorException("Failed to read default application layout"); + } + } +} diff --git a/layout-server/src/main/java/org/finos/vuu/layoutserver/utils/JsonNodeConverter.java b/layout-server/src/main/java/org/finos/vuu/layoutserver/utils/JsonNodeConverter.java new file mode 100644 index 000000000..1984aa56b --- /dev/null +++ b/layout-server/src/main/java/org/finos/vuu/layoutserver/utils/JsonNodeConverter.java @@ -0,0 +1,43 @@ +package org.finos.vuu.layoutserver.utils; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.persistence.AttributeConverter; +import java.io.IOException; + +public class JsonNodeConverter implements AttributeConverter { + private static final Logger logger = LoggerFactory.getLogger(JsonNodeConverter.class); + private static final ObjectMapper objectMapper = new ObjectMapper(); + + @Override + public String convertToDatabaseColumn(JsonNode definition) { + try { + return objectMapper.writeValueAsString(definition); + } catch (final JsonProcessingException e) { + logger.error("JSON writing error", e); + return null; + } + } + + @Override + public JsonNode convertToEntityAttribute(String definition) { + try { + return objectMapper.readValue(extractDefinition(definition), new TypeReference<>() {}); + } catch (final IOException e) { + logger.error("JSON reading error", e); + return null; + } + } + + private String extractDefinition(String definition) { + if (definition.startsWith("\"") && definition.endsWith("\"")) { + definition = definition.substring(1, definition.length() - 1); + } + return definition.replaceAll("\\\\", ""); + } +} diff --git a/layout-server/src/main/resources/defaultApplicationLayout.json b/layout-server/src/main/resources/defaultApplicationLayout.json new file mode 100644 index 000000000..871b11b44 --- /dev/null +++ b/layout-server/src/main/resources/defaultApplicationLayout.json @@ -0,0 +1,22 @@ +{ + "id": "main-tabs", + "type": "Stack", + "props": { + "className": "vuuShell-mainTabs", + "TabstripProps": { + "allowAddTab": true, + "allowRenameTab": true, + "animateSelectionThumb": false, + "className": "vuuShellMainTabstrip", + "location": "main-tab" + }, + "preserve": true, + "active": 0 + }, + "children": [ + { + "type": "Placeholder", + "title": "Page 1" + } + ] +} diff --git a/layout-server/src/test/java/org/finos/vuu/layoutserver/controller/ApplicationLayoutControllerTest.java b/layout-server/src/test/java/org/finos/vuu/layoutserver/controller/ApplicationLayoutControllerTest.java new file mode 100644 index 000000000..24284d2aa --- /dev/null +++ b/layout-server/src/test/java/org/finos/vuu/layoutserver/controller/ApplicationLayoutControllerTest.java @@ -0,0 +1,63 @@ +package org.finos.vuu.layoutserver.controller; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.finos.vuu.layoutserver.dto.response.ApplicationLayoutDto; +import org.finos.vuu.layoutserver.model.ApplicationLayout; +import org.finos.vuu.layoutserver.service.ApplicationLayoutService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.modelmapper.ModelMapper; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.*; + +class ApplicationLayoutControllerTest { + private static ApplicationLayoutService mockService; + private static ApplicationLayoutController controller; + private static final ModelMapper modelMapper = new ModelMapper(); + private static final ObjectMapper objectMapper = new ObjectMapper(); + + @BeforeEach + public void setup() { + mockService = Mockito.mock(ApplicationLayoutService.class); + controller = new ApplicationLayoutController(mockService, modelMapper); + } + + @Test + public void getApplicationLayout_anyUsername_returnsLayoutFromService() throws JsonProcessingException { + String user = "user"; + JsonNode definition = objectMapper.readTree("{\"id\":\"main-tabs\"}"); + + when(mockService.getApplicationLayout(user)) + .thenReturn(new ApplicationLayout(user, definition)); + + ApplicationLayoutDto response = controller.getApplicationLayout(user); + + assertThat(response.getUsername()).isEqualTo(user); + assertThat(response.getDefinition()).isEqualTo(definition); + + verify(mockService, times(1)).getApplicationLayout(user); + } + + @Test + public void persistApplicationLayout_anyInput_callsService() throws JsonProcessingException { + String user = "user"; + JsonNode definition = objectMapper.readTree("{\"id\":\"main-tabs\"}"); + + controller.persistApplicationLayout(user, definition); + + verify(mockService, times(1)).persistApplicationLayout(user, definition); + } + + @Test + public void deleteApplicationLayout_anyUsername_callsService() { + String user = "user"; + + controller.deleteApplicationLayout(user); + + verify(mockService, times(1)).deleteApplicationLayout(user); + } +} diff --git a/layout-server/src/test/java/org/finos/vuu/layoutserver/controller/LayoutControllerTest.java b/layout-server/src/test/java/org/finos/vuu/layoutserver/controller/LayoutControllerTest.java index 82f937163..7f0a42cd6 100644 --- a/layout-server/src/test/java/org/finos/vuu/layoutserver/controller/LayoutControllerTest.java +++ b/layout-server/src/test/java/org/finos/vuu/layoutserver/controller/LayoutControllerTest.java @@ -1,18 +1,9 @@ package org.finos.vuu.layoutserver.controller; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.ArrayList; -import java.util.List; -import java.util.NoSuchElementException; -import java.util.UUID; -import org.finos.vuu.layoutserver.dto.request.LayoutRequestDTO; -import org.finos.vuu.layoutserver.dto.request.MetadataRequestDTO; -import org.finos.vuu.layoutserver.dto.response.LayoutResponseDTO; -import org.finos.vuu.layoutserver.dto.response.MetadataResponseDTO; +import org.finos.vuu.layoutserver.dto.request.LayoutRequestDto; +import org.finos.vuu.layoutserver.dto.request.MetadataRequestDto; +import org.finos.vuu.layoutserver.dto.response.LayoutResponseDto; +import org.finos.vuu.layoutserver.dto.response.MetadataResponseDto; import org.finos.vuu.layoutserver.model.BaseMetadata; import org.finos.vuu.layoutserver.model.Layout; import org.finos.vuu.layoutserver.model.Metadata; @@ -26,9 +17,26 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.modelmapper.ModelMapper; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + @ExtendWith(MockitoExtension.class) class LayoutControllerTest { + private static final String LAYOUT_DEFINITION = "Test Definition"; + private static final String LAYOUT_GROUP = "Test Group"; + private static final String LAYOUT_NAME = "Test Layout"; + private static final String LAYOUT_SCREENSHOT = "Test Screenshot"; + private static final String LAYOUT_USER = "Test User"; + private static final UUID VALID_ID = UUID.randomUUID(); + private static final UUID DOES_NOT_EXIST_ID = UUID.randomUUID(); + @Mock private LayoutService layoutService; @@ -41,74 +49,69 @@ class LayoutControllerTest { @InjectMocks private LayoutController layoutController; - private UUID validLayoutId; - private UUID doesNotExistLayoutId; private Layout layout; private Metadata metadata; private BaseMetadata baseMetadata; - private LayoutRequestDTO layoutRequest; - private LayoutResponseDTO expectedLayoutResponse; - private List expectedMetadataResponse; + private LayoutRequestDto layoutRequest; + private LayoutResponseDto expectedLayoutResponse; + private MetadataResponseDto metadataResponse; @BeforeEach public void setup() { - validLayoutId = UUID.randomUUID(); - doesNotExistLayoutId = UUID.randomUUID(); - String layoutDefinition = "Test Definition"; - baseMetadata = new BaseMetadata(); - baseMetadata.setName("Test Layout"); - baseMetadata.setUser("Test User"); - baseMetadata.setGroup("Test Group"); - baseMetadata.setScreenshot("Test Screenshot"); + baseMetadata.setName(LAYOUT_NAME); + baseMetadata.setUser(LAYOUT_USER); + baseMetadata.setGroup(LAYOUT_GROUP); + baseMetadata.setScreenshot(LAYOUT_SCREENSHOT); - metadata = new Metadata(); - metadata.setBaseMetadata(baseMetadata); + metadata = Metadata.builder().id(VALID_ID).baseMetadata(baseMetadata).build(); layout = new Layout(); layout.setMetadata(metadata); - layout.setId(validLayoutId); - layout.setDefinition(layoutDefinition); + layout.setId(VALID_ID); + layout.setDefinition(LAYOUT_DEFINITION); - layoutRequest = new LayoutRequestDTO(); - MetadataRequestDTO metadataRequestDTO = new MetadataRequestDTO(); - metadataRequestDTO.setBaseMetadata(baseMetadata); + layoutRequest = new LayoutRequestDto(); + MetadataRequestDto metadataRequestDto = new MetadataRequestDto(); + metadataRequestDto.setBaseMetadata(baseMetadata); layoutRequest.setDefinition(layout.getDefinition()); - layoutRequest.setMetadata(metadataRequestDTO); + layoutRequest.setMetadata(metadataRequestDto); - expectedLayoutResponse = new LayoutResponseDTO(); - expectedLayoutResponse.setDefinition(layout.getDefinition()); + metadataResponse = getMetadataResponseDto(); - MetadataResponseDTO metadataResponse = getMetadataResponseDTO(); + expectedLayoutResponse = new LayoutResponseDto(); + expectedLayoutResponse.setId(layout.getId()); + expectedLayoutResponse.setDefinition(layout.getDefinition()); expectedLayoutResponse.setMetadata(metadataResponse); - expectedMetadataResponse = new ArrayList<>(); - expectedMetadataResponse.add(metadataResponse); } @Test void getLayout_layoutExists_returnsLayout() { - when(layoutService.getLayout(validLayoutId)).thenReturn(layout); - when(modelMapper.map(layout, LayoutResponseDTO.class)).thenReturn( - expectedLayoutResponse); - assertThat(layoutController.getLayout(validLayoutId)).isEqualTo(expectedLayoutResponse); + when(layoutService.getLayout(VALID_ID)).thenReturn(layout); + when(modelMapper.map(layout, LayoutResponseDto.class)).thenReturn(expectedLayoutResponse); + assertThat(layoutController.getLayout(VALID_ID)).isEqualTo(expectedLayoutResponse); } @Test - void getLayout_layoutDoesNotExist_throwsNotFoundAndReturns404() { - when(layoutService.getLayout(doesNotExistLayoutId)).thenThrow(NoSuchElementException.class); + void getLayout_layoutDoesNotExist_throwsNoSuchElementException() { + when(layoutService.getLayout(DOES_NOT_EXIST_ID)) + .thenThrow(NoSuchElementException.class); + assertThrows(NoSuchElementException.class, - () -> layoutController.getLayout(doesNotExistLayoutId)); + () -> layoutController.getLayout(DOES_NOT_EXIST_ID)); } @Test void getMetadata_metadataExists_returnsMetadata() { - when(metadataService.getMetadata()).thenReturn(List.of(metadata)); - when(modelMapper.map(metadata, MetadataResponseDTO.class)).thenReturn( - getMetadataResponseDTO()); + List metadataList = List.of(metadata); - assertThat(layoutController.getMetadata()).isEqualTo(expectedMetadataResponse); + when(metadataService.getMetadata()).thenReturn(metadataList); + when(modelMapper.map(metadata, MetadataResponseDto.class)) + .thenReturn(metadataResponse); + + assertThat(layoutController.getMetadata()).isEqualTo(List.of(metadataResponse)); } @Test @@ -121,39 +124,39 @@ void getMetadata_noMetadataExists_returnsEmptyArray() { void createLayout_validLayout_returnsCreatedLayout() { Layout layoutWithoutIds = layout; layoutWithoutIds.setId(null); - layoutWithoutIds.getMetadata().setId(null); when(modelMapper.map(layoutRequest, Layout.class)).thenReturn(layoutWithoutIds); when(layoutService.createLayout(layoutWithoutIds)).thenReturn(layout); - when(modelMapper.map(layout, LayoutResponseDTO.class)).thenReturn(expectedLayoutResponse); + when(modelMapper.map(layout, LayoutResponseDto.class)).thenReturn(expectedLayoutResponse); - assertThat(layoutController.createLayout(layoutRequest)) - .isEqualTo(expectedLayoutResponse); + assertThat(layoutController.createLayout(layoutRequest)).isEqualTo(expectedLayoutResponse); } @Test - void updateLayout_callsLayoutService() { + void updateLayout_validLayout_callsLayoutService() { + layout.setId(null); + // layout.getMetadata().setId(null); when(modelMapper.map(layoutRequest, Layout.class)).thenReturn(layout); - layoutController.updateLayout(validLayoutId, layoutRequest); + layoutController.updateLayout(VALID_ID, layoutRequest); - verify(layoutService).updateLayout(validLayoutId, layout); + verify(layoutService).updateLayout(VALID_ID, layout); } @Test - void deleteLayout_callsLayoutService() { - layoutController.deleteLayout(validLayoutId); + void deleteLayout__validId_callsLayoutService() { + layoutController.deleteLayout(VALID_ID); - verify(layoutService).deleteLayout(validLayoutId); + verify(layoutService).deleteLayout(VALID_ID); } - private MetadataResponseDTO getMetadataResponseDTO() { - MetadataResponseDTO metadataResponse = new MetadataResponseDTO(); + private MetadataResponseDto getMetadataResponseDto() { + MetadataResponseDto metadataResponse = new MetadataResponseDto(); + metadataResponse.setId(layout.getId()); metadataResponse.setBaseMetadata(baseMetadata); metadataResponse.setCreated(layout.getMetadata().getCreated()); metadataResponse.setUpdated(layout.getMetadata().getUpdated()); - metadataResponse.setId(layout.getId()); return metadataResponse; } } diff --git a/layout-server/src/test/java/org/finos/vuu/layoutserver/integration/ApplicationLayoutIntegrationTest.java b/layout-server/src/test/java/org/finos/vuu/layoutserver/integration/ApplicationLayoutIntegrationTest.java new file mode 100644 index 000000000..e4724bbb1 --- /dev/null +++ b/layout-server/src/test/java/org/finos/vuu/layoutserver/integration/ApplicationLayoutIntegrationTest.java @@ -0,0 +1,181 @@ +package org.finos.vuu.layoutserver.integration; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.finos.vuu.layoutserver.exceptions.InternalServerErrorException; +import org.finos.vuu.layoutserver.model.ApplicationLayout; +import org.finos.vuu.layoutserver.repository.ApplicationLayoutRepository; +import org.finos.vuu.layoutserver.utils.DefaultApplicationLayoutLoader; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; + +import java.util.HashMap; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.*; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest +@AutoConfigureMockMvc +@ActiveProfiles("test") +public class ApplicationLayoutIntegrationTest { + private static final ObjectMapper objectMapper = new ObjectMapper(); + private static final String BASE_URL = "/application-layouts"; + private static final String MISSING_USERNAME_ERROR_MESSAGE = + "Required request header 'username' for method parameter type String is not present"; + + @Autowired + private MockMvc mockMvc; + @Autowired + private ApplicationLayoutRepository repository; + @MockBean + private DefaultApplicationLayoutLoader mockLoader; + private final DefaultApplicationLayoutLoader realLoader = new DefaultApplicationLayoutLoader(); + + @Test + public void getApplicationLayout_noLayoutExists_returns200WithDefaultLayout() throws Exception { + when(mockLoader.getDefaultLayout()).thenReturn(realLoader.getDefaultLayout()); + + mockMvc.perform(get(BASE_URL).header("username", "new user")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.username", nullValue())) + // Expecting application layout as defined in /test/resources/defaultApplicationLayout.json + .andExpect(jsonPath("$.definition.defaultLayoutKey", is("default-layout-value"))); + } + + @Test + public void getApplicationLayout_defaultFailsToLoad_returns500() throws Exception { + String errorMessage = "Failed to read default application layout"; + doThrow(new InternalServerErrorException(errorMessage)).when(mockLoader).getDefaultLayout(); + + mockMvc.perform(get(BASE_URL).header("username", "new user")) + .andExpect(status().isInternalServerError()) + .andExpect(jsonPath("$.messages", iterableWithSize(1))) + .andExpect(jsonPath("$.messages", contains(errorMessage))); + } + + @Test + public void getApplicationLayout_noUserInHeader_returns400() throws Exception { + String actualError = mockMvc.perform(get(BASE_URL)) + .andExpect(status().isBadRequest()) + .andReturn().getResponse().getErrorMessage(); + + assertThat(actualError).isEqualTo(MISSING_USERNAME_ERROR_MESSAGE); + } + + @Test + public void getApplicationLayout_layoutExists_returns200WithPersistedLayout() throws Exception { + String user = "user"; + + Map definition = new HashMap<>(); + definition.put("defKey", "defVal"); + + persistApplicationLayout(user, definition); + + mockMvc.perform(get(BASE_URL).header("username", user)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.username", is(user))) + .andExpect(jsonPath("$.definition", is(definition))); + } + + @Test + public void persistApplicationLayout_noLayoutExists_returns201AndPersistsLayout() throws Exception { + String user = "user"; + String definition = "{\"key\": \"value\"}"; + + mockMvc.perform(put(BASE_URL).header("username", user) + .content(definition) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$").doesNotExist()); + + ApplicationLayout persistedLayout = repository.findById(user).orElseThrow(); + + assertThat(persistedLayout.getUsername()).isEqualTo(user); + assertThat(persistedLayout.getDefinition()).isEqualTo(objectMapper.readTree(definition)); + } + + @Test + public void persistApplicationLayout_layoutExists_returns201AndOverwritesLayout() throws Exception { + String user = "user"; + + Map initialDefinition = new HashMap<>(); + initialDefinition.put("initial-key", "initial-value"); + + persistApplicationLayout(user, initialDefinition); + + String newDefinition = "{\"new-key\": \"new-value\"}"; + + mockMvc.perform(put(BASE_URL).header("username", user) + .content(newDefinition) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$").doesNotExist()); + + assertThat(repository.findAll()).hasSize(1); + + ApplicationLayout retrievedLayout = repository.findById(user).orElseThrow(); + + assertThat(retrievedLayout.getUsername()).isEqualTo(user); + assertThat(retrievedLayout.getDefinition()).isEqualTo(objectMapper.readTree(newDefinition)); + } + + @Test + public void persistApplicationLayout_noUserInHeader_returns400() throws Exception { + String actualError = mockMvc.perform(put(BASE_URL)) + .andExpect(status().isBadRequest()) + .andReturn().getResponse().getErrorMessage(); + + assertThat(actualError).isEqualTo(MISSING_USERNAME_ERROR_MESSAGE); + } + + @Test + public void deleteApplicationLayout_noLayoutExists_returns404() throws Exception { + String user = "user"; + + mockMvc.perform(delete(BASE_URL).header("username", user)) + .andExpect(status().isNotFound()) + .andExpect(jsonPath("$.messages", iterableWithSize(1))) + .andExpect(jsonPath("$.messages", contains("No layout found for user: " + user))); + } + + @Test + public void deleteApplicationLayout_layoutExists_returns204AndDeletesLayout() throws Exception { + String user = "user"; + + Map initialDefinition = new HashMap<>(); + initialDefinition.put("initial-key", "initial-value"); + + persistApplicationLayout(user, initialDefinition); + + mockMvc.perform(delete(BASE_URL).header("username", user)) + .andExpect(status().isNoContent()) + .andExpect(jsonPath("$").doesNotExist()); + + assertThat(repository.findAll()).hasSize(0); + } + + @Test + public void deleteApplicationLayout_noUserInHeader_returns400() throws Exception { + String actualError = mockMvc.perform(delete(BASE_URL)) + .andExpect(status().isBadRequest()) + .andReturn().getResponse().getErrorMessage(); + + assertThat(actualError).isEqualTo(MISSING_USERNAME_ERROR_MESSAGE); + } + + private void persistApplicationLayout(String user, Map definition) { + repository.save(new ApplicationLayout(user, objectMapper.convertValue(definition, JsonNode.class))); + } +} diff --git a/layout-server/src/test/java/org/finos/vuu/layoutserver/integration/LayoutIntegrationTest.java b/layout-server/src/test/java/org/finos/vuu/layoutserver/integration/LayoutIntegrationTest.java index 1aebe4192..764eb626a 100644 --- a/layout-server/src/test/java/org/finos/vuu/layoutserver/integration/LayoutIntegrationTest.java +++ b/layout-server/src/test/java/org/finos/vuu/layoutserver/integration/LayoutIntegrationTest.java @@ -1,28 +1,15 @@ package org.finos.vuu.layoutserver.integration; -import static org.assertj.core.api.Assertions.assertThat; -import static org.hamcrest.Matchers.anyOf; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - import com.fasterxml.jackson.databind.ObjectMapper; import com.jayway.jsonpath.JsonPath; -import java.util.UUID; -import org.finos.vuu.layoutserver.dto.request.LayoutRequestDTO; -import org.finos.vuu.layoutserver.dto.request.MetadataRequestDTO; +import org.finos.vuu.layoutserver.dto.request.LayoutRequestDto; +import org.finos.vuu.layoutserver.dto.request.MetadataRequestDto; import org.finos.vuu.layoutserver.model.BaseMetadata; import org.finos.vuu.layoutserver.model.Layout; import org.finos.vuu.layoutserver.model.Metadata; import org.finos.vuu.layoutserver.repository.LayoutRepository; import org.finos.vuu.layoutserver.repository.MetadataRepository; -import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; @@ -31,20 +18,26 @@ import org.springframework.test.context.ActiveProfiles; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; -import org.springframework.transaction.annotation.Transactional; + +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @SpringBootTest @AutoConfigureMockMvc -@Transactional @ActiveProfiles("test") public class LayoutIntegrationTest { - private static String defaultDefinition; - private static String defaultName; - private static String defaultGroup; - private static String defaultScreenshot; - private static String defaultUser; - private static UUID defaultId; + private static final String DEFAULT_LAYOUT_DEFINITION = "Default layout definition"; + private static final String DEFAULT_LAYOUT_NAME = "Default layout name"; + private static final String DEFAULT_LAYOUT_GROUP = "Default layout group"; + private static final String DEFAULT_LAYOUT_SCREENSHOT = "Default layout screenshot"; + private static final String DEFAULT_LAYOUT_USER = "Default layout user"; + private static final UUID DEFAULT_LAYOUT_ID = UUID.fromString("00000000-0000-0000-0000-000000000000"); private final ObjectMapper objectMapper = new ObjectMapper(); @@ -55,32 +48,29 @@ public class LayoutIntegrationTest { @Autowired private MetadataRepository metadataRepository; - @BeforeAll - public static void setup() { - defaultDefinition = "Default layout definition"; - defaultName = "Default layout name"; - defaultGroup = "Default layout group"; - defaultScreenshot = "Default layout screenshot"; - defaultUser = "Default layout user"; - defaultId = UUID.fromString("00000000-0000-0000-0000-000000000000"); + @BeforeEach + void tearDown() { + layoutRepository.deleteAll(); + metadataRepository.deleteAll(); } @Test void getLayout_validIDAndLayoutExists_returns200WithLayout() throws Exception { Layout layout = createDefaultLayoutInDatabase(); + assertThat(layoutRepository.findById(layout.getId()).orElseThrow()).isEqualTo(layout); mockMvc.perform(get("/layouts/{id}", layout.getId())) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.definition", - is(layout.getDefinition()))) - .andExpect(jsonPath("$.metadata.name", - is(layout.getMetadata().getBaseMetadata().getName()))) - .andExpect(jsonPath("$.metadata.group", - is(layout.getMetadata().getBaseMetadata().getGroup()))) - .andExpect(jsonPath("$.metadata.screenshot", - is(layout.getMetadata().getBaseMetadata().getScreenshot()))) - .andExpect(jsonPath("$.metadata.user", - is(layout.getMetadata().getBaseMetadata().getUser()))); + .andExpect(status().isOk()) + .andExpect(jsonPath("$.definition", + is(layout.getDefinition()))) + .andExpect(jsonPath("$.metadata.name", + is(layout.getMetadata().getBaseMetadata().getName()))) + .andExpect(jsonPath("$.metadata.group", + is(layout.getMetadata().getBaseMetadata().getGroup()))) + .andExpect(jsonPath("$.metadata.screenshot", + is(layout.getMetadata().getBaseMetadata().getScreenshot()))) + .andExpect(jsonPath("$.metadata.user", + is(layout.getMetadata().getBaseMetadata().getUser()))); } @Test @@ -95,61 +85,64 @@ void getLayout_invalidId_returns400() throws Exception { String layoutID = "invalidUUID"; mockMvc.perform(get("/layouts/{id}", layoutID)) - .andExpect(status().isBadRequest()) - .andExpect(content().string( - "Failed to convert value of type 'java.lang.String' to required type 'java.util" - + ".UUID'; nested exception is java.lang.IllegalArgumentException: Invalid " - + "UUID string: invalidUUID")); + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.messages", iterableWithSize(1))) + .andExpect(jsonPath("$.messages", + contains("Failed to convert value of type 'java.lang.String' to required type 'java.util" + + ".UUID'; nested exception is java.lang.IllegalArgumentException: Invalid " + + "UUID string: invalidUUID"))); } @Test - void getMetadata_metadataExists_returnsMetadata() throws Exception { + void getMetadata_singleMetadataExists_returnsMetadata() throws Exception { Layout layout = createDefaultLayoutInDatabase(); + assertThat(layoutRepository.findById(layout.getId()).orElseThrow()).isEqualTo(layout); mockMvc.perform(get("/layouts/metadata")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$[0].name", - is(layout.getMetadata().getBaseMetadata().getName()))) - .andExpect(jsonPath("$[0].group", - is(layout.getMetadata().getBaseMetadata().getGroup()))) - .andExpect(jsonPath("$[0].screenshot", - is(layout.getMetadata().getBaseMetadata().getScreenshot()))) - .andExpect(jsonPath("$[0].user", - is(layout.getMetadata().getBaseMetadata().getUser()))); + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].name", + is(layout.getMetadata().getBaseMetadata().getName()))) + .andExpect(jsonPath("$[0].group", + is(layout.getMetadata().getBaseMetadata().getGroup()))) + .andExpect(jsonPath("$[0].screenshot", + is(layout.getMetadata().getBaseMetadata().getScreenshot()))) + .andExpect(jsonPath("$[0].user", + is(layout.getMetadata().getBaseMetadata().getUser()))); } @Test void getMetadata_metadataDoesNotExist_returnsEmptyList() throws Exception { mockMvc.perform(get("/layouts/metadata")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$").isEmpty()); + .andExpect(status().isOk()) + .andExpect(jsonPath("$").isEmpty()); } @Test - void createLayout_validLayout_returnsCreatedLayoutAndLayoutIsPersisted() - throws Exception { - LayoutRequestDTO layoutRequest = createValidLayoutRequest(); + void createLayout_validRequest_returnsCreatedLayoutAndLayoutIsPersisted() + throws Exception { + LayoutRequestDto layoutRequest = createValidLayoutRequest(); MvcResult result = mockMvc.perform(post("/layouts") - .content(objectMapper.writeValueAsString(layoutRequest)) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isCreated()) - .andExpect(jsonPath("$.definition", is(layoutRequest.getDefinition()))) - .andExpect(jsonPath("$.metadata.name", - is(layoutRequest.getMetadata().getBaseMetadata().getName()))) - .andExpect(jsonPath("$.metadata.group", - is(layoutRequest.getMetadata().getBaseMetadata().getGroup()))) - .andExpect(jsonPath("$.metadata.screenshot", - is(layoutRequest.getMetadata().getBaseMetadata().getScreenshot()))) - .andExpect(jsonPath("$.metadata.user", - is(layoutRequest.getMetadata().getBaseMetadata().getUser()))) - .andReturn(); + .content(objectMapper.writeValueAsString(layoutRequest)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$.id").isNotEmpty()) + .andExpect(jsonPath("$.definition", is(layoutRequest.getDefinition()))) + .andExpect(jsonPath("$.metadata.name", + is(layoutRequest.getMetadata().getBaseMetadata().getName()))) + .andExpect(jsonPath("$.metadata.group", + is(layoutRequest.getMetadata().getBaseMetadata().getGroup()))) + .andExpect(jsonPath("$.metadata.screenshot", + is(layoutRequest.getMetadata().getBaseMetadata().getScreenshot()))) + .andExpect(jsonPath("$.metadata.user", + is(layoutRequest.getMetadata().getBaseMetadata().getUser()))) + .andReturn(); UUID createdLayoutId = UUID.fromString( - JsonPath.read(result.getResponse().getContentAsString(), "$.metadata.id")); + JsonPath.read(result.getResponse().getContentAsString(), "$.id")); Layout createdLayout = layoutRepository.findById(createdLayoutId).orElseThrow(); Metadata createdMetadata = metadataRepository.findById(createdLayout.getMetadata().getId()) - .orElseThrow(); + .orElseThrow(); // Check that the one-to-one relationship isn't causing duplicate/unexpected entries in // the DB @@ -157,161 +150,212 @@ void createLayout_validLayout_returnsCreatedLayoutAndLayoutIsPersisted() assertThat(metadataRepository.findAll()).containsExactly(createdMetadata); assertThat(createdLayout.getDefinition()) - .isEqualTo(layoutRequest.getDefinition()); + .isEqualTo(layoutRequest.getDefinition()); assertThat(createdMetadata.getBaseMetadata().getName()) - .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getName()); + .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getName()); assertThat(createdMetadata.getBaseMetadata().getGroup()) - .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getGroup()); + .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getGroup()); assertThat(createdMetadata.getBaseMetadata().getScreenshot()) - .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getScreenshot()); + .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getScreenshot()); assertThat(createdMetadata.getBaseMetadata().getUser()) - .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getUser()); + .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getUser()); } @Test - void createLayout_invalidLayout_returns400() throws Exception { - String invalidLayout = "invalidLayout"; + void createLayout_invalidRequestBodyDefinitionsIsBlank_returns400AndDoesNotCreateLayout() + throws Exception { + LayoutRequestDto layoutRequest = createValidLayoutRequest(); + layoutRequest.setDefinition(""); mockMvc.perform(post("/layouts") - .content(invalidLayout) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isBadRequest()) - .andExpect(content().string( - "JSON parse error: Unrecognized token 'invalidLayout': was expecting (JSON " - + "String, Number, Array, Object or token 'null', 'true' or 'false'); nested " - + "exception is com.fasterxml.jackson.core.JsonParseException: Unrecognized " - + "token 'invalidLayout': was expecting (JSON String, Number, Array, Object " - + "or token 'null', 'true' or 'false')\n" - + " at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream);" - + " line: 1, column: 14]")); + .content(objectMapper.writeValueAsString(layoutRequest)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.messages", iterableWithSize(1))) + .andExpect(jsonPath("$.messages", contains("definition: Definition must not be blank"))); + + assertThat(layoutRepository.findAll()).isEmpty(); + assertThat(metadataRepository.findAll()).isEmpty(); } @Test - void createLayout_validLayoutButInvalidMetadata_returns400AndDoesNotCreateLayout() - throws Exception { - LayoutRequestDTO layoutRequest = createValidLayoutRequest(); + void createLayout_invalidRequestBodyMetadataIsNull_returns400AndDoesNotCreateLayout() + throws Exception { + LayoutRequestDto layoutRequest = createValidLayoutRequest(); layoutRequest.setMetadata(null); mockMvc.perform(post("/layouts") - .content(objectMapper.writeValueAsString(layoutRequest)) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isBadRequest()) - .andExpect(content().string( - "[metadata: Metadata must not be null]")); + .content(objectMapper.writeValueAsString(layoutRequest)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.messages", iterableWithSize(1))) + .andExpect(jsonPath("$.messages", contains("metadata: Metadata must not be null"))); assertThat(layoutRepository.findAll()).isEmpty(); + assertThat(metadataRepository.findAll()).isEmpty(); } + @Test - void updateLayout_validIDAndValidRequest_returns204AndLayoutHasChanged() throws Exception { - Layout layout = createDefaultLayoutInDatabase(); - LayoutRequestDTO layoutRequest = createValidLayoutRequest(); + void createLayout_invalidRequestBodyUnexpectedFormat_returns400() throws Exception { + String invalidLayout = "invalidLayout"; - mockMvc.perform(put("/layouts/{id}", layout.getId()) - .content(objectMapper.writeValueAsString(layoutRequest)) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isNoContent()) - .andExpect(jsonPath("$").doesNotExist()); + mockMvc.perform(post("/layouts") + .content(invalidLayout) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.messages", iterableWithSize(1))) + .andExpect(jsonPath("$.messages", contains( + "JSON parse error: Unrecognized token 'invalidLayout': was expecting (JSON " + + "String, Number, Array, Object or token 'null', 'true' or 'false'); nested " + + "exception is com.fasterxml.jackson.core.JsonParseException: Unrecognized " + + "token 'invalidLayout': was expecting (JSON String, Number, Array, Object " + + "or token 'null', 'true' or 'false')\n" + + " at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream);" + + " line: 1, column: 14]"))); + } - Layout updatedLayout = layoutRepository.findById(layout.getId()).orElseThrow(); + @Test + void updateLayout_validIdAndValidRequest_returns204AndLayoutHasChanged() throws Exception { + Layout initialLayout = createDefaultLayoutInDatabase(); + assertThat(layoutRepository.findById(initialLayout.getId()).orElseThrow()).isEqualTo( + initialLayout); + + LayoutRequestDto layoutRequest = createValidLayoutRequest(); + layoutRequest.setDefinition("Updated definition"); + layoutRequest.getMetadata().getBaseMetadata().setName("Updated name"); + layoutRequest.getMetadata().getBaseMetadata().setGroup("Updated group"); + layoutRequest.getMetadata().getBaseMetadata().setScreenshot("Updated screenshot"); + layoutRequest.getMetadata().getBaseMetadata().setUser("Updated user"); + + mockMvc.perform(put("/layouts/{id}", initialLayout.getId()) + .content(objectMapper.writeValueAsString(layoutRequest)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isNoContent()) + .andExpect(jsonPath("$").doesNotExist()); + + Layout updatedLayout = layoutRepository.findById(initialLayout.getId()).orElseThrow(); assertThat(updatedLayout.getDefinition()) - .isEqualTo(layoutRequest.getDefinition()); + .isEqualTo(layoutRequest.getDefinition()); assertThat(updatedLayout.getMetadata().getBaseMetadata().getName()) - .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getName()); + .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getName()); assertThat(updatedLayout.getMetadata().getBaseMetadata().getGroup()) - .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getGroup()); + .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getGroup()); assertThat(updatedLayout.getMetadata().getBaseMetadata().getScreenshot()) - .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getScreenshot()); + .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getScreenshot()); assertThat(updatedLayout.getMetadata().getBaseMetadata().getUser()) - .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getUser()); + .isEqualTo(layoutRequest.getMetadata().getBaseMetadata().getUser()); + + assertThat(updatedLayout).isNotEqualTo(initialLayout); } @Test - void updateLayout_invalidRequestBodyDefinitionIsBlankAndMetadataIsNull_returns400AndLayoutDoesNotChange() - throws Exception { + void updateLayout_invalidRequestBodyDefinitionIsBlank_returns400AndLayoutDoesNotChange() + throws Exception { Layout layout = createDefaultLayoutInDatabase(); + assertThat(layoutRepository.findById(layout.getId()).orElseThrow()).isEqualTo(layout); - LayoutRequestDTO request = new LayoutRequestDTO(); + LayoutRequestDto request = createValidLayoutRequest(); request.setDefinition(""); + + mockMvc.perform(put("/layouts/{id}", layout.getId()) + .content(objectMapper.writeValueAsString(request)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.messages", iterableWithSize(1))) + .andExpect(jsonPath("$.messages", contains("definition: Definition must not be blank"))); + + assertThat(layoutRepository.findById(layout.getId()).orElseThrow()).isEqualTo(layout); + } + + @Test + void updateLayout_invalidRequestBodyMetadataIsNull_returns400AndLayoutDoesNotChange() + throws Exception { + Layout layout = createDefaultLayoutInDatabase(); + assertThat(layoutRepository.findById(layout.getId()).orElseThrow()).isEqualTo(layout); + + LayoutRequestDto request = createValidLayoutRequest(); request.setMetadata(null); mockMvc.perform(put("/layouts/{id}", layout.getId()) - .content(objectMapper.writeValueAsString(request)) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isBadRequest()) - .andExpect(content().string(anyOf( - equalTo("[definition: Definition must not be blank, metadata: Metadata must not be null]"), - equalTo("[metadata: Metadata must not be null, definition: Definition must not be blank]")))); + .content(objectMapper.writeValueAsString(request)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.messages", iterableWithSize(1))) + .andExpect(jsonPath("$.messages", contains("metadata: Metadata must not be null"))); assertThat(layoutRepository.findById(layout.getId()).orElseThrow()).isEqualTo(layout); } @Test void updateLayout_invalidRequestBodyUnexpectedFormat_returns400AndLayoutDoesNotChange() - throws Exception { + throws Exception { Layout layout = createDefaultLayoutInDatabase(); + assertThat(layoutRepository.findById(layout.getId()).orElseThrow()).isEqualTo(layout); + String request = "invalidRequest"; mockMvc.perform(put("/layouts/{id}", layout.getId()) - .content(objectMapper.writeValueAsString(request)) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isBadRequest()) - .andExpect(content().string( - "JSON parse error: Cannot construct instance of `org.finos.vuu.layoutserver.dto" - + ".request.LayoutRequestDTO` (although at least one Creator exists): no " - + "String-argument constructor/factory method to deserialize from String " - + "value ('invalidRequest'); nested exception is com.fasterxml.jackson" - + ".databind.exc.MismatchedInputException: Cannot construct instance of `org" - + ".finos.vuu.layoutserver.dto.request.LayoutRequestDTO` (although at least " - + "one Creator exists): no String-argument constructor/factory method to " - + "deserialize from String value ('invalidRequest')\n" - + " at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream);" - + " line: 1, column: 1]")); + .content(objectMapper.writeValueAsString(request)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.messages", iterableWithSize(1))) + .andExpect(jsonPath("$.messages", contains( + "JSON parse error: Cannot construct instance of `org.finos.vuu.layoutserver.dto" + + ".request.LayoutRequestDto` (although at least one Creator exists): no " + + "String-argument constructor/factory method to deserialize from String " + + "value ('invalidRequest'); nested exception is com.fasterxml.jackson" + + ".databind.exc.MismatchedInputException: Cannot construct instance of `org" + + ".finos.vuu.layoutserver.dto.request.LayoutRequestDto` (although at least " + + "one Creator exists): no String-argument constructor/factory method to " + + "deserialize from String value ('invalidRequest')\n" + + " at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream);" + + " line: 1, column: 1]"))); assertThat(layoutRepository.findById(layout.getId()).orElseThrow()).isEqualTo( - layout); + layout); } @Test void updateLayout_validIdButLayoutDoesNotExist_returnsNotFound() throws Exception { UUID layoutID = UUID.randomUUID(); - LayoutRequestDTO layoutRequest = createValidLayoutRequest(); + LayoutRequestDto layoutRequest = createValidLayoutRequest(); mockMvc.perform(put("/layouts/{id}", layoutID) - .content(objectMapper.writeValueAsString(layoutRequest)) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isNotFound()); + .content(objectMapper.writeValueAsString(layoutRequest)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isNotFound()); } @Test void updateLayout_invalidId_returns400() throws Exception { String layoutID = "invalidUUID"; - LayoutRequestDTO layoutRequest = createValidLayoutRequest(); + LayoutRequestDto layoutRequest = createValidLayoutRequest(); mockMvc.perform(put("/layouts/{id}", layoutID) - .content(objectMapper.writeValueAsString(layoutRequest)) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isBadRequest()) - .andExpect(content().string( - "Failed to convert value of type 'java.lang.String' to required type 'java.util" - + ".UUID'; nested exception is java.lang.IllegalArgumentException: Invalid " - + "UUID string: invalidUUID")); + .content(objectMapper.writeValueAsString(layoutRequest)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.messages", iterableWithSize(1))) + .andExpect(jsonPath("$.messages", contains( + "Failed to convert value of type 'java.lang.String' to required type 'java.util" + + ".UUID'; nested exception is java.lang.IllegalArgumentException: Invalid " + + "UUID string: invalidUUID"))); } @Test - void deleteLayout_validIDLayoutExists_returnsSuccessAndLayoutIsDeleted() throws Exception { + void deleteLayout_validIdLayoutExists_returnsSuccessAndLayoutIsDeleted() throws Exception { Layout layout = createDefaultLayoutInDatabase(); - - mockMvc.perform(get("/layouts/{id}", layout.getId())).andExpect(status().isOk()); + assertThat(layoutRepository.findById(layout.getId()).orElseThrow()).isEqualTo(layout); mockMvc.perform(delete("/layouts/{id}", layout.getId())).andExpect(status().isNoContent()); - mockMvc.perform(get("/layouts/{id}", layout.getId())).andExpect(status().isNotFound()); + assertThat(layoutRepository.findById(layout.getId())).isEmpty(); } @Test - void deleteLayout_validIDLayoutDoesNotExist_returnsNotFound() throws Exception { + void deleteLayout_validIdLayoutDoesNotExist_returnsNotFound() throws Exception { UUID layoutID = UUID.randomUUID(); mockMvc.perform(delete("/layouts/{id}", layoutID)).andExpect(status().isNotFound()); @@ -322,11 +366,12 @@ void deleteLayout_invalidId_returns400() throws Exception { String layoutID = "invalidUUID"; mockMvc.perform(delete("/layouts/{id}", layoutID)) - .andExpect(status().isBadRequest()) - .andExpect(content().string( - "Failed to convert value of type 'java.lang.String' to required type 'java.util" - + ".UUID'; nested exception is java.lang.IllegalArgumentException: Invalid " - + "UUID string: invalidUUID")); + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.messages", iterableWithSize(1))) + .andExpect(jsonPath("$.messages", contains( + "Failed to convert value of type 'java.lang.String' to required type 'java.util" + + ".UUID'; nested exception is java.lang.IllegalArgumentException: Invalid " + + "UUID string: invalidUUID"))); } private Layout createDefaultLayoutInDatabase() { @@ -334,37 +379,32 @@ private Layout createDefaultLayoutInDatabase() { Metadata metadata = new Metadata(); BaseMetadata baseMetadata = new BaseMetadata(); - baseMetadata.setName(defaultName); - baseMetadata.setGroup(defaultGroup); - baseMetadata.setScreenshot(defaultScreenshot); - baseMetadata.setUser(defaultUser); + baseMetadata.setName(DEFAULT_LAYOUT_NAME); + baseMetadata.setGroup(DEFAULT_LAYOUT_GROUP); + baseMetadata.setScreenshot(DEFAULT_LAYOUT_SCREENSHOT); + baseMetadata.setUser(DEFAULT_LAYOUT_USER); metadata.setBaseMetadata(baseMetadata); - layout.setDefinition(defaultDefinition); + layout.setDefinition(DEFAULT_LAYOUT_DEFINITION); layout.setMetadata(metadata); - layout.setId(defaultId); - - Layout createdLayout = layoutRepository.save(layout); - - assertThat(layoutRepository.findById(createdLayout.getId()).orElseThrow()) - .isEqualTo(layout); + layout.setId(DEFAULT_LAYOUT_ID); - return createdLayout; + return layoutRepository.save(layout); } - private LayoutRequestDTO createValidLayoutRequest() { + private LayoutRequestDto createValidLayoutRequest() { BaseMetadata baseMetadata = new BaseMetadata(); - baseMetadata.setName(defaultName); - baseMetadata.setGroup(defaultGroup); - baseMetadata.setScreenshot(defaultScreenshot); - baseMetadata.setUser(defaultUser); + baseMetadata.setName(DEFAULT_LAYOUT_NAME); + baseMetadata.setGroup(DEFAULT_LAYOUT_GROUP); + baseMetadata.setScreenshot(DEFAULT_LAYOUT_SCREENSHOT); + baseMetadata.setUser(DEFAULT_LAYOUT_USER); - MetadataRequestDTO metadataRequest = new MetadataRequestDTO(); + MetadataRequestDto metadataRequest = new MetadataRequestDto(); metadataRequest.setBaseMetadata(baseMetadata); - LayoutRequestDTO layoutRequest = new LayoutRequestDTO(); - layoutRequest.setDefinition(defaultDefinition); + LayoutRequestDto layoutRequest = new LayoutRequestDto(); + layoutRequest.setDefinition(DEFAULT_LAYOUT_DEFINITION); layoutRequest.setMetadata(metadataRequest); return layoutRequest; diff --git a/layout-server/src/test/java/org/finos/vuu/layoutserver/service/ApplicationLayoutServiceTest.java b/layout-server/src/test/java/org/finos/vuu/layoutserver/service/ApplicationLayoutServiceTest.java new file mode 100644 index 000000000..e6c8f0414 --- /dev/null +++ b/layout-server/src/test/java/org/finos/vuu/layoutserver/service/ApplicationLayoutServiceTest.java @@ -0,0 +1,103 @@ +package org.finos.vuu.layoutserver.service; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.finos.vuu.layoutserver.model.ApplicationLayout; +import org.finos.vuu.layoutserver.repository.ApplicationLayoutRepository; +import org.finos.vuu.layoutserver.utils.DefaultApplicationLayoutLoader; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.dao.EmptyResultDataAccessException; + +import java.util.NoSuchElementException; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.*; + +class ApplicationLayoutServiceTest { + + private static ApplicationLayoutRepository mockRepo; + private static ApplicationLayoutService service; + private static final DefaultApplicationLayoutLoader defaultLoader = new DefaultApplicationLayoutLoader(); + private static final ObjectMapper objectMapper = new ObjectMapper(); + + @BeforeEach + public void setup() { + mockRepo = Mockito.mock(ApplicationLayoutRepository.class); + service = new ApplicationLayoutService(mockRepo, defaultLoader); + } + + @Test + public void getApplicationLayout_noLayout_returnsDefault() throws JsonProcessingException { + when(mockRepo.findById(anyString())).thenReturn(Optional.empty()); + + ApplicationLayout actualLayout = service.getApplicationLayout("new user"); + + // Expecting application layout as defined in /test/resources/defaultApplicationLayout.json + JsonNode expectedDefinition = objectMapper.readTree("{\"defaultLayoutKey\":\"default-layout-value\"}"); + + assertThat(actualLayout.getUsername()).isNull(); + assertThat(actualLayout.getDefinition()).isEqualTo(expectedDefinition); + } + + @Test + public void getApplicationLayout_layoutExists_returnsLayout() throws JsonProcessingException { + String user = "user"; + + JsonNode expectedDefinition = objectMapper.readTree("{\"id\":\"main-tabs\"}"); + ApplicationLayout expectedLayout = new ApplicationLayout(user, expectedDefinition); + + when(mockRepo.findById(user)).thenReturn(Optional.of(expectedLayout)); + + ApplicationLayout actualLayout = service.getApplicationLayout(user); + + assertThat(actualLayout).isEqualTo(expectedLayout); + } + + @Test + public void createApplicationLayout_validDefinition_callsRepoSave() throws JsonProcessingException { + String user = "user"; + JsonNode definition = objectMapper.readTree("{\"id\":\"main-tabs\"}"); + + service.persistApplicationLayout(user, definition); + + verify(mockRepo, times(1)) + .save(new ApplicationLayout(user, definition)); + } + + @Test + public void createApplicationLayout_invalidDefinition_throwsJsonException() { + String definition = "invalid JSON"; + + assertThrows(JsonProcessingException.class, () -> + service.persistApplicationLayout("user", objectMapper.readTree(definition)) + ); + } + + @Test + public void deleteApplicationLayout_entryExists_callsRepoDelete() { + String user = "user"; + + service.deleteApplicationLayout(user); + + verify(mockRepo, times(1)).deleteById(user); + } + + @Test + public void deleteApplicationLayout_deleteFails_throwsException() { + String user = "user"; + + doThrow(EmptyResultDataAccessException.class).when(mockRepo).deleteById(user); + + NoSuchElementException exception = assertThrows(NoSuchElementException.class, () -> + service.deleteApplicationLayout(user) + ); + + assertThat(exception.getMessage()).isEqualTo("No layout found for user: " + user); + } +} diff --git a/layout-server/src/test/java/org/finos/vuu/layoutserver/service/LayoutServiceTest.java b/layout-server/src/test/java/org/finos/vuu/layoutserver/service/LayoutServiceTest.java index f7a0bfd43..21d38a671 100644 --- a/layout-server/src/test/java/org/finos/vuu/layoutserver/service/LayoutServiceTest.java +++ b/layout-server/src/test/java/org/finos/vuu/layoutserver/service/LayoutServiceTest.java @@ -1,15 +1,5 @@ package org.finos.vuu.layoutserver.service; -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.List; -import java.util.NoSuchElementException; -import java.util.Optional; -import java.util.UUID; import org.finos.vuu.layoutserver.model.BaseMetadata; import org.finos.vuu.layoutserver.model.Layout; import org.finos.vuu.layoutserver.model.Metadata; @@ -20,84 +10,99 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.dao.EmptyResultDataAccessException; + +import java.util.NoSuchElementException; +import java.util.Optional; +import java.util.UUID; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) class LayoutServiceTest { - @Mock - private LayoutRepository layoutRepository; + private static final UUID LAYOUT_ID = UUID.randomUUID(); @Mock - private MetadataService metadataService; + private LayoutRepository layoutRepository; @InjectMocks private LayoutService layoutService; private Layout layout; - private Metadata metadata; - private UUID layoutId; @BeforeEach public void setup() { - UUID metadataId = UUID.randomUUID(); BaseMetadata baseMetadata = new BaseMetadata(); - metadata = new Metadata(); - layout = new Layout(); - baseMetadata.setName("Test Name"); baseMetadata.setGroup("Test Group"); baseMetadata.setScreenshot("Test Screenshot"); baseMetadata.setUser("Test User"); - metadata.setId(metadataId); - metadata.setBaseMetadata(baseMetadata); + Metadata metadata = Metadata.builder().id(LAYOUT_ID).baseMetadata(baseMetadata).build(); - layout.setDefinition(""); + layout = new Layout(); layout.setMetadata(metadata); + layout.setId(LAYOUT_ID); + layout.setDefinition(""); } @Test - void getLayout_returnsLayout() { - when(layoutRepository.findById(layoutId)).thenReturn(Optional.of(layout)); + void getLayout_layoutExists_returnsLayout() { + when(layoutRepository.findById(LAYOUT_ID)).thenReturn(Optional.of(layout)); - assertThat(layoutService.getLayout(layoutId)).isEqualTo(layout); + assertThat(layoutService.getLayout(LAYOUT_ID)).isEqualTo(layout); } @Test - void getMetadata_returnsMetadata() { - when(metadataService.getMetadata()).thenReturn(List.of(metadata)); + void getLayout_noLayoutsExist_throwsNotFoundException() { + when(layoutRepository.findById(LAYOUT_ID)).thenReturn(Optional.empty()); - assertThat(layoutService.getMetadata()).isEqualTo(List.of(metadata)); + assertThrows(NoSuchElementException.class, + () -> layoutService.getLayout(LAYOUT_ID)); } @Test - void createLayout_returnsLayout() { + void createLayout_anyLayout_returnsNewLayout() { when(layoutRepository.save(layout)).thenReturn(layout); assertThat(layoutService.createLayout(layout)).isEqualTo(layout); } @Test - void updateLayout_layoutExists_callsRepository() { - when(layoutRepository.findById(layoutId)).thenReturn(Optional.of(layout)); + void updateLayout_layoutExists_callsRepositorySave() { + when(layoutRepository.findById(LAYOUT_ID)).thenReturn(Optional.of(layout)); - layoutService.updateLayout(layoutId, layout); + layoutService.updateLayout(LAYOUT_ID, layout); verify(layoutRepository, times(1)).save(layout); } @Test void updateLayout_layoutDoesNotExist_throwsNoSuchElementException() { - when(layoutRepository.findById(layoutId)).thenReturn(Optional.empty()); + when(layoutRepository.findById(LAYOUT_ID)).thenReturn(Optional.empty()); assertThrows(NoSuchElementException.class, - () -> layoutService.updateLayout(layoutId, layout)); + () -> layoutService.updateLayout(LAYOUT_ID, layout)); } @Test - void deleteLayout_callsRepository() { - layoutService.deleteLayout(layoutId); + void deleteLayout_anyUUID_callsRepositoryDeleteById() { + layoutService.deleteLayout(LAYOUT_ID); + + verify(layoutRepository, times(1)).deleteById(LAYOUT_ID); + } + + @Test + void deleteLayout_noLayoutExists_throwsNoSuchElementException() { + doThrow(new EmptyResultDataAccessException(1)) + .when(layoutRepository).deleteById(LAYOUT_ID); + + assertThrows(NoSuchElementException.class, + () -> layoutService.deleteLayout(LAYOUT_ID)); - verify(layoutRepository, times(1)).deleteById(layoutId); + verify(layoutRepository, times(1)).deleteById(LAYOUT_ID); } } \ No newline at end of file diff --git a/layout-server/src/test/java/org/finos/vuu/layoutserver/service/MetadataServiceTest.java b/layout-server/src/test/java/org/finos/vuu/layoutserver/service/MetadataServiceTest.java new file mode 100644 index 000000000..74bbb4844 --- /dev/null +++ b/layout-server/src/test/java/org/finos/vuu/layoutserver/service/MetadataServiceTest.java @@ -0,0 +1,38 @@ +package org.finos.vuu.layoutserver.service; + +import org.finos.vuu.layoutserver.model.Metadata; +import org.finos.vuu.layoutserver.repository.MetadataRepository; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.List; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class MetadataServiceTest { + + @Mock + private MetadataRepository metadataRepository; + + @InjectMocks + private MetadataService metadataService; + + @Test + void getMetadata_metadataExists_returnsMetadata() { + Metadata metadata = Metadata.builder().build(); + + when(metadataRepository.findAll()).thenReturn(List.of(metadata)); + assertThat(metadataService.getMetadata()).isEqualTo(List.of(metadata)); + } + + @Test + void getMetadata_noMetadataExists_returnsEmptyList() { + when(metadataRepository.findAll()).thenReturn(List.of()); + assertThat(metadataService.getMetadata()).isEqualTo(List.of()); + } +} \ No newline at end of file diff --git a/layout-server/src/test/resources/defaultApplicationLayout.json b/layout-server/src/test/resources/defaultApplicationLayout.json new file mode 100644 index 000000000..87a79e544 --- /dev/null +++ b/layout-server/src/test/resources/defaultApplicationLayout.json @@ -0,0 +1,3 @@ +{ + "defaultLayoutKey": "default-layout-value" +} diff --git a/vuu-ui/cypress/support/component/index.css b/vuu-ui/cypress/support/component/index.css index 482c95234..f8371ced6 100644 --- a/vuu-ui/cypress/support/component/index.css +++ b/vuu-ui/cypress/support/component/index.css @@ -1,2 +1,2 @@ -.vuu-purple-theme{color:var(--salt-text-primary-foreground);font-family:var(--salt-typography-fontFamily);font-size:var(--salt-text-fontSize);letter-spacing:var(--salt-text-letterSpacing);line-height:var(--salt-text-lineHeight);--vuuMenuItem-height: 21px;--vuuMenuItem-borderColor: #EDEDED;--vuuMenuItem-borderStyle: none none solid none;--vuuMenuList-borderColor: #6D18BD;--vuuMenuList-color: #606477;--vuuMenuList-fontSize: 12px;--vuuMenuList-padding: 8px}.vuu-purple-theme[data-mode=light]{color-scheme:light}.vuu-purple-theme[data-mode=dark]{color-scheme:dark}*,*:before,*:after{box-sizing:border-box}.vuu-purple-density-touch,.vuu-purple-density-low,.vuu-purple-density-medium,.vuu-purple-density-high{--salt-animation-opacity-start: 0;--salt-animation-opacity-end: 1;--salt-animation-scale-start: 0;--salt-animation-scale-end: 1;--salt-animation-transform-start: 100%;--salt-animation-transform-end: 0;--salt-animation-duration: .3s;--salt-animation-timing-function: ease-in;--salt-animation-slide-in-top: slide-in-top var(--salt-animation-duration) var(--salt-animation-timing-function);--salt-animation-slide-in-left: slide-in-left var(--salt-animation-duration) var(--salt-animation-timing-function);--salt-animation-slide-in-right: slide-in-right var(--salt-animation-duration) var(--salt-animation-timing-function);--salt-animation-slide-in-bottom: slide-in-bottom var(--salt-animation-duration) var(--salt-animation-timing-function);--salt-animation-slide-out-top: slide-out-top var(--salt-animation-duration) var(--salt-animation-timing-function);--salt-animation-slide-out-left: slide-out-left var(--salt-animation-duration) var(--salt-animation-timing-function);--salt-animation-slide-out-right: slide-out-right var(--salt-animation-duration) var(--salt-animation-timing-function);--salt-animation-slide-out-bottom: slide-out-bottom var(--salt-animation-duration) var(--salt-animation-timing-function);--salt-animation-fade-in-back: fade-in-back var(--salt-animation-duration) var(--salt-animation-timing-function);--salt-animation-fade-in-forward: fade-in-forward var(--salt-animation-duration) var(--salt-animation-timing-function);--salt-animation-fade-in-center: fade-in-center var(--salt-animation-duration) var(--salt-animation-timing-function);--salt-animation-fade-out-back: fade-out-back var(--salt-animation-duration) ease-out both}@keyframes slide-in-top{0%{opacity:var(--salt-animation-opacity-start);transform:translateY(var(--salt-animation-transform-start))}to{opacity:var(--salt-animation-opacity-end);transform:translateY(var(--salt-animation-transform-end))}}@keyframes slide-out-top{0%{opacity:var(--salt-animation-opacity-end);transform:translateY(var(--salt-animation-transform-end))}to{opacity:var(--salt-animation-opacity-start);transform:translateY(var(--salt-animation-transform-start))}}@keyframes slide-in-left{0%{opacity:var(--salt-animation-opacity-start);transform:translate(calc(-1 * var(--salt-animation-transform-start)))}to{opacity:var(--salt-animation-opacity-end);transform:translate(var(--salt-animation-transform-end))}}@keyframes slide-out-left{0%{opacity:var(--salt-animation-opacity-end);transform:translate(var(--salt-animation-transform-end))}to{opacity:var(--salt-animation-opacity-start);transform:translate(calc(-1 * var(--salt-animation-transform-start)))}}@keyframes slide-in-right{0%{opacity:var(--salt-animation-opacity-start);transform:translate(var(--salt-animation-transform-start))}to{opacity:var(--salt-animation-opacity-end);transform:translate(var(--salt-animation-transform-end))}}@keyframes slide-out-right{0%{opacity:var(--salt-animation-opacity-end);transform:translate(var(--salt-animation-transform-end))}to{opacity:var(--salt-animation-opacity-start);transform:translate(var(--salt-animation-transform-start))}}@keyframes slide-in-bottom{0%{opacity:var(--salt-animation-opacity-start);transform:translateY(calc(-1 * var(--salt-animation-transform-start)))}to{opacity:var(--salt-animation-opacity-end);transform:translateY(var(--salt-animation-transform-end))}}@keyframes slide-out-bottom{0%{opacity:var(--salt-animation-opacity-end);transform:translateY(var(--salt-animation-transform-end))}to{opacity:var(--salt-animation-opacity-start);transform:translateY(calc(-1 * var(--salt-animation-transform-start)))}}@keyframes fade-in-back{0%{--salt-animation-scale-start: 1.4;opacity:var(--salt-animation-opacity-start);transform:scale(var(--salt-animation-scale-start))}to{opacity:var(--salt-animation-opacity-end);transform:scale(var(--salt-animation-scale-end))}}@keyframes fade-in-forward{0%{--salt-animation-scale-start: .6;opacity:var(--salt-animation-opacity-start);transform:scale(var(--salt-animation-scale-start))}to{opacity:var(--salt-animation-opacity-end);transform:scale(var(--salt-animation-scale-end))}}@keyframes fade-in-center{0%{opacity:var(--salt-animation-opacity-start)}to{opacity:var(--salt-animation-opacity-end)}}@keyframes fade-out-back{0%{opacity:var(--salt-animation-opacity-end)}to{opacity:var(--salt-animation-opacity-start)}}.vuu-purple-theme{--salt-color-white: rgb(255, 255, 255);--salt-color-black: rgb(0, 0, 0);--salt-color-red-10: rgb(255, 227, 224);--salt-color-red-20: rgb(255, 207, 201);--salt-color-red-30: rgb(255, 187, 178);--salt-color-red-40: rgb(255, 167, 156);--salt-color-red-50: rgb(255, 148, 133);--salt-color-red-100: rgb(255, 128, 111);--salt-color-red-200: rgb(255, 108, 88);--salt-color-red-300: rgb(255, 89, 66);--salt-color-red-400: rgb(237, 65, 42);--salt-color-red-500: rgb(227, 43, 22);--salt-color-red-600: rgb(196, 32, 16);--salt-color-red-700: rgb(166, 21, 11);--salt-color-red-800: rgb(136, 10, 5);--salt-color-red-900: rgb(65, 37, 34);--salt-color-orange-10: rgb(255, 232, 191);--salt-color-orange-20: rgb(254, 223, 166);--salt-color-orange-30: rgb(254, 214, 142);--salt-color-orange-40: rgb(254, 205, 118);--salt-color-orange-50: rgb(254, 197, 94);--salt-color-orange-100: rgb(250, 181, 81);--salt-color-orange-200: rgb(246, 165, 68);--salt-color-orange-300: rgb(242, 149, 56);--salt-color-orange-400: rgb(238, 133, 43);--salt-color-orange-500: rgb(234, 115, 25);--salt-color-orange-600: rgb(224, 101, 25);--salt-color-orange-700: rgb(214, 85, 19);--salt-color-orange-800: rgb(204, 68, 13);--salt-color-orange-900: rgb(54, 44, 36);--salt-color-green-10: rgb(209, 244, 201);--salt-color-green-20: rgb(184, 232, 182);--salt-color-green-30: rgb(160, 221, 164);--salt-color-green-40: rgb(136, 210, 145);--salt-color-green-50: rgb(112, 199, 127);--salt-color-green-100: rgb(93, 189, 116);--salt-color-green-200: rgb(77, 180, 105);--salt-color-green-300: rgb(60, 171, 96);--salt-color-green-400: rgb(48, 156, 90);--salt-color-green-500: rgb(36, 135, 75);--salt-color-green-600: rgb(24, 114, 61);--salt-color-green-700: rgb(12, 93, 46);--salt-color-green-800: rgb(1, 73, 32);--salt-color-green-900: rgb(35, 52, 43);--salt-color-teal-10: rgb(218, 240, 240);--salt-color-teal-20: rgb(199, 232, 232);--salt-color-teal-30: rgb(180, 224, 225);--salt-color-teal-40: rgb(162, 217, 218);--salt-color-teal-50: rgb(141, 205, 209);--salt-color-teal-100: rgb(123, 193, 200);--salt-color-teal-200: rgb(99, 181, 192);--salt-color-teal-300: rgb(73, 160, 172);--salt-color-teal-400: rgb(48, 149, 166);--salt-color-teal-500: rgb(0, 130, 151);--salt-color-teal-600: rgb(27, 107, 133);--salt-color-teal-700: rgb(0, 85, 113);--salt-color-teal-800: rgb(1, 65, 86);--salt-color-teal-900: rgb(0, 49, 76);--salt-color-blue-10: rgb(203, 231, 249);--salt-color-blue-20: rgb(183, 222, 246);--salt-color-blue-30: rgb(164, 213, 244);--salt-color-blue-40: rgb(144, 204, 242);--salt-color-blue-50: rgb(125, 195, 240);--salt-color-blue-100: rgb(100, 177, 228);--salt-color-blue-200: rgb(75, 159, 216);--salt-color-blue-300: rgb(51, 141, 205);--salt-color-blue-400: rgb(46, 132, 198);--salt-color-blue-500: rgb(38, 112, 169);--salt-color-blue-600: rgb(21, 92, 147);--salt-color-blue-700: rgb(0, 71, 123);--salt-color-blue-800: rgb(39, 60, 77);--salt-color-blue-900: rgb(35, 47, 56);--salt-color-purple-10: rgb(249, 224, 247);--salt-color-purple-20: rgb(247, 212, 244);--salt-color-purple-30: rgb(245, 201, 241);--salt-color-purple-40: rgb(243, 189, 238);--salt-color-purple-50: rgb(241, 178, 235);--salt-color-purple-100: rgb(223, 156, 225);--salt-color-purple-200: rgb(205, 135, 215);--salt-color-purple-300: rgb(192, 116, 203);--salt-color-purple-400: rgb(169, 97, 181);--salt-color-purple-500: rgb(150, 78, 162);--salt-color-purple-600: rgb(129, 60, 141);--salt-color-purple-700: rgb(103, 46, 122);--salt-color-purple-800: rgb(83, 37, 109);--salt-color-purple-900: rgb(59, 16, 84);--salt-color-gray-10: rgb(242, 244, 246);--salt-color-gray-20: rgb(234, 237, 239);--salt-color-gray-30: rgb(224, 228, 233);--salt-color-gray-40: rgb(217, 221, 227);--salt-color-gray-50: rgb(206, 210, 217);--salt-color-gray-60: rgb(197, 201, 208);--salt-color-gray-70: rgb(180, 183, 190);--salt-color-gray-80: rgb(159, 163, 170);--salt-color-gray-90: rgb(132, 135, 142);--salt-color-gray-100: rgb(116, 119, 127);--salt-color-gray-200: rgb(97, 101, 110);--salt-color-gray-300: rgb(76, 80, 91);--salt-color-gray-400: rgb(68, 72, 79);--salt-color-gray-500: rgb(59, 63, 70);--salt-color-gray-600: rgb(47, 49, 54);--salt-color-gray-700: rgb(42, 44, 47);--salt-color-gray-800: rgb(36, 37, 38);--salt-color-gray-900: rgb(21, 23, 27)}.vuu-purple-theme{--salt-delay-instant: 100;--salt-delay-perceptible: 300;--salt-delay-notable: 1000;--salt-delay-cutoff: 10000}.vuu-purple-theme{--salt-color-blue-100-fade-foreground: rgba(100, 177, 228, var(--salt-palette-opacity-foreground));--salt-color-blue-600-fade-foreground: rgba(21, 92, 147, var(--salt-palette-opacity-foreground));--salt-color-gray-70-fade-foreground: rgba(180, 183, 190, var(--salt-palette-opacity-foreground));--salt-color-gray-200-fade-foreground: rgba(97, 101, 110, var(--salt-palette-opacity-foreground));--salt-color-gray-90-fade-foreground: rgba(132, 135, 142, var(--salt-palette-opacity-foreground));--salt-color-gray-900-fade-foreground: rgba(22, 22, 22, var(--salt-palette-opacity-foreground));--salt-color-white-fade-foreground: rgba(255, 255, 255, var(--salt-palette-opacity-foreground));--salt-color-gray-60-fade-border: rgba(197, 201, 208, var(--salt-palette-opacity-border));--salt-color-gray-90-fade-border: rgba(132, 135, 142, var(--salt-palette-opacity-border));--salt-color-gray-200-fade-border: rgba(97, 101, 110, var(--salt-palette-opacity-border));--salt-color-gray-300-fade-border: rgba(76, 80, 91, var(--salt-palette-opacity-border));--salt-color-orange-400-fade-border: rgba(238, 133, 43, var(--salt-palette-opacity-border));--salt-color-orange-600-fade-border: rgba(224, 101, 25, var(--salt-palette-opacity-border));--salt-color-gray-90-fade-border-readonly: rgba(132, 135, 142, var(--salt-palette-opacity-border-readonly));--salt-color-gray-200-fade-border-readonly: rgba(97, 101, 110, var(--salt-palette-opacity-border-readonly));--salt-color-blue-600-fade-background: rgba(21, 92, 147, var(--salt-palette-opacity-background));--salt-color-blue-700-fade-background: rgba(0, 71, 123, var(--salt-palette-opacity-background));--salt-color-gray-20-fade-background: rgba(234, 237, 239, var(--salt-palette-opacity-background));--salt-color-gray-60-fade-background: rgba(197, 201, 208, var(--salt-palette-opacity-background));--salt-color-gray-70-fade-background: rgba(180, 183, 190, var(--salt-palette-opacity-background));--salt-color-gray-200-fade-background: rgba(97, 101, 110, var(--salt-palette-opacity-background));--salt-color-gray-300-fade-background: rgba(76, 80, 91, var(--salt-palette-opacity-background));--salt-color-gray-600-fade-background: rgba(47, 49, 54, var(--salt-palette-opacity-background));--salt-color-gray-800-fade-background: rgba(36, 37, 38, var(--salt-palette-opacity-background));--salt-color-orange-400-fade-background: rgba(238, 133, 43, var(--salt-palette-opacity-background));--salt-color-orange-600-fade-background: rgba(224, 101, 25, var(--salt-palette-opacity-background));--salt-color-white-fade-background: rgba(255, 255, 255, var(--salt-palette-opacity-background));--salt-color-white-fade-background-readonly: rgba(255, 255, 255, var(--salt-palette-opacity-readonly));--salt-color-gray-20-fade-background-readonly: rgba(234, 237, 239, var(--salt-palette-opacity-readonly));--salt-color-gray-600-fade-background-readonly: rgba(47, 49, 54, var(--salt-palette-opacity-readonly));--salt-color-gray-800-fade-background-readonly: rgba(36, 37, 38, var(--salt-palette-opacity-readonly));--salt-color-black-fade-backdrop: rgba(36, 37, 38, var(--salt-palette-opacity-backdrop));--salt-color-blue-100-fade-fill: rgba(100, 177, 228, var(--salt-palette-opacity-fill));--salt-color-blue-300-fade-fill: rgba(51, 141, 205, var(--salt-palette-opacity-fill));--salt-color-blue-500-fade-fill: rgba(38, 112, 169, var(--salt-palette-opacity-fill));--salt-color-blue-600-fade-fill: rgba(21, 92, 147, var(--salt-palette-opacity-fill));--salt-color-white-fade-separatorOpacity-primary: rgba(255, 255, 255, var(--salt-palette-opacity-primary-border));--salt-color-white-fade-separatorOpacity-secondary: rgba(255, 255, 255, var(--salt-palette-opacity-secondary-border));--salt-color-white-fade-separatorOpacity-tertiary: rgba(255, 255, 255, var(--salt-palette-opacity-tertiary-border));--salt-color-black-fade-separatorOpacity-primary: rgba(0, 0, 0, var(--salt-palette-opacity-primary-border));--salt-color-black-fade-separatorOpacity-secondary: rgba(0, 0, 0, var(--salt-palette-opacity-secondary-border));--salt-color-black-fade-separatorOpacity-tertiary: rgba(0, 0, 0, var(--salt-palette-opacity-tertiary-border))}.vuu-purple-density-touch{--salt-size-icon-base: 16px}.vuu-purple-density-low{--salt-size-icon-base: 14px}.vuu-purple-density-medium{--salt-size-icon-base: 12px}.vuu-purple-density-high{--salt-size-icon-base: 10px}.vuu-purple-theme{--salt-opacity-1: .15;--salt-opacity-2: .25;--salt-opacity-3: .4;--salt-opacity-4: .7}.vuu-purple-theme[data-mode=light]{--salt-shadow-1-color: rgba(0, 0, 0, .1);--salt-shadow-2-color: rgba(0, 0, 0, .1);--salt-shadow-3-color: rgba(0, 0, 0, .15);--salt-shadow-4-color: rgba(0, 0, 0, .2);--salt-shadow-5-color: rgba(0, 0, 0, .3)}.vuu-purple-theme[data-mode=dark]{--salt-shadow-1-color: rgba(0, 0, 0, .5);--salt-shadow-2-color: rgba(0, 0, 0, .5);--salt-shadow-3-color: rgba(0, 0, 0, .55);--salt-shadow-4-color: rgba(0, 0, 0, .55);--salt-shadow-5-color: rgba(0, 0, 0, .65)}.vuu-purple-theme{--salt-shadow-0: none;--salt-shadow-1: 0 1px 3px 0 var(--salt-shadow-1-color);--salt-shadow-2: 0 2px 4px 0 var(--salt-shadow-2-color);--salt-shadow-3: 0 4px 8px 0 var(--salt-shadow-3-color);--salt-shadow-4: 0 6px 10px 0 var(--salt-shadow-4-color);--salt-shadow-5: 0 12px 40px 5px var(--salt-shadow-5-color)}.vuu-purple-density-touch,.vuu-purple-density-low,.vuu-purple-density-medium,.vuu-purple-density-high{--salt-size-basis-unit: 4px;--salt-size-border: 1px;--salt-size-brandBar: 4px;--salt-size-divider-strokeWidth: 1px;--salt-size-sharktooth-height: 5px;--salt-size-sharktooth-width: 10px;--salt-size-divider-height: calc(var(--salt-size-base) - (1.5 * var(--salt-size-unit)) - (.5 * var(--salt-size-basis-unit)));--salt-size-selection: calc(var(--salt-size-base) - (1.5 * var(--salt-size-unit)) - (.5 * var(--salt-size-basis-unit)));--salt-size-stackable: calc(var(--salt-size-base) + var(--salt-size-unit));--salt-size-graphic-small: 12px;--salt-size-graphic-medium: 24px;--salt-size-graphic-large: 48px}.vuu-purple-density-high{--salt-size-unit: calc(var(--salt-size-basis-unit) * 1);--salt-size-detail: calc(var(--salt-size-basis-unit) * 1.5);--salt-size-base: calc(var(--salt-size-basis-unit) * 5)}.vuu-purple-density-medium{--salt-size-unit: calc(var(--salt-size-basis-unit) * 2);--salt-size-detail: calc(var(--salt-size-basis-unit) * 2);--salt-size-base: calc(var(--salt-size-basis-unit) * 7)}.vuu-purple-density-low{--salt-size-unit: calc(var(--salt-size-basis-unit) * 3);--salt-size-detail: calc(var(--salt-size-basis-unit) * 2.5);--salt-size-base: calc(var(--salt-size-basis-unit) * 9)}.vuu-purple-density-touch{--salt-size-unit: calc(var(--salt-size-basis-unit) * 4);--salt-size-detail: calc(var(--salt-size-basis-unit) * 3);--salt-size-base: calc(var(--salt-size-basis-unit) * 11)}.vuu-purple-theme{--salt-typography-fontFamily: "Nunito Sans";--salt-typography-fontFamily-code: "PT Mono";--salt-typography-fontWeight-light: 300;--salt-typography-fontWeight-regular: 400;--salt-typography-fontWeight-medium: 500;--salt-typography-fontWeight-semiBold: 600;--salt-typography-fontWeight-bold: 700;--salt-typography-fontWeight-extraBold: 800}.vuu-purple-density-touch,.vuu-purple-density-low,.vuu-purple-density-medium,.vuu-purple-density-high{--salt-zIndex-default: 1;--salt-zIndex-popout: 1000;--salt-zIndex-docked: 1050;--salt-zIndex-appHeader: 1100;--salt-zIndex-drawer: 1200;--salt-zIndex-modal: 1300;--salt-zIndex-notification: 1400;--salt-zIndex-dragObject: 1420;--salt-zIndex-contextMenu: 1450;--salt-zIndex-flyover: 1500}.vuu-purple-theme{--salt-palette-opacity-background: var(--salt-opacity-3);--salt-palette-opacity-border: var(--salt-opacity-3);--salt-palette-opacity-border-readonly: var(--salt-opacity-2);--salt-palette-opacity-fill: var(--salt-opacity-3);--salt-palette-opacity-foreground: var(--salt-opacity-4);--salt-palette-opacity-backdrop: var(--salt-opacity-3);--salt-palette-opacity-stroke: var(--salt-opacity-3);--salt-palette-opacity-primary-border: var(--salt-opacity-3);--salt-palette-opacity-secondary-border: var(--salt-opacity-2);--salt-palette-opacity-tertiary-border: var(--salt-opacity-1)}.vuu-purple-theme[data-mode=light]{--salt-palette-accent-background: var(--salt-color-blue-500);--salt-palette-accent-border: var(--salt-color-blue-500);--salt-palette-accent-foreground: var(--salt-color-white);--salt-palette-interact-background: transparent;--salt-palette-interact-background-blurSelected: var(--salt-color-gray-30);--salt-palette-interact-background-hover: var(--salt-color-blue-10);--salt-palette-interact-background-active: var(--salt-color-blue-30);--salt-palette-interact-background-disabled: transparent;--salt-palette-interact-border: var(--salt-color-gray-200);--salt-palette-interact-border-active: var(--salt-color-blue-600);--salt-palette-interact-border-activeDisabled: var(--salt-color-blue-600-fade-fill);--salt-palette-interact-border-disabled: var(--salt-color-gray-200-fade-border);--salt-palette-interact-border-hover: var(--salt-color-blue-500);--salt-palette-interact-border-readonly: var(--salt-color-gray-200-fade-border-readonly);--salt-palette-interact-foreground: var(--salt-color-gray-900);--salt-palette-interact-foreground-disabled: var(--salt-color-gray-900-fade-foreground);--salt-palette-interact-foreground-partial: var(--salt-color-blue-600);--salt-palette-interact-foreground-partialDisabled: var(--salt-color-blue-600-fade-foreground);--salt-palette-interact-outline: var(--salt-color-blue-600);--salt-palette-interact-cta-background: var(--salt-color-blue-600);--salt-palette-interact-cta-background-active: var(--salt-color-blue-700);--salt-palette-interact-cta-background-activeDisabled: var(--salt-color-blue-700-fade-background);--salt-palette-interact-cta-background-disabled: var(--salt-color-blue-600-fade-background);--salt-palette-interact-cta-background-hover: var(--salt-color-blue-500);--salt-palette-interact-cta-foreground: var(--salt-color-white);--salt-palette-interact-cta-foreground-active: var(--salt-color-white);--salt-palette-interact-cta-foreground-activeDisabled: var(--salt-color-white-fade-foreground);--salt-palette-interact-cta-foreground-disabled: var(--salt-color-white-fade-foreground);--salt-palette-interact-cta-foreground-hover: var(--salt-color-white);--salt-palette-interact-primary-background: var(--salt-color-gray-60);--salt-palette-interact-primary-background-active: var(--salt-color-gray-200);--salt-palette-interact-primary-background-activeDisabled: var(--salt-color-gray-200-fade-background);--salt-palette-interact-primary-background-disabled: var(--salt-color-gray-60-fade-background);--salt-palette-interact-primary-background-hover: var(--salt-color-gray-40);--salt-palette-interact-primary-foreground: var(--salt-color-gray-900);--salt-palette-interact-primary-foreground-active: var(--salt-color-white);--salt-palette-interact-primary-foreground-activeDisabled: var(--salt-color-white-fade-foreground);--salt-palette-interact-primary-foreground-disabled: var(--salt-color-gray-900-fade-foreground);--salt-palette-interact-primary-foreground-hover: var(--salt-color-gray-900);--salt-palette-interact-secondary-background: transparent;--salt-palette-interact-secondary-background-active: var(--salt-color-gray-200);--salt-palette-interact-secondary-background-activeDisabled: var(--salt-color-gray-200-fade-background);--salt-palette-interact-secondary-background-disabled: transparent;--salt-palette-interact-secondary-background-hover: var(--salt-color-gray-40);--salt-palette-interact-secondary-foreground: var(--salt-color-gray-900);--salt-palette-interact-secondary-foreground-active: var(--salt-color-white);--salt-palette-interact-secondary-foreground-activeDisabled: var(--salt-color-white-fade-foreground);--salt-palette-interact-secondary-foreground-disabled: var(--salt-color-gray-900-fade-foreground);--salt-palette-interact-secondary-foreground-hover: var(--salt-color-gray-900);--salt-palette-error-background-emphasize: var(--salt-color-red-10);--salt-palette-error-border: var(--salt-color-red-500);--salt-palette-error-foreground: var(--salt-color-red-500);--salt-palette-info-background-emphasize: var(--salt-color-blue-10);--salt-palette-info-border: var(--salt-color-blue-500);--salt-palette-info-foreground: var(--salt-color-blue-500);--salt-palette-success-background-emphasize: var(--salt-color-green-10);--salt-palette-success-border: var(--salt-color-green-500);--salt-palette-success-foreground: var(--salt-color-green-500);--salt-palette-warning-background-emphasize: var(--salt-color-orange-10);--salt-palette-warning-border: var(--salt-color-orange-500);--salt-palette-warning-foreground: var(--salt-color-orange-500);--salt-palette-measured-fill: var(--salt-color-blue-500);--salt-palette-measured-fill-disabled: var(--salt-color-blue-500-fade-fill);--salt-palette-measured-foreground: var(--salt-color-gray-90);--salt-palette-measured-foreground-active: var(--salt-color-blue-500);--salt-palette-measured-foreground-disabled: var(--salt-color-gray-90-fade-foreground);--salt-palette-measured-foreground-activeDisabled: var(--salt-color-blue-500-fade-fill);--salt-palette-measured-background: var(--salt-color-gray-60);--salt-palette-measured-background-disabled: var(--salt-color-gray-60-fade-background);--salt-palette-measured-border: var(--salt-color-gray-90);--salt-palette-measured-border-disabled: var(--salt-color-gray-90-fade-border);--salt-palette-navigate-primary-background: transparent;--salt-palette-navigate-primary-background-active: transparent;--salt-palette-navigate-primary-background-hover: var(--salt-color-gray-20);--salt-palette-navigate-secondary-background: transparent;--salt-palette-navigate-secondary-background-active: transparent;--salt-palette-navigate-secondary-background-hover: var(--salt-color-gray-30);--salt-palette-navigate-tertiary-background: transparent;--salt-palette-navigate-tertiary-background-active: transparent;--salt-palette-navigate-tertiary-background-hover: var(--salt-color-gray-20);--salt-palette-navigate-foreground-hover: var(--salt-color-blue-600);--salt-palette-navigate-foreground-active: var(--salt-color-blue-700);--salt-palette-navigate-foreground-visited: var(--salt-color-purple-800);--salt-palette-navigate-indicator-hover: var(--salt-color-gray-90);--salt-palette-navigate-indicator-active: var(--salt-color-orange-600);--salt-palette-navigate-indicator-activeDisabled: var(--salt-color-orange-600-fade-border);--salt-palette-negative-background: var(--salt-color-red-40);--salt-palette-negative-foreground: var(--salt-color-red-700);--salt-palette-neutral-primary-background: var(--salt-color-white);--salt-palette-neutral-primary-background-disabled: var(--salt-color-white-fade-background);--salt-palette-neutral-primary-background-readonly: var(--salt-color-white-fade-background-readonly);--salt-palette-neutral-primary-foreground: var(--salt-color-gray-900);--salt-palette-neutral-primary-foreground-disabled: var(--salt-color-gray-900-fade-foreground);--salt-palette-neutral-primary-separator: var(--salt-color-black-fade-separatorOpacity-primary);--salt-palette-neutral-primary-border: var(--salt-color-gray-60);--salt-palette-neutral-primary-border-disabled: var(--salt-color-gray-60-fade-border);--salt-palette-neutral-secondary-background: var(--salt-color-gray-20);--salt-palette-neutral-secondary-background-disabled: var(--salt-color-gray-20-fade-background);--salt-palette-neutral-secondary-background-readonly: var(--salt-color-gray-20-fade-background-readonly);--salt-palette-neutral-secondary-border: var(--salt-color-gray-90);--salt-palette-neutral-secondary-border-disabled: var(--salt-color-gray-90-fade-border);--salt-palette-neutral-secondary-foreground: var(--salt-color-gray-200);--salt-palette-neutral-secondary-foreground-disabled: var(--salt-color-gray-200-fade-foreground);--salt-palette-neutral-backdrop: var(--salt-color-black-fade-backdrop);--salt-palette-neutral-secondary-separator: var(--salt-color-black-fade-separatorOpacity-secondary);--salt-palette-neutral-tertiary-background: transparent;--salt-palette-neutral-tertiary-background-disabled: transparent;--salt-palette-neutral-tertiary-background-readonly: transparent;--salt-palette-neutral-tertiary-border: transparent;--salt-palette-neutral-tertiary-border-disabled: transparent;--salt-palette-neutral-tertiary-separator: var(--salt-color-black-fade-separatorOpacity-tertiary);--salt-palette-positive-background: var(--salt-color-green-20);--salt-palette-positive-foreground: var(--salt-color-green-700)}.vuu-purple-theme[data-mode=dark]{--salt-palette-accent-background: var(--salt-color-blue-500);--salt-palette-accent-border: var(--salt-color-blue-500);--salt-palette-accent-foreground: var(--salt-color-white);--salt-palette-interact-background: transparent;--salt-palette-interact-background-active: var(--salt-color-blue-700);--salt-palette-interact-background-blurSelected: var(--salt-color-gray-600);--salt-palette-interact-background-hover: var(--salt-color-blue-800);--salt-palette-interact-background-disabled: transparent;--salt-palette-interact-border: var(--salt-color-gray-90);--salt-palette-interact-border-active: var(--salt-color-blue-100);--salt-palette-interact-border-activeDisabled: var(--salt-color-blue-100-fade-fill);--salt-palette-interact-border-disabled: var(--salt-color-gray-90-fade-border);--salt-palette-interact-border-hover: var(--salt-color-blue-500);--salt-palette-interact-border-readonly: var(--salt-color-gray-90-fade-border-readonly);--salt-palette-interact-foreground: var(--salt-color-white);--salt-palette-interact-foreground-disabled: var(--salt-color-white-fade-foreground);--salt-palette-interact-foreground-partial: var(--salt-color-blue-100);--salt-palette-interact-foreground-partialDisabled: var(--salt-color-blue-100-fade-foreground);--salt-palette-interact-outline: var(--salt-color-blue-100);--salt-palette-interact-cta-background: var(--salt-color-blue-600);--salt-palette-interact-cta-background-active: var(--salt-color-blue-700);--salt-palette-interact-cta-background-activeDisabled: var(--salt-color-blue-700-fade-background);--salt-palette-interact-cta-background-disabled: var(--salt-color-blue-600-fade-background);--salt-palette-interact-cta-background-hover: var(--salt-color-blue-500);--salt-palette-interact-cta-foreground: var(--salt-color-white);--salt-palette-interact-cta-foreground-active: var(--salt-color-white);--salt-palette-interact-cta-foreground-activeDisabled: var(--salt-color-white-fade-foreground);--salt-palette-interact-cta-foreground-disabled: var(--salt-color-white-fade-foreground);--salt-palette-interact-cta-foreground-hover: var(--salt-color-white);--salt-palette-interact-primary-background: var(--salt-color-gray-300);--salt-palette-interact-primary-background-active: var(--salt-color-gray-70);--salt-palette-interact-primary-background-activeDisabled: var(--salt-color-gray-70-fade-background);--salt-palette-interact-primary-background-disabled: var(--salt-color-gray-300-fade-background);--salt-palette-interact-primary-background-hover: var(--salt-color-gray-200);--salt-palette-interact-primary-foreground: var(--salt-color-white);--salt-palette-interact-primary-foreground-active: var(--salt-color-gray-900);--salt-palette-interact-primary-foreground-activeDisabled: var(--salt-color-gray-900-fade-foreground);--salt-palette-interact-primary-foreground-disabled: var(--salt-color-white-fade-foreground);--salt-palette-interact-primary-foreground-hover: var(--salt-color-white);--salt-palette-interact-secondary-background: transparent;--salt-palette-interact-secondary-background-active: var(--salt-color-gray-70);--salt-palette-interact-secondary-background-activeDisabled: var(--salt-color-gray-70-fade-background);--salt-palette-interact-secondary-background-disabled: transparent;--salt-palette-interact-secondary-background-hover: var(--salt-color-gray-200);--salt-palette-interact-secondary-foreground: var(--salt-color-white);--salt-palette-interact-secondary-foreground-active: var(--salt-color-gray-900);--salt-palette-interact-secondary-foreground-activeDisabled: var(--salt-color-gray-900-fade-foreground);--salt-palette-interact-secondary-foreground-disabled: var(--salt-color-white-fade-foreground);--salt-palette-interact-secondary-foreground-hover: var(--salt-color-white);--salt-palette-error-background-emphasize: var(--salt-color-red-900);--salt-palette-error-border: var(--salt-color-red-500);--salt-palette-error-foreground: var(--salt-color-red-500);--salt-palette-info-background-emphasize: var(--salt-color-blue-900);--salt-palette-info-border: var(--salt-color-blue-500);--salt-palette-info-foreground: var(--salt-color-blue-500);--salt-palette-success-background-emphasize: var(--salt-color-green-900);--salt-palette-success-border: var(--salt-color-green-500);--salt-palette-success-foreground: var(--salt-color-green-500);--salt-palette-warning-background-emphasize: var(--salt-color-orange-900);--salt-palette-warning-border: var(--salt-color-orange-500);--salt-palette-warning-foreground: var(--salt-color-orange-500);--salt-palette-measured-fill: var(--salt-color-blue-300);--salt-palette-measured-fill-disabled: var(--salt-color-blue-300-fade-fill);--salt-palette-measured-foreground: var(--salt-color-gray-90);--salt-palette-measured-foreground-active: var(--salt-color-blue-300);--salt-palette-measured-foreground-disabled: var(--salt-color-gray-90-fade-foreground);--salt-palette-measured-foreground-activeDisabled: var(--salt-color-blue-300-fade-fill);--salt-palette-measured-background: var(--salt-color-gray-300);--salt-palette-measured-background-disabled: var(--salt-color-gray-300-fade-background);--salt-palette-measured-border: var(--salt-color-gray-90);--salt-palette-measured-border-disabled: var(--salt-color-gray-90-fade-border);--salt-palette-navigate-primary-background: transparent;--salt-palette-navigate-primary-background-active: transparent;--salt-palette-navigate-primary-background-hover: var(--salt-color-gray-700);--salt-palette-navigate-secondary-background: transparent;--salt-palette-navigate-secondary-background-active: transparent;--salt-palette-navigate-secondary-background-hover: var(--salt-color-gray-600);--salt-palette-navigate-tertiary-background: transparent;--salt-palette-navigate-tertiary-background-active: transparent;--salt-palette-navigate-tertiary-background-hover: var(--salt-color-gray-700);--salt-palette-navigate-foreground-hover: var(--salt-color-blue-200);--salt-palette-navigate-foreground-active: var(--salt-color-blue-300);--salt-palette-navigate-foreground-visited: var(--salt-color-purple-100);--salt-palette-navigate-indicator-hover: var(--salt-color-gray-90);--salt-palette-navigate-indicator-active: var(--salt-color-orange-400);--salt-palette-navigate-indicator-activeDisabled: var(--salt-color-orange-400-fade-border);--salt-palette-negative-background: var(--salt-color-red-40);--salt-palette-negative-foreground: var(--salt-color-red-300);--salt-palette-neutral-primary-background: var(--salt-color-gray-800);--salt-palette-neutral-primary-background-disabled: var(--salt-color-gray-800-fade-background);--salt-palette-neutral-primary-background-readonly: var(--salt-color-gray-800-fade-background-readonly);--salt-palette-neutral-primary-border: var(--salt-color-gray-300);--salt-palette-neutral-primary-border-disabled: var(--salt-color-gray-300-fade-border);--salt-palette-neutral-primary-foreground: var(--salt-color-white);--salt-palette-neutral-primary-foreground-disabled: var(--salt-color-white-fade-foreground);--salt-palette-neutral-primary-separator: var(--salt-color-white-fade-separatorOpacity-primary);--salt-palette-neutral-secondary-background: var(--salt-color-gray-600);--salt-palette-neutral-secondary-background-disabled: var(--salt-color-gray-600-fade-background);--salt-palette-neutral-secondary-background-readonly: var(--salt-color-gray-600-fade-background-readonly);--salt-palette-neutral-secondary-border: var(--salt-color-gray-90);--salt-palette-neutral-secondary-border-disabled: var(--salt-color-gray-90-fade-border);--salt-palette-neutral-secondary-foreground: var(--salt-color-gray-70);--salt-palette-neutral-secondary-foreground-disabled: var(--salt-color-gray-70-fade-foreground);--salt-palette-neutral-backdrop: var(--salt-color-black-fade-backdrop);--salt-palette-neutral-secondary-separator: var(--salt-color-white-fade-separatorOpacity-secondary);--salt-palette-neutral-tertiary-background: transparent;--salt-palette-neutral-tertiary-background-disabled: transparent;--salt-palette-neutral-tertiary-background-readonly: transparent;--salt-palette-neutral-tertiary-border: transparent;--salt-palette-neutral-tertiary-border-disabled: transparent;--salt-palette-neutral-tertiary-separator: var(--salt-color-white-fade-separatorOpacity-tertiary);--salt-palette-positive-background: var(--salt-color-green-30);--salt-palette-positive-foreground: var(--salt-color-green-300)}.vuu-purple-density-high{--salt-accent-fontSize: 8px;--salt-accent-lineHeight: 11px}.vuu-purple-density-medium{--salt-accent-fontSize: 10px;--salt-accent-lineHeight: 13px}.vuu-purple-density-low{--salt-accent-fontSize: 12px;--salt-accent-lineHeight: 16px}.vuu-purple-density-touch{--salt-accent-fontSize: 14px;--salt-accent-lineHeight: 18px}.vuu-purple-theme{--salt-accent-background: var(--salt-palette-accent-background);--salt-accent-borderColor: var(--salt-palette-accent-border);--salt-accent-foreground: var(--salt-palette-accent-foreground);--salt-accent-fontWeight: var(--salt-typography-fontWeight-semiBold)}.vuu-purple-theme{--salt-actionable-cursor-hover: pointer;--salt-actionable-cursor-active: pointer;--salt-actionable-cursor-disabled: not-allowed;--salt-actionable-letterSpacing: .6px;--salt-actionable-textAlign: center;--salt-actionable-textTransform: uppercase;--salt-actionable-primary-foreground: var(--salt-palette-interact-primary-foreground);--salt-actionable-primary-foreground-hover: var(--salt-palette-interact-primary-foreground-hover);--salt-actionable-primary-foreground-active: var(--salt-palette-interact-primary-foreground-active);--salt-actionable-primary-foreground-disabled: var(--salt-palette-interact-primary-foreground-disabled);--salt-actionable-primary-background: var(--salt-palette-interact-primary-background);--salt-actionable-primary-background-hover: var(--salt-palette-interact-primary-background-hover);--salt-actionable-primary-background-active: var(--salt-palette-interact-primary-background-active);--salt-actionable-primary-background-disabled: var(--salt-palette-interact-primary-background-disabled);--salt-actionable-primary-fontWeight: var(--salt-typography-fontWeight-bold);--salt-actionable-cta-foreground: var(--salt-palette-interact-cta-foreground);--salt-actionable-cta-foreground-hover: var(--salt-palette-interact-cta-foreground-hover);--salt-actionable-cta-foreground-active: var(--salt-palette-interact-cta-foreground-active);--salt-actionable-cta-foreground-disabled: var(--salt-palette-interact-cta-foreground-disabled);--salt-actionable-cta-background: var(--salt-palette-interact-cta-background);--salt-actionable-cta-background-hover: var(--salt-palette-interact-cta-background-hover);--salt-actionable-cta-background-active: var(--salt-palette-interact-cta-background-active);--salt-actionable-cta-background-disabled: var(--salt-palette-interact-cta-background-disabled);--salt-actionable-cta-fontWeight: var(--salt-typography-fontWeight-bold);--salt-actionable-secondary-foreground: var(--salt-palette-interact-secondary-foreground);--salt-actionable-secondary-foreground-hover: var(--salt-palette-interact-secondary-foreground-hover);--salt-actionable-secondary-foreground-active: var(--salt-palette-interact-secondary-foreground-active);--salt-actionable-secondary-foreground-disabled: var(--salt-palette-interact-secondary-foreground-disabled);--salt-actionable-secondary-background: var(--salt-palette-interact-secondary-background);--salt-actionable-secondary-background-hover: var(--salt-palette-interact-secondary-background-hover);--salt-actionable-secondary-background-active: var(--salt-palette-interact-secondary-background-active);--salt-actionable-secondary-background-disabled: var(--salt-palette-interact-secondary-background-disabled);--salt-actionable-secondary-fontWeight: var(--salt-typography-fontWeight-semiBold)}.vuu-purple-theme{--salt-container-borderStyle: solid;--salt-container-primary-background: var(--salt-palette-neutral-primary-background);--salt-container-primary-background-disabled: var(--salt-palette-neutral-primary-background-disabled);--salt-container-primary-borderColor: var(--salt-palette-neutral-primary-border);--salt-container-primary-borderColor-disabled: var(--salt-palette-neutral-primary-border-disabled);--salt-container-secondary-background: var(--salt-palette-neutral-secondary-background);--salt-container-secondary-background-disabled: var(--salt-palette-neutral-secondary-background-disabled);--salt-container-secondary-borderColor: var(--salt-palette-neutral-secondary-border);--salt-container-secondary-borderColor-disabled: var(--salt-palette-neutral-secondary-border-disabled);--salt-container-tertiary-background: var(--salt-palette-neutral-tertiary-background);--salt-container-tertiary-background-disabled: var(--salt-palette-neutral-tertiary-background-disabled);--salt-container-tertiary-borderColor: var(--salt-palette-neutral-tertiary-border);--salt-container-tertiary-borderColor-disabled: var(--salt-palette-neutral-tertiary-border-disabled)}.vuu-purple-theme{--salt-differential-positive-background: var(--salt-palette-positive-background);--salt-differential-negative-background: var(--salt-palette-negative-background);--salt-differential-positive-foreground: var(--salt-palette-positive-foreground);--salt-differential-negative-foreground: var(--salt-palette-negative-foreground)}.vuu-purple-theme{--salt-draggable-horizontal-cursor-hover: row-resize;--salt-draggable-horizontal-cursor-active: row-resize;--salt-draggable-vertical-cursor-hover: col-resize;--salt-draggable-vertical-cursor-active: col-resize;--salt-draggable-grab-cursor-hover: grab;--salt-draggable-grab-cursor-active: grabbing}.vuu-purple-theme{--salt-target-background-hover: var(--salt-palette-interact-background-hover);--salt-target-borderColor-hover: var(--salt-palette-interact-border-hover);--salt-target-borderStyle: dashed;--salt-target-borderStyle-hover: solid;--salt-target-borderStyle-disabled: dashed;--salt-target-cursor-disabled: not-allowed}.vuu-purple-theme{--salt-editable-cursor-hover: text;--salt-editable-cursor-active: text;--salt-editable-cursor-disabled: not-allowed;--salt-editable-cursor-readonly: text;--salt-editable-borderStyle: solid;--salt-editable-borderStyle-hover: solid;--salt-editable-borderStyle-active: solid;--salt-editable-borderStyle-disabled: solid;--salt-editable-borderStyle-readonly: solid;--salt-editable-borderWidth-active: 2px;--salt-editable-borderColor: var(--salt-palette-interact-border);--salt-editable-borderColor-active: var(--salt-palette-interact-border-active);--salt-editable-borderColor-disabled: var(--salt-palette-interact-border-disabled);--salt-editable-borderColor-hover: var(--salt-palette-interact-border-hover);--salt-editable-borderColor-readonly: var(--salt-palette-interact-border-readonly);--salt-editable-primary-background: var(--salt-palette-neutral-primary-background);--salt-editable-primary-background-active: var(--salt-palette-neutral-primary-background);--salt-editable-primary-background-disabled: var(--salt-palette-neutral-primary-background-disabled);--salt-editable-primary-background-hover: var(--salt-palette-neutral-primary-background);--salt-editable-primary-background-readonly: var(--salt-palette-neutral-primary-background-readonly);--salt-editable-secondary-background: var(--salt-palette-neutral-secondary-background);--salt-editable-secondary-background-active: var(--salt-palette-neutral-secondary-background);--salt-editable-secondary-background-disabled: var(--salt-palette-neutral-secondary-background-disabled);--salt-editable-secondary-background-hover: var(--salt-palette-neutral-secondary-background);--salt-editable-secondary-background-readonly: var(--salt-palette-neutral-secondary-background-readonly);--salt-editable-tertiary-background: var(--salt-palette-neutral-tertiary-background);--salt-editable-tertiary-background-active: var(--salt-palette-neutral-tertiary-background);--salt-editable-tertiary-background-disabled: var(--salt-palette-neutral-tertiary-background-disabled);--salt-editable-tertiary-background-hover: var(--salt-palette-neutral-tertiary-background);--salt-editable-tertiary-background-readonly: var(--salt-palette-neutral-tertiary-background-readonly);--salt-editable-help-fontStyle: italic}.vuu-purple-theme{--salt-focused-outlineColor: var(--salt-palette-interact-outline);--salt-focused-outlineStyle: dotted;--salt-focused-outlineWidth: 2px;--salt-focused-outlineInset: 0;--salt-focused-outlineOffset: 0;--salt-focused-outline: var(--salt-focused-outlineWidth) var(--salt-focused-outlineStyle) var(--salt-focused-outlineColor)}.saltFocusVisible:after,.focused:focus:after,.focused:focus-visible:after{content:"";inset:var(--salt-focused-outlineInset);outline-color:var(--salt-focused-outlineColor);outline-offset:var(--salt-focused-outlineOffset);outline-style:var(--salt-focused-outlineStyle);outline-width:var(--salt-focused-outlineWidth);position:absolute}.vuu-purple-theme{--salt-measured-borderStyle: solid;--salt-measured-borderStyle-active: solid;--salt-measured-borderStyle-complete: solid;--salt-measured-borderStyle-incomplete: dotted;--salt-measured-borderWidth: 2px;--salt-measured-borderWidth-active: 2px;--salt-measured-borderWidth-complete: 2px;--salt-measured-borderWidth-incomplete: 2px;--salt-measured-fontWeight: var(--salt-typography-fontWeight-semiBold);--salt-measured-textAlign: center;--salt-measured-background: var(--salt-palette-measured-background);--salt-measured-background-disabled: var(--salt-palette-measured-background-disabled);--salt-measured-borderColor: var(--salt-palette-measured-border);--salt-measured-borderColor-disabled: var(--salt-palette-measured-border-disabled);--salt-measured-fill: var(--salt-palette-measured-fill);--salt-measured-fill-disabled: var(--salt-palette-measured-fill-disabled);--salt-measured-foreground: var(--salt-palette-measured-foreground);--salt-measured-foreground-hover: var(--salt-palette-measured-foreground-active);--salt-measured-foreground-active: var(--salt-palette-measured-foreground-active);--salt-measured-foreground-undo: var(--salt-palette-measured-foreground-active);--salt-measured-foreground-activeDisabled: var(--salt-palette-measured-foreground-activeDisabled);--salt-measured-foreground-disabled: var(--salt-palette-measured-foreground-disabled)}.vuu-purple-theme{--salt-navigable-cursor-active: pointer;--salt-navigable-cursor-hover: pointer;--salt-navigable-cursor-disabled: not-allowed;--salt-navigable-cursor-edit: text;--salt-navigable-fontWeight: var(--salt-typography-fontWeight-regular);--salt-navigable-fontWeight-hover: var(--salt-typography-fontWeight-regular);--salt-navigable-fontWeight-active: var(--salt-typography-fontWeight-semiBold);--salt-navigable-fontWeight-edit: var(--salt-typography-fontWeight-regular);--salt-navigable-indicator-hover: var(--salt-palette-navigate-indicator-hover);--salt-navigable-indicator-active: var(--salt-palette-navigate-indicator-active);--salt-navigable-indicator-activeDisabled: var(--salt-palette-navigate-indicator-activeDisabled);--salt-navigable-primary-background: var(--salt-palette-navigate-primary-background);--salt-navigable-primary-background-hover: var(--salt-palette-navigate-primary-background-hover);--salt-navigable-primary-background-active: var(--salt-palette-navigate-primary-background-active);--salt-navigable-secondary-background: var(--salt-palette-navigate-secondary-background);--salt-navigable-secondary-background-hover: var(--salt-palette-navigate-secondary-background-hover);--salt-navigable-secondary-background-active: var(--salt-palette-navigate-secondary-background-active);--salt-navigable-tertiary-background: var(--salt-palette-navigate-tertiary-background);--salt-navigable-tertiary-background-hover: var(--salt-palette-navigate-tertiary-background-hover);--salt-navigable-tertiary-background-active: var(--salt-palette-navigate-tertiary-background-active)}.vuu-purple-theme{--salt-overlayable-shadow-scroll: var(--salt-shadow-1);--salt-overlayable-shadow-scroll-color: var(--salt-shadow-1-color);--salt-overlayable-shadow-borderRegion: var(--salt-shadow-2);--salt-overlayable-shadow: var(--salt-shadow-2);--salt-overlayable-shadow-hover: var(--salt-shadow-3);--salt-overlayable-shadow-popout: var(--salt-shadow-4);--salt-overlayable-shadow-drag: var(--salt-shadow-4);--salt-overlayable-shadow-modal: var(--salt-shadow-5);--salt-overlayable-background: var(--salt-palette-neutral-backdrop)}.vuu-purple-theme{--salt-selectable-cursor-hover: pointer;--salt-selectable-cursor-selected: pointer;--salt-selectable-cursor-blurSelected: pointer;--salt-selectable-cursor-disabled: not-allowed;--salt-selectable-borderStyle: solid;--salt-selectable-borderStyle-hover: solid;--salt-selectable-borderStyle-selected: solid;--salt-selectable-borderStyle-blurSelected: solid;--salt-selectable-borderColor: var(--salt-palette-interact-border);--salt-selectable-borderColor-hover: var(--salt-palette-interact-border-hover);--salt-selectable-borderColor-selected: var(--salt-palette-interact-border-active);--salt-selectable-borderColor-selectedDisabled: var(--salt-palette-interact-border-activeDisabled);--salt-selectable-borderColor-disabled: var(--salt-palette-interact-border-disabled);--salt-selectable-foreground-partial: var(--salt-palette-interact-foreground-partial);--salt-selectable-foreground-partialDisabled: var(--salt-palette-interact-foreground-partialDisabled);--salt-selectable-background: var(--salt-palette-interact-background);--salt-selectable-background-hover: var(--salt-palette-interact-background-hover);--salt-selectable-background-selected: var(--salt-palette-interact-background-active);--salt-selectable-background-blurSelected: var(--salt-palette-interact-background-blurSelected);--salt-selectable-background-disabled: var(--salt-palette-interact-background-disabled);--salt-selectable-cta-foreground: var(--salt-palette-interact-foreground);--salt-selectable-cta-foreground-hover: var(--salt-palette-interact-cta-foreground-hover);--salt-selectable-cta-foreground-selected: var(--salt-palette-interact-cta-foreground-active);--salt-selectable-cta-foreground-selectedDisabled: var(--salt-palette-interact-cta-foreground-activeDisabled);--salt-selectable-cta-foreground-disabled: var(--salt-palette-interact-foreground-disabled);--salt-selectable-cta-background: var(--salt-palette-interact-background);--salt-selectable-cta-background-disabled: var(--salt-palette-interact-background-disabled);--salt-selectable-cta-background-hover: var(--salt-palette-interact-cta-background-hover);--salt-selectable-cta-background-selected: var(--salt-palette-interact-cta-background-active);--salt-selectable-cta-background-selectedDisabled: var(--salt-palette-interact-cta-background-activeDisabled);--salt-selectable-primary-foreground: var(--salt-palette-interact-foreground);--salt-selectable-primary-foreground-selected: var(--salt-palette-interact-primary-foreground-active);--salt-selectable-primary-foreground-selectedDisabled: var(--salt-palette-interact-primary-foreground-activeDisabled);--salt-selectable-primary-foreground-disabled: var(--salt-palette-interact-foreground-disabled);--salt-selectable-primary-foreground-hover: var(--salt-palette-interact-primary-foreground-hover);--salt-selectable-primary-background: var(--salt-palette-interact-background);--salt-selectable-primary-background-disabled: var(--salt-palette-interact-background-disabled);--salt-selectable-primary-background-hover: var(--salt-palette-interact-primary-background-hover);--salt-selectable-primary-background-selected: var(--salt-palette-interact-primary-background-active);--salt-selectable-primary-background-selectedDisabled: var(--salt-palette-interact-primary-background-activeDisabled);--salt-selectable-secondary-foreground: var(--salt-palette-interact-foreground);--salt-selectable-secondary-foreground-selected: var(--salt-palette-interact-secondary-foreground-active);--salt-selectable-secondary-foreground-selectedDisabled: var(--salt-palette-interact-secondary-foreground-activeDisabled);--salt-selectable-secondary-foreground-disabled: var(--salt-palette-interact-foreground-disabled);--salt-selectable-secondary-foreground-hover: var(--salt-palette-interact-secondary-foreground-hover);--salt-selectable-secondary-background: var(--salt-palette-interact-background);--salt-selectable-secondary-background-disabled: var(--salt-palette-interact-background-disabled);--salt-selectable-secondary-background-hover: var(--salt-palette-interact-secondary-background-hover);--salt-selectable-secondary-background-selected: var(--salt-palette-interact-secondary-background-active);--salt-selectable-secondary-background-selectedDisabled: var(--salt-palette-interact-secondary-background-activeDisabled)}.vuu-purple-theme{--salt-separable-borderStyle: solid;--salt-separable-primary-borderColor: var(--salt-palette-neutral-primary-separator);--salt-separable-secondary-borderColor: var(--salt-palette-neutral-secondary-separator);--salt-separable-tertiary-borderColor: var(--salt-palette-neutral-tertiary-separator)}.vuu-purple-theme{--salt-status-info-foreground: var(--salt-palette-info-foreground);--salt-status-success-foreground: var(--salt-palette-success-foreground);--salt-status-warning-foreground: var(--salt-palette-warning-foreground);--salt-status-error-foreground: var(--salt-palette-error-foreground);--salt-status-info-borderColor: var(--salt-palette-info-border);--salt-status-success-borderColor: var(--salt-palette-success-border);--salt-status-warning-borderColor: var(--salt-palette-warning-border);--salt-status-error-borderColor: var(--salt-palette-error-border);--salt-status-info-background-emphasize: var(--salt-palette-info-background-emphasize);--salt-status-success-background-emphasize: var(--salt-palette-success-background-emphasize);--salt-status-warning-background-emphasize: var(--salt-palette-warning-background-emphasize);--salt-status-error-background-emphasize: var(--salt-palette-error-background-emphasize)}.vuu-purple-theme{--salt-taggable-cursor-hover: pointer;--salt-taggable-cursor-active: pointer;--salt-taggable-cursor-disabled: not-allowed;--salt-taggable-background: var(--salt-palette-interact-primary-background);--salt-taggable-background-hover: var(--salt-palette-interact-primary-background-hover);--salt-taggable-background-active: var(--salt-palette-interact-primary-background-active);--salt-taggable-background-disabled: var(--salt-palette-interact-primary-background-disabled);--salt-taggable-foreground: var(--salt-palette-interact-primary-foreground);--salt-taggable-foreground-hover: var(--salt-palette-interact-primary-foreground-hover);--salt-taggable-foreground-active: var(--salt-palette-interact-primary-foreground-active);--salt-taggable-foreground-disabled: var(--salt-palette-interact-primary-foreground-disabled)}.vuu-purple-theme{--salt-text-letterSpacing: 0;--salt-text-textAlign: left;--salt-text-textAlign-embedded: center;--salt-text-textDecoration: none;--salt-text-textTransform: none;--salt-text-fontFamily: var(--salt-typography-fontFamily);--salt-text-fontWeight: var(--salt-typography-fontWeight-regular);--salt-text-fontWeight-small: var(--salt-typography-fontWeight-light);--salt-text-fontWeight-strong: var(--salt-typography-fontWeight-semiBold);--salt-text-h1-fontWeight: var(--salt-typography-fontWeight-bold);--salt-text-h1-fontWeight-small: var(--salt-typography-fontWeight-medium);--salt-text-h1-fontWeight-strong: var(--salt-typography-fontWeight-extraBold);--salt-text-h2-fontWeight: var(--salt-typography-fontWeight-semiBold);--salt-text-h2-fontWeight-small: var(--salt-typography-fontWeight-regular);--salt-text-h2-fontWeight-strong: var(--salt-typography-fontWeight-bold);--salt-text-h3-fontWeight: var(--salt-typography-fontWeight-semiBold);--salt-text-h3-fontWeight-small: var(--salt-typography-fontWeight-regular);--salt-text-h3-fontWeight-strong: var(--salt-typography-fontWeight-bold);--salt-text-h4-fontWeight: var(--salt-typography-fontWeight-semiBold);--salt-text-h4-fontWeight-small: var(--salt-typography-fontWeight-regular);--salt-text-h4-fontWeight-strong: var(--salt-typography-fontWeight-bold);--salt-text-label-fontWeight: var(--salt-typography-fontWeight-regular);--salt-text-label-fontWeight-small: var(--salt-typography-fontWeight-light);--salt-text-label-fontWeight-strong: var(--salt-typography-fontWeight-semiBold);--salt-text-display1-fontWeight: var(--salt-typography-fontWeight-semiBold);--salt-text-display1-fontWeight-strong: var(--salt-typography-fontWeight-bold);--salt-text-display1-fontWeight-small: var(--salt-typography-fontWeight-regular);--salt-text-display2-fontWeight: var(--salt-typography-fontWeight-semiBold);--salt-text-display2-fontWeight-strong: var(--salt-typography-fontWeight-bold);--salt-text-display2-fontWeight-small: var(--salt-typography-fontWeight-regular);--salt-text-display3-fontWeight: var(--salt-typography-fontWeight-semiBold);--salt-text-display3-fontWeight-strong: var(--salt-typography-fontWeight-bold);--salt-text-display3-fontWeight-small: var(--salt-typography-fontWeight-regular);--salt-text-background-selected: var(--salt-palette-interact-background-active);--salt-text-primary-foreground: var(--salt-palette-neutral-primary-foreground);--salt-text-primary-foreground-disabled: var(--salt-palette-neutral-primary-foreground-disabled);--salt-text-secondary-foreground: var(--salt-palette-neutral-secondary-foreground);--salt-text-secondary-foreground-disabled: var(--salt-palette-neutral-secondary-foreground-disabled);--salt-text-link-foreground-hover: var(--salt-palette-navigate-foreground-hover);--salt-text-link-foreground-active: var(--salt-palette-navigate-foreground-active);--salt-text-link-foreground-visited: var(--salt-palette-navigate-foreground-visited);--salt-text-link-textDecoration: underline;--salt-text-link-textDecoration-hover: none;--salt-text-link-textDecoration-selected: underline;--salt-text-code-fontFamily: var(--salt-typography-fontFamily-code)}.vuu-purple-density-touch{--salt-text-h1-fontSize: 42px;--salt-text-h1-lineHeight: 54px;--salt-text-h2-fontSize: 32px;--salt-text-h2-lineHeight: 42px;--salt-text-h3-fontSize: 24px;--salt-text-h3-lineHeight: 32px;--salt-text-h4-fontSize: 16px;--salt-text-h4-lineHeight: 20px;--salt-text-label-fontSize: 14px;--salt-text-label-lineHeight: 18px;--salt-text-fontSize: 16px;--salt-text-lineHeight: 20px;--salt-text-minHeight: 20px;--salt-text-display1-fontSize: 84px;--salt-text-display1-lineHeight: 109px;--salt-text-display2-fontSize: 58px;--salt-text-display2-lineHeight: 76px;--salt-text-display3-fontSize: 42px;--salt-text-display3-lineHeight: 54px}.vuu-purple-density-low{--salt-text-h1-fontSize: 32px;--salt-text-h1-lineHeight: 42px;--salt-text-h2-fontSize: 24px;--salt-text-h2-lineHeight: 32px;--salt-text-h3-fontSize: 18px;--salt-text-h3-lineHeight: 24px;--salt-text-h4-fontSize: 14px;--salt-text-h4-lineHeight: 18px;--salt-text-label-fontSize: 12px;--salt-text-label-lineHeight: 16px;--salt-text-fontSize: 14px;--salt-text-lineHeight: 18px;--salt-text-minHeight: 18px;--salt-text-display1-fontSize: 68px;--salt-text-display1-lineHeight: 88px;--salt-text-display2-fontSize: 46px;--salt-text-display2-lineHeight: 60px;--salt-text-display3-fontSize: 32px;--salt-text-display3-lineHeight: 42px}.vuu-purple-density-medium{--salt-text-h1-fontSize: 24px;--salt-text-h1-lineHeight: 32px;--salt-text-h2-fontSize: 18px;--salt-text-h2-lineHeight: 24px;--salt-text-h3-fontSize: 14px;--salt-text-h3-lineHeight: 18px;--salt-text-h4-fontSize: 12px;--salt-text-h4-lineHeight: 16px;--salt-text-label-fontSize: 11px;--salt-text-label-lineHeight: 14px;--salt-text-fontSize: 12px;--salt-text-lineHeight: 16px;--salt-text-minHeight: 16px;--salt-text-display1-fontSize: 54px;--salt-text-display1-lineHeight: 70px;--salt-text-display2-fontSize: 36px;--salt-text-display2-lineHeight: 47px;--salt-text-display3-fontSize: 24px;--salt-text-display3-lineHeight: 32px}.vuu-purple-density-high{--salt-text-h1-fontSize: 18px;--salt-text-h1-lineHeight: 24px;--salt-text-h2-fontSize: 14px;--salt-text-h2-lineHeight: 18px;--salt-text-h3-fontSize: 12px;--salt-text-h3-lineHeight: 16px;--salt-text-h4-fontSize: 11px;--salt-text-h4-lineHeight: 14px;--salt-text-label-fontSize: 10px;--salt-text-label-lineHeight: 13px;--salt-text-fontSize: 11px;--salt-text-lineHeight: 14px;--salt-text-minHeight: 14px;--salt-text-display1-fontSize: 42px;--salt-text-display1-lineHeight: 54px;--salt-text-display2-fontSize: 28px;--salt-text-display2-lineHeight: 36px;--salt-text-display3-fontSize: 18px;--salt-text-display3-lineHeight: 24px}.vuu-purple-theme{--svg-add: url('data:image/svg+xml;utf8,');--svg-alert-circle-filled: url('data:image/svg+xml;utf8,');--svg-arrow-thin: url('data:image/svg+xml;utf8,');--svg-box: url('data:image/svg+xml;utf8,');--svg-caret-right: url('data:image/svg+xml;utf8,');--svg-caret-down: url('data:image/svg+xml;utf8,');--svg-checkbox: url('data:image/svg+xml;utf8,');--svg-checkbox-checked: url('data:image/svg+xml;utf8,');--svg-close: url('data:image/svg+xml;utf8,');--svg-close-circle: url('data:image/svg+xml;utf8,');--svg-checkbox-small: url('data:image/svg+xml;utf8,');--svg-chevron-down: url('data:image/svg+xml;utf8,');--svg-chevron-double-left: url('data:image/svg+xml;utf8,');--svg-chevron-double-right: url('data:image/svg+xml;utf8,');--svg-column-2A: url('data:image/svg+xml;utf8,');--svg-column-2B: url('data:image/svg+xml;utf8,');--svg-corner-triangle: url('data:image/svg+xml;utf8,');--svg-filter: url('data:image/svg+xml;utf8,');--svg-folder-closed: url('data:image/svg+xml;utf8,');--svg-folder-open: url('data:image/svg+xml;utf8,');--svg-function: url('data:image/svg+xml;utf8,');--svg-logout: url('data:image/svg+xml;utf8,');--svg-rings: url('data:image/svg+xml;utf8,');--svg-settings: url('data:image/svg+xml;utf8,');--svg-sort-order-down: url('data:image/svg+xml;utf8,');--svg-sorted-asc: url('data:image/svg+xml;utf8,');--svg-sorted-dsc: url('data:image/svg+xml;utf8,');--svg-user: url('data:image/svg+xml;utf8,');--svg-grab-handle: url('data:image/svg+xml;utf8, ');--svg-open-in: url('data:image/svg+xml;utf8,');--svg-sort-up: url('data:image/svg+xml;utf8,');--svg-tree-node-collapse: url('data:image/svg+xml;utf8,');--svg-tree-node-expand: url('data:image/svg+xml;utf8,');--svg-triangle-right: url('data:image/svg+xml;utf8,');--svg-triangle-down: url('data:image/svg+xml;utf8,');--svg-plus-box: url('data:image/svg+xml;utf8,');--svg-minus-box: url('data:image/svg+xml;utf8,');--vuu-icon-size: 12px;--svg-active-status: url('data:image/svg+xml;utf8,');--svg-connecting-status: url('data:image/svg+xml;utf8,');--svg-disconnected-status: url('data:image/svg+xml;utf8,');--vuu-svg-chevron-left: url('data:image/svg+xml;utf8,');--vuu-svg-chevron-right: url('data:image/svg+xml;utf8,');--vuu-svg-more-vert: url('data:image/svg+xml;utf8,');--vuu-svg-triangle-right: url('data:image/svg+xml;utf8,')}span[data-icon]{display:inline-block;height:var(--vuu-icon-height, var(--vuu-icon-size,18px));position:relative;width:var(--vuu-icon-width, var(--vuu-icon-size, 18px))}[data-icon]:after{content:"";background-color:var(--vuu-icon-color, var(--saltIcon-color, var(--salt-text-secondary-foreground)));left:var(--vuu-icon-left, auto);height:var(--vuu-icon-height, var(--vuu-icon-size, 12px));-webkit-mask:var(--vuu-icon-svg) center center/var(--vuu-icon-size) var(--vuu-icon-size);mask:var(--vuu-icon-svg) center center/var(--vuu-icon-size) var(--vuu-icon-size);mask-repeat:no-repeat;-webkit-mask-repeat:no-repeat;position:absolute;top:var(--vuu-icon-top, auto);width:var(--vuu-icon-width, var(--vuu-icon-size, 12px))}[data-icon=sort-up]{--vuu-icon-svg: var(--svg-sort-up)}[data-icon=add]{--vuu-icon-svg: var(--svg-add)}[data-icon=arrow-thin-left]{--vuu-icon-svg: var(--svg-arrow-thin)}[data-icon=arrow-thin-right]{--vuu-icon-svg: var(--svg-arrow-thin);transform:rotate(180deg)}[data-icon=arrow-thin-up]{--vuu-icon-svg: var(--svg-arrow-thin);transform:rotate(90deg)}[data-icon=arrow-thin-down]{--vuu-icon-svg: var(--svg-arrow-thin);transform:rotate(270deg)}[data-icon=box]{--vuu-icon-svg: var(--svg-box)}[data-icon=chevron-left]{--vuu-icon-svg: var(--vuu-svg-chevron-left)}[data-icon=chevron-right]{--vuu-icon-svg: var(--vuu-svg-chevron-right)}[data-icon=close]{--vuu-icon-svg: var(--vuu-close-icon-svg, var(--svg-close))}[data-icon=error]{--vuu-icon-color: var(--salt-status-error-foreground);--vuu-icon-svg: var(--svg-alert-circle-filled)}[data-icon=filter]{--vuu-icon-svg: var(--svg-filter)}[data-icon=rings]{--vuu-icon-svg: var(--svg-rings)}[data-icon=open-in]{--vuu-icon-svg: var(--svg-open-in)}[data-icon=close-circle]{--vuu-icon-svg: var(--svg-close-circle)}[data-icon=chevron-double-left]{--vuu-icon-svg: var(--svg-chevron-double-left)}[data-icon=chevron-double-right]{--vuu-icon-svg: var(--svg-chevron-double-right)}[data-icon=column-2A]{--vuu-icon-svg: var(--svg-column-2A)}[data-icon=column-2B]{--vuu-icon-svg: var(--svg-column-2B)}:is([data-icon="folder"],[data-icon="folder-closed"]){--vuu-icon-svg: var(--svg-folder-closed)}[data-icon=plus-box]{--vuu-icon-svg: var(--svg-plus-box)}[data-icon=minus-box]{--vuu-icon-svg: var(--svg-minus-box)}[data-icon=more-vert]{--vuu-icon-svg: var(--vuu-svg-more-vert)}[data-icon=settings]{--vuu-icon-svg: var(--svg-settings)}[data-icon=sorted-asc]{--vuu-icon-svg: var(--svg-sorted-asc)}[data-icon=sorted-dsc]{--vuu-icon-svg: var(--svg-sorted-dsc)}[data-icon=triangle-right]{--vuu-icon-svg: var(--svg-triangle-right)}[data-icon=user]{--vuu-icon-svg: var(--svg-user)}[data-icon=active-status]{--svg-icon: var(--svg-active-status)}[data-icon=connecting-status]{--svg-icon: var(--svg-connecting-status)}[data-icon=disconnected-status]{--svg-icon: var(--svg-disconnected-status)}[data-icon=vuu-triangle-right]{--vuu-icon-svg: var(--vuu-svg-triangle-right)} +@font-face{font-family:Nunito Sans;font-style:normal;font-weight:300;font-stretch:100%;font-display:swap;src:url(data:font/woff2;base64,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) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Nunito Sans;font-style:normal;font-weight:400;font-stretch:100%;font-display:swap;src:url(data:font/woff2;base64,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) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Nunito Sans;font-style:normal;font-weight:500;font-stretch:100%;font-display:swap;src:url(data:font/woff2;base64,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) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Nunito Sans;font-style:normal;font-weight:600;font-stretch:100%;font-display:swap;src:url(data:font/woff2;base64,d09GMgABAAAAAFaAABQAAAAA07gAAFYKAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGoI6G/56HIwSP0hWQVKDND9NVkFSVAZgP1NUQVSBGCcWAIUyLywRCAqBgyDnAQuETgAw5UoBNgIkA4kYBCAFhx4HjC8b68E3aHZftonDbQOif7Cc7M84G1HDxgG2A3tpJMI2clJI+f//z0gqh1RSf2kLYNsXCSIPRSARqUyhRipbH3P13vfyXqsiN05NI1B3o2Pe5rSq4E/g/YZV8aDCaXcWZLh4cO3eWTQHPtGXPEkb3RoUjf0P6jGCsmM9eLPhcKf14KHVrAlB2I3C2m3wxTT+abX7vS+968KXEjMROAh8y3I3JVMyX3NyRcP63T6MChVLdsoa7oYgq9H0gBJ+w8rgj6Z9qRpue3kr3wvDEtya51cOP6ySrkKxDJH+pp2hMWToOqliOgLvRbW3PqF+nUQq9bJmb/3YGdg28ic5ef3n+Tk9973/k58QPIgWvBrELKWCVh2rOTWjNlEqYx0Vo7qOmjvL1hDyh+enswcU6h5rxOT/mP+otE2NOk0NKybFZbs7xO6uU6adIDoXbIM5JhTRsjKy+vbdsnf4EXfOoYdIBMsDKCoqQIWH5+EPf+fe19gWFXACUZuiNF0TP8cLKdXe0Jy2PbJ7Y18IM5Cv2DINIW0IihDkCzR3P8311ePiJM0LgG6FObJukgx5d3fCLVN/SHeq/k9n/94hDUozIwTbu6sleuj3CUJ8+px0SdFG3n0JFxVVJXUVVUiGHbBxExLcG8BsUuMG2A8SrtLKthSqte2fCl/FbFUwlDS7Jzro5n/5om3fa2nAgyVEgASClNa/iM23337bfc6GbVc5ymnOSNHBjFUMkyFA5LS8kFghOqAfoL7Wt8C+HiEGwGi3RPYXWEASKO9wajWSLTt2srtXKjpAH+Cn6KmSUPqNl4av9iSWVaZmoARAAPxsudfYTVlz0T/nrbGAB/f3pmrtf4D2BDpixePcUpcWkjleZzi3uhBz5+66j78Ad/8uVlwsKQkAKXu5UFiQkm8BiBZAOoFUAOlEp0zrUpLklBYgOQZJByrN0VnhYuxDiN25Kl3UV/ax9LXltaWr861lvbRf7ckxMP5ToC5uAm313uja27rLjH+NJmin2ylBA2oCoA8gQwRrpr29SR54HxCFKQtXYSurQw97lzwQVgGR8hWOQVWJKluLltPyLKU5sGiM/UGod5abhb6Uql6BcK2k1EscwsXpmPl7TbviNReSymiooS5xHAPp6+t8jKk+786xk02FXEKvCPEpIfQ+5V8QweRMMUEW5TvbRV6d013j5XVrIH/38PAwCILBYDAYBEEQBMEgePhBPK0yX8yZFPTkfzggcNgBqgCrAdcwWIOgQwgWj5AgAUOiHIQ83RB6KEeoNBlhqqkI01RjMPgfh1EzDnNKcFKRJTjZVo2TfwQECQw2vBAYppmOIICTHwWAoAWo186r2xIGQAPADoFICQYx4HTUKiB6rXLtEQAbb3D19HzohxwCIBZAwCd5m1ixqMXUD34JTcu+DPomTlJMMsq4yEspu9ZN16+G9WZ7vKOJd/Y41+TpIBAIkEsQAEdtqSEiXbh4+Urx9Av6QhRfTxxVhuKbfmMqUIyPeD+qApl9ZEJ/OyIMi0ICAEI2UW/VYykafYwDFLBByISt3GyEXHAmqsak4Rk4BE53mhlqD/rEeZGwxxh/+p8xdusdfg2h2f93hz/1upOMz+g/m1zIMg5wuVPQL0gHeB0s1PXXAnYke0+IH+taQvCk7syutHuaHs4cxdwEmIRnusyVWkIs/9sBC7sE0iHsK2Im4oRQ39atGtaiaDpu9wmfsDQ0NOWXZZ4ZBCfNTBWhQCyswCo6w9FM2i8VjqBw5zyqBOCC6D533e0Xm8CdTcGfw50Z+VhP2sJa5DpYQkjhz0/qM+NhmS0FZ6rwXnsJBY+X/b149Kq5I22W9KKyrS/n+iN5YUqm7VHT3YU/P0Sk4irS6zGI6si54Af3lNKxAU9B1d2n5xcPNI3ih37uN8SfzPk/rvJiv0U42qTqp8E9KVIoUSEpM/JnlrW4pympVCGN+0ehBJzqDCHravQd8mWgoctP9qWO+72mqE34SVOKYM/m8R2BbwkX1Q6JhVwd5L1rCzLeJPE2HsQ4qhZt+K04DikqtJ6hYADGprMjueeXwC24izkl1t07+U2VU2XnwomLyYmRFkw8Ic7nht0j7zIWlQDbqZGunrNKu0offW8BmDOD2T4zK9ZTtK1otb7qxl8uJfI8wP8Tku1PNkqB6zAZ7U0No7b2K9flSbJJMQQkcF+4fmnfN+Qxoa/IazjIjsdYdN9G2YOFOfRi11ms79ZVeSB+t94Twmn8F76W12o1ZfbKveZV/frt14pCmEPgHcZx+HrU9A3CVFUB4ntlC7cbFSGjrRPmaWR8k8MmBCyNLKPxyzjfTPqeUexzTXTkAS1HZ8FGqvY7kDDcgcsDwS/ta2+QBSdEEIkRx0R1XezpIBzHGnAZNs1dmpolhDjDIP870NHK1DBTnJSSK2aAqmT7r8Btf5N+KPU4NJV/9ASwE3eXYIQWhXJlAOwRhgINGHAEAcjCPS6nmv5DwRA3+HPaSq8XgwINZSex0gnYGlCdb6ROjvrRlLyJpCO8VO8syvSia2tA/F1WvSP3bjLfvz4WXkSnf4Qel1GelFmQpSk9fjpsvzbO1T2pPm81lA/DIkM1vN9ByUxdPe7VUsnkiGg8Rz40dth0YNREO6+Yl4o0rd4cvkdFtiJtkBh1JbMm6NybNZzQbMHafUkMrOFYlspaHXZk7/IDQK1GcDwqxRUqFFM5vAuH7cCdPmAGRyVed14Zw9fhBHxlNqoyLcFVdkIFf1zcwM2smW7omqR1t6+fLy0hqr6mRVRnpOJWIBpZshiATeYtaGxcrQvNydd1EEfOiF5lJoxWDa1UyMsX2LKULaYer/k+GQUZeFuW1T/dzzbdAmwq0l9sGKcldvRFUXua0dy2UPZs+TVbbLoeBk5N48KqfbwwtQTz3b5fVZ97gNS2px4J3uye5s2GHsF1Dr6tFSQIIeOzxIY5m3rm1VDrs2kAuRzyUw+pPJ/YrTIfJGBUl7Qfh1udlZDVcDFXBwt44m+EKC/HVGsqqhKg05E1vyvi50TN6WuLUFtlsowpnifth/009UNk4REbQEbQJQk1sErDZAnpimZPC6wLGglM2kPPrwGdrPKHAJVtLE0E2NoIcNog6UHs82P5E2jMkGFIYvJgDZYI1SiqqBi6xxiWLG0k7q5pzVOn8iCNAL3RCkgeHA8VQiVB9Vdw0Pxpiof1zJPBNyxK0ly3RCVFNUBa9cuD1a4rUo5awE/MvVrtWNoEtraWihHk2HXCUPSPymkNdaLsOpQNarp8IRL09PO5+FpqO19v9nvQ/mGykPGjmdcJf/cKFd/lk2W/If2o/qX9rs86G6n8XWiDOsiDD2VxTA+8GpM9Brn5+w5UvBLCM211LBL3iSt7ORaAX0BuYldVTB5A3On2yT2BG5UH51fePh5nHayHyE9rJXNfvenERY8vmAaQR4E2GLXuku9DAryeNwLPMkXxIP9+wXfMTx7+p50Lblq3oVGx1jKz94NzoavScy5kvYHRk3XNdrvJAtwntG/hRBO0D5F8dte4frKXim/dra4JFPP3qN+yj4VqyClBuna5fw2HPNcfMPqk+b8pMXNOSA7EMkf2/wnwV5WXrnlJqu75EiSdJP7FKme5zhO21xyQlpsae3CiabXbFidSciSOdQy/enLbwcKg72aUwyyzoBIQqWfO9a9B+OGPoYV0OwquwtsEuK9Fy/xJ0B505elH1WqEJdh7FJC6qRuHTnMnCUk12OPx9C6buJ9O9nfyA/yxwG95kmjN91iWlg0ZzY2ePenFgEtGjtNnkWs87MBZ5D5aoYtLZJlLedQ+CtObGYShDcAtcbJwzh6NyPuZbH6O61h89I7cjkrEKy28DHEH/ET5CyhmapGj0kGOkt/V4Eqt87fxuDRW8rSMFoBTg15qp4UPQT4JurDY2zkDb67zFOrt/WL1oiU0Hq7OkFgK7N+pNGV/jOlOILEidTACQ4Lp/+5vIkDtR6POPqZkJGA8RHwOggaG58LnmGPhTjVkaeW4x3Plg0qsX1T7dPqWDBIIuoNg8XQvBSCOLIoZ5o97mn/P8QiV1Nas5sB8umPcK6W0+hJr1syrO29qls9rO0++1YNKtMPQndLSpEc7YtSBO+/lddpka4+dl/J8t0tUZVX/akjCI+6gitdOfOqp9wDpzOlP0g8gXfq3CF7ay1GgSLESpbrprodexhpngokmma5arTW22ma7BjvscdQxJ5xyxlmWyIQCmFXkIrjx4sOvgTI1GCBClA66GetbDPQVWPbAhRsvPvwECBIhSgfdjOlL+fr+PU5ztm8F0Fc0/SAXbrz48BMgSIQoHXQztvpSzRRzJ7nQ9y1Oc7bthfm1r3eRS1yOiNEMzVsR4MaLDz8BgkSI0kE3YyFo2fTKSqHvS05zVi/MAXLe8JZ3I12z2xFDP9q04eZgKZbhF9RhizJjL44cI9YpgPn5tTGFhQRmSvrH5wfaKZvmTiLZlFJLOwNsZCfHOE7eyULW8jvJkl3PBjbyUtjfM/ap0GMuJoxoRRRbWknJ2HYF1KhODWpMC1Wr72T0ejWMMdSoO6orpYJOMJwiT7mZNDJXjowx1Xy7bIwqsY1n39nmnoN3e/DgKo/mOf8EmK3VMLijm6rVDply02MbjqKR/9WDqDzKYDQ+raUOePDGuBJJS3ozmsWpyU9Zm03ZnUOh0g/KB0SfoexJ9uZ9loXdvm5P3LMlEdubAZ7gtn0/ABZTAgBY9QJoRl6YvCumm2mSH60xzZ/qLbDVPks02u9nBx3za7XTNX25W+rc8dgOmzAF9h/3yv6qCIgmBjRdvH3b4eWuH5j+CGkxbnDKaQWwNoCEPUjZQ/eMJCBpti+jMvOcEzb3Z1h4VXj3p1Alzb++u798SolAWPs8rH0BgYLVzys4vRegGpCX06dnN7dK6Az2ybGmkNYeHFTYXbOktawIjXBodIQBUOuzEwvFeE6B5eiV/03BIvJMUG+b/WubYiK5rdwAtBoQs13C9uiZ8VdO8bEeZ1MClEC98plh4kK69ASl5yVHsq1dZt17RX1gadUnToOhbzy7B1QBsuHUejMfi2HBApw1QUWlVeqiHnER94Gsz+eFFsW5ZDg8lXrhYoWTR0jl0RLQTeVirzcxsWI3vHtutwmLzvK/2O1GAO+HA2wziPkdb51NCT1DzuHLgGrgVJEsHOqPlK/koUAZKPLrX87h3agyEIdaYcZAKWKUMysebMYv8JNRsLrRIPxfl76SO6u1LeFX1xrEMUPzNP3gktTEYFPq1MlU95dWqB79dh+N4dih+6wNjoPwSOLZIvGBurCitzBywNk0eXDIECa7ZVT8GMpX8uBkuMQKmU6NTGexTHcnpbJO8XsIazTKVEofeUECXcMlsmVifAzCGcOlCIMU8c6JDYwTn8DzMqNZtA5HzJUOTHHKJ1eToXwl169lwB9Z6SFl0s3tn8oC443YAN4Ay8hi6bRMUCdtuVTfdiXXqbDSKKEjM6WGnbHpyhpj6DDH1vB5W/uuqgMNwO/AVtfjXckO8Hxeci2CVIkjZeJIf/HTzEUWf4LFOd6ZdJhjK3MO58aPcgOYCRLIOPPI3A/nYDTwScTGlOKZiHIkmlEQOhe0db8Pja/LRLABLJ63znMmZ4NjzGCXBvI5hn2qK5a7bf6FuzqVNjN7yEMnaQ1Ds1U1vZtuvxA7PDglGXOqxRybAw02hyx5p25oZ0tHYLF+sGuUyBDkmt8e5gNmik+yZ7Jrsk1B6gjd6BTcnOz/5MLAU77xpu4T0IuWizu5n6at3PIflLFP7bNdusoznxg6zHHafHC+ms4B/B1bAB0BY+BJ/Z89a2cZ0LYRpXQjykpBY+yIDRcytrnV4qn+4LuNOUCFOoaP9XgVKQMqGzJigs7vlLJ6NFmoFC0DyreabC2XWjZ/wQ5GgZsdq8XkrzsOFGqHM1eXypTzbSvxdKt9bRd3dIQRigdtcEbCGpG2RBAuAUpAHuBJa6xwxJ5gWuFDB7wIwRVvAnGiHRwVChywxAJb/PDFBTsEYogmKh4ZTzHUKO1/2T11bt0VJOXuO78FrbOpaadGx2rOuebebpNn3ulq7kxolkAa0n6D1YDXZWOI+LapvIr68fJ57yoqy4n+WxN8g9q+DRvSj7jfegaUkVhBiRYzTnznRn6MLR9Fjdn/kQIA0REEgNg2NrgibxphYSimx4utmaRN9PRK6JBgNIBMmIMmM74WKahIxBL/FfunjPTFaqFKeZLhRcNnUwq9aPVZ11y87yrc/TUvXHfovbD6wprOtTN3HB0T79Kx+Jt7rrxz/wQQXCh2OCNhhQo1lligEdtrOexpOUCsNRwKKEdEekYJyHIc0YnAl0RYgugXIohWU1AbqLVme67raHX3ZtD5rPwp7TlinyBzZ+uwFyl99wYejdPa9nao1NxEoN9a/ZrqMabtu8z+BgygLRglpmww/KY7Y/mTw9pP7xjQ59TjoTHsNekA8h1NsiwYOuIUTzKLQJRBepaiczTl0aSjqY6mPpqFaD7EyIsVqUhNFguI//+SSiurvIoqq6oao1I2CvWwPyAQCro0sne+AjvthJHTu+ZzQJhlsSQLnRVAel1K+NFqeF+QcxmlZkSa5Ire8q9f71ljbTgNrrN+jH7J3QZt61BAj3hK6EiXFm71gvXXBNElfnBYdIETEoIJ+QnE57OiEHSbGcBFfFLkiNjCYDArCMrQ/RkswCABd3AhitIUfMzgHQ6wfiLGgUjBgUgpSpdkKJCPQy9UCZ39h6HZ/zxyEzC4i+9CdW13U4cnCHDirEBRgBeSLRgid4NE0+5xVYhOpZQoZhFiuHCXBazrPFEnYANGLzUJBgJGbLRc3BVzArcmRoCm04DMJOVStBPJyQAtYCFVJQQ4AE/wKx36ljBhV4hHNKI5JkpqC9vjpRXV7wVDCUMzg9kirQenCIwSgjVandFktjsQl9vj9YWj8dTM9ODwPDBNzGgeduEvwKYQQUTdf2trMBiPd8/sTcWSero5bZs1K4HDDnSlEm2NbXHvEbV6t8tlX7BgaP9jPalUT3PfU3o7e8JHMJsT3uGenpm+kZ5Zs/pbBvs5v90eOHpPW8fg7A6/DzyrnT54IUGmEzidGrUBH+T2RYVo1AccjEcQgKk/QxDXfU0wfT6LZfuLMBtCJh1QH2q0wHwVcq8BXnqF5DR46XgJIsJ/5DEgFGOjZS5+/TGwEiLb5ePTkDGA3KqmW+qYU2BbS4BSA4FFtY4IsIVTCsjT10+9+aWBalXDECcNyK9KJ/t9QD670/75jw0I+RnOgH4EgF7MYYBXxolwscBAsSvisW739GlUAFQ+jJ5EGaDx78YMpWlg4z8OHUNTwZfhfghUSYAGzvwEi6dHAEDW1BTfYrKhYGYzsqUBxlpjIMvBcyVaBqyRBaHJudw1Mmg8NUuQLDlFGq8GlXRWYLU09Zkqtr61LBEkxjQyDYXkntfnxNyZe4u4wFXc90w2Zo85ianBoDA4DBHDw0gxWswYzCZvH1wJrvyZDAAs4SVYrNVcda55rQGcc2n2CUwVpu6VcTGS79ANfgMUACDT5guA+XHVV936EAC0/KfO844H4NGvcUdtF/2hm8ZM9v3Fg6sgAEAioLsnANBv1VIb6Kd+odN369MB/53aaKdr/vHMv2667pjj9nltm4O2arRdg4/e+2C3GwhqWMAS1tBy4MiJOw+eWvHio632OtAJFiJSlGgx4pyy32lfHY2HRJmy5MjTWRddFeiup15666OfYUYoU65SlbHGGW+CyU545KTPNtnliReeeumx23F3xwyXfHHI3fi475N1/oqnJrfsja8/zXTZH9aqs4cCDAIkiFBCBQ3s2bBlx40zF66s4C2ALz+t+XsrUIRQYcLFaqdCqiTJ0qVIkyFbJ3od5eumSLESufoapL8BhhjoncHGGGmU0SYabpI2hoYQnjkGQwpccNEZ55x3FgGwwUDQIkiVJVaHptG6ggSSgCrhSJYhbDMFAMD0QK3Adh3A8Q8QmmYENggwMFm1MHAeYt0Lpe5PNQ47uFieA+OqzMnFB8h6g5R4jsmcNRvIF/Ex/hUZSDoXjAxeyrQObmnJ6i8h1mDPs8miEz0QDN4QLuD2lwwcwgUz77WHKefB2hxEH8qNkpiT9Gx7Jx1W4AsLuiGFqiAPYitbLY1aGxpFgTOpy2QordSpK+XltYiFc8Zcfvq5zcxsNsXalNRQZPvj0pkbbGfRe5eZtL3YluVZhzIVPf6nsumvNFuvneiNWcvTm7OUn0Yj6thobuSR3B95TVeUurKlmPY8CxGhCuf0/S4i616WaZuKkUu7CLLwcOPut31NTQCqCxGdXSBqag1K6L3Mz3x1E77xUlwtHXHRCOC2iJSNPfQvcxbo6jFlr/bxBl5HqsHXJDYMBeziCG34HHzB4YD9oiv/IlQZN9VOjrBlexQAgU/o26QXSbHX3joVQ/ft5M2nRMjeji4jNxlly/q+kpq0Rdxt01EA6CNHm7wNbKkkJyK0Als2+OBJgkoNaWdb8gOjKXTdSRqHQWyhYZscR6bPSAri4lXftfASdvL+R0o36MnzPJM1S3M0JHraeR1tOOQtnqE5EQZLXu9EtQhEIDqqL6qGkMQMAgYt2dimzx2XN7cRM+dbtpsXIcMcHsfAv/cC/JHdpP4aSHv2Hb+cskFUIzJyUmfOJZJ+crbgqjESRLxR36D4ZajysleF0lu+wn0ASakqdKa3VjVhKeEs0kct8ai1yCTFm7bX1ciabVs+/Bx8yUqhyUZBxHe4oK6Pbu6CPcajNP7kH6GxbeF5mONhcngGZynCQ7ZZAZerMhg3gA9tWIAqc46Ik4GicP34gFDGuoLoYl1YXymatTFFyP9ki3yn4zbTlkOX2Im29niXva1oUErxCg/WnWw5l/+JB47HA1lssKoUYB66lXfqZryIv1xghgYrOMAYOXRzmZAPiPljLWmFKRaVOuHoUFhVU3/hpUIkvVEteUH+EclGkMEmIReXJ9B1OSerOw9KZCCjsEm+fwKITaXkJJk7aH9pZFbK3pPCNxsvjZWpcWQYMdlgJ9Cy7bl1bpnzq95+Xi0+it3GaZ5AQ1FGxT6cUL7B3n+S+OWHTQaKlZYU6ZQLnG1a/EBY+nRIikpfOVplzDpEeMNAFnqri+LIqtwNZPY+/1aSFgMdMhSqD6lkQ2vED1/91Wycy6SZk35xDkcSYOki2e07ki0vA/k80YpuUque4oFVv/CXr7grRScgrpnPhItMyYQLv1wuOsq2Uyq6XXFbowd38HK7+LoE8DdqFNiIhBwQWAT78+wlc65Vp4mZNvQXPUY+hcqp88CRPtaG3kQIEU63wgHFkjQLHCbFQmr4N7XAON/vMNNH+eLPPoPERjOcqLtib/us44ivCc+hpL3Kz/xvbhoCEdJxz0m/v9UrUYGy052XxlYwssWiU3McA6Nzb7+EWNhcmQp1+zh/v1mgDdJSAf2GLo3SGilxNd7W9eMThEHzbDAQqJYZVAJ3IlYkQ2RubQvonInFm5y3HJsCzSaB3veByLqJfyAyVh1cxe/msbdYK1dAseelDlQiHYuurBGNQKIGjLRAb7gBOsOKTFTpMWL6VIOS+q64UvT1Fyh0fgZJSho3KFWDZNJw0chCPJC3xn/EP9M1W2QkdKKpI3+HDLxlooFJeMmENhDQ3yNf6x8A0ErrcyIkDMWM0wdAFPtkzA9Ea50SsiMgZgfkqEOCx5M6uFrEkGaNihi0ogVNg2ctIeILqUvHIUT+B3q6fEVc2sR8nVqArD1kTv0+y8ZTagz9hAz7P047yDD0HSIpPcYj8bIcHh6D0+iaj8rKZBcnZSdtgSdFu998PDufnBxdZZkjq+1UeS4tTWq3+6HbGiC/OGylKjhYnIR0oOlcPiAnrBMEyng1KEkPiEQNKkn2K2ZN+LQ7i92BfKSpftCjI7xLyp2DO8xPoQ1IJb6EiqhKXQv1wGL1tMnwSjM1q8Eb/M+HMUupLTwWXetslcx1HwfdtOuEnn8But5kkAgq1nzmLTMaXESoQuVQxAK5puCQf1mCMZfkagaKE6IWP2yVbPxbDPu2uO/ngg2c9Ac8DE7jKfVvLMDka4V6QEgdXuiDEheL8NDJT1rGk3kF2qu0aMu6fqO/PAAye2SekLDPb5HmTxQzc1GHm4PB5GIhLcEu2uI3aZLO7ZqZ3Z4qSfH9OVvQlnwuKPa28/3dj0c34PVOSX64nkM3kWYBu9iraDWtasbw4pJRhNVLfLG0zqbkO+WQ0pEPyBeoF636tJscWIWx/fKdBnkjTsnfHn7Ayt1GdXNJLeKkg2/xsecJg2ecJ7wMi7EQwWkvKeoL36LMedNJSZ6fcYZdTpQE2OW15JitBpu7h25Q9AtSAztrESIIo01BqTTlal71C4ONY8uiSUx5ynW1+pKRIXBuy6YgyFZ98u9UULXJtajDr1vECTWpYtmszgPzAnpJZKrjk+hv8WvtxAl7HlbMiXU8MiQ+oS13oYbpSYo0iFA5lULI8X+9xdISFtHiaOGjpLA8pSuIQgYq+uXl3xSaJinuyrTvghURMDLu7oFuvP0sa8i+GYIFNtgY8qTBrqzgb0J9qAzvGpje2MmcrahbtWqTukXIZgUrE8Jk4xWhsjZ8j9MwhZOwZWpAE0VKYKLbdNS5WXjUOboSK+GtzLZvFNzw3yumaQOnYRp9aBv6RECyolgnhzlviOefHqUsJ7/b8O1MQSWm9Kdd5XRuQ9BxUp+nxzQLERWGiA+NJHlKKpa4EEaUpIQVHS6ia77aki6qPW9dqY2x2iOb6ftP/M5JNavGSTMInPyDLBXiMfVWy9oFR3xiGtpYp/DoPE4ZXFUk1f9DtG8VKYIiZNOUB6wNSnwT5eiuaDF0X7j95Gf+u+zNAIcW0OLf6iRmiQ//G4tPPB218Pd/9uwTgPR8V7Lm3Dl9Z1+Jspnq+x81HzPJ61mEyM25c1rKDY0nnfnR+G002f05fhspYtXplGhi6hkQqNKdkVu+U7EUvyTyWR5TIiru6jtdNl+mvxWhmdB446n3/WBK2ji6ZrCBe4GLIZ8lOBPpdekoh15MB6XCt/VTNa/vzMDxxd4z0xL7Rvv7Xf1jIqDo6NvTde/kKYnvz9Z1ClSsR1ZdN/X850vvDJ1tjf8wusjyqXMO8E/WdA7FA2qrH84vKDfQCUaOSuhrpZk/hS9hKJ7dZ2tqz+xxUzCX1G/anSq50qm0vwmWSW0b/fb9vb32fRv9babZjJ1o9VeNRPnQ3M3Ll8/dMiRvJH6FVu+YzQT+yd9n7XG6dvX3u3bvcc7aqduyavn4+PiK1Su3AP/kG7qu2wFd4GmXDvgnX9A13rXr7DDYJvXt8Dr29/U69m/2d3ADpVbiBTT8IEWARuZtXrl64cbF7HDJGOrBBPxQf8xR4c8D/kmX+IDYNelSH1AD/6RrEginaydw36Tx010zJCSXjbER+Cdd0FSvqn1ZZ+6u+Z1tlqlW4J90jbQaQXBSV1+Fqq3STVrdVVOvCqdfq/IA/yT0tq/Kb51Uvu2r9IN5WaYhrjtKX+L20Be7I4Ncs2WQ44kmuoeR0WjqYrS2aUQLwhHR/BizmjU+Fg67e5sWPFe8iBEOMhf6fIK5dBHdp/Z++8h08wXzV65YPT6+fBz4JyutbWxBTKsWxNs41verY68hLqPeQAN5zWZj7BQqENVqBLG/VU7t+O51BDEaDIgBeR3AZ9xLH80haerQF9n56pmZO++INY+99I20NyqFoXameVcZaevs2VdDIz/edNzEjlFnvupya3Uat9b1KpBmiRKlTnxOHVylx7mKOCGfWlR/6GJ2a1m0NBKyqqDoAM/C9pYaia9dPtOEVwqs6KNk9gF1Xmt5c1nCY5IqQwMccFxSJNHQt3ZrNVNv0imUDti1QNvBgOskFJUbcjQ2h6PnXRfd6t554qC5kyFzSako497RIktWMGZT8fxJBsgYBQa3AYyCzqyV6zaMH3b9pzvV2dTU1Nn9H9fh8TUbAI/3dqBkHqZ4no//Nii/+3bxF6MN34yqvxxFfznquvt2zsfJik+TIKdyCJ3TmviaXvMlPZnTiq4YSv6ixNxQgildVejViZ8k5T9JoqjVWV2ArTgSwRw1PFAcCaNPGsAViWsnMjRUYde86m6GgK5AMv9RVVEWccjv42Bav7JCQkeqjpxcD9cY8rEqhExywVxrX3b6fbge/CLxnUTmL+7f3PnVXQwhA4nka7CUjVzKZ1gtvVNpENNdlUdeZR5XbzC5Zd9UrmxRQKqohN1uru8VSm/x0abTDD2S9GRG3EkXzV6nOJTf1MATh3AK7Ydle7g6Gx7AWeqY5n7OgGMSseZlRmG1Oi7n99pt/N6EAoF0zkQo7IzrtEg8HEISoDrL1K4S91tt4p52mYnhR184eV5bjbYisaAfabaitdUXTl4IYEBGFpxQ8Httdn5vQg6ro/C9XCsy6RjIuR/TsKX/m1GapWuViFv1OnFLSqwxJA3FjkrQ6NikpVccszQuldaYvfdm5DqxH/WtVzb2cWg6XQt+tjkmWNihscB6R8BmtfsNOoff6rD7ADHL1i2X99itst42lU4dlXDbzej5AtNjpz6g5emZDS7RDAXRbaMKac4a5Sv5qQbQciChGvQQk4mm5unJro8WKoYo1De3qVYfALjXVd2YfYc/OXwTZzBajH05vyQ0sCYp53cZjfzOpEyjjqu/yJ7leNfMbkpy3Nl6JI6YIKbXITFkp8aBdRIx5JtiUqXUSiF4YBZCZbTnkugwoUHDLAdwLNwcDsauIdeA9VnRwr8X+ROY2PMff867g/xGL4V2f/Ec4LwNiPQv6sTUHz5vzXlWDsWtd35mV8APktnsd2GQmgaWvy6vccMUzd/vwn7N0Zn7whWohqS0Si8WVkYgpUhPaXCmDE3znYj0b5SWVfph5u9C8mYDWFnDdr9SMsGbX55laFWIe202x7HUACn6zO4RDvlC4TXFM6y2NVdNzQOlWfoW5d++npaRLO22Cm1luabTbq7r/aFnC/QPBUm2hpHJbDneY6KJqbWNnkyFLw5g5fAfVb+J1U4cC2KqaXi3TIF3aaiMRKZGXSFLcTY6sEzscMzKuR9Tq+FEuetxxXJjo+rMPOLGm9WJj94qacSe5zi0g5h7L9oVNz/+xUbez5nl2HGFJiH/N2lWTo5brs14Z7qOoJluNMPl4A+JqC8459rWP7wTJdmOr3MuD5XeusxjMCFvgwT3bQfvIPY+vUa8E1/H84dKoHxIzqezIB8ObJBwmoKjTQet7loCZxRff3c/dGcfBp196teV1RWOvnq92W37FfnBzG9rFhoEFtQIqfqrmpfrF5cVy6/PsVbAWgGNDiF4UJDl84a9z/qo4puRzTtUO+5JHgqL7r17/1QtuJcls1KJXoiJMGhtNQTqpw0aZhlyzdGbLw0pwNeXrgaOHar97yH3h1fBxZ1XvZsOVW0/pNtyqHISIi9ete15gXbfQcGXhdSLzxI73qvb+V78whPCF3mJAx/V/+cjsGhH6ELDJ3/I+p2eOOTFbAciIX5JOUHVKyQtq+Sp5ikP29cvUH5dEHPp15ADXx/4MBZuCoNlv7A+JjJdJKMcL8We8xSX3cJVe4P1EiwbXzu3+8FadSFGdUP8qlA4teBrcOgXGkwgaJhM52A8jRqBtgdhN+Uqn3eVSr7N598Bp1nObpdof3pQtK8bcSJdiGjv4GBavcvl1Huc41u2OFZ63ciqzVvwHyKYo9/Ppx2aSX8lLZu9VQ9Cyj+nlVEgBUZuVOqFEeK2P1qH2RpDksbxKDC3bv0x5eMfKnv0oCGL5Su14M/VQ5lNDVKerl5KUyIqe5shyYTQUqrYINWKo8Rt348MM9XaBJXnlMCGyAe5mVpWg5mtEAfa2WBkq07puqm70q5v3+r6ZkFVxZYKIM1ieEvNhLMo6G4jXmx2IRqdw6/nWcm/yp/frjdWV2wP0yWahIjfrFFLUu0SoM3yDDhl27tG1QfH/EG8qQwitH+v9+GZHHMD31jdaYxmB4QuL02ojIsEzbBa1JqS6nV0DZGgZzIJOjWJQdeQCDqR9dn2AL3B3fhlho+UpoWAljW0qCXKIVkNrKuFh/7EGWjBeY0zO71KkIYzPqvvq3o2ycKJVqc0qPH6YI3aB3k9fkit8cNuixnRyOWI2mxCKKY04FGWieVHUJDQT2BwLA08Y007M8svdA8bEwlTkEbc0ixVu91acUR9aJ5f5iFlluOYR2eoSUQdiwmMquANztKz8HGjkRDXMtnspxHo25l1h0F1Ii6qnUGn2V0IzQn8shgb3aX5aa6V3+mUASF36fpLC2rQHFztAe//tjnqqeSj/+BxaKg0PSf7ogyc5Bx7/ch/BZ/jG35owN4k2WRq0vfYuh48iu/fQJrCIONQp1dlTexYhSJ6oVpwpWCSewqrqJbL5G71+IWird8Ug0nOsNZte0t7Gkf+hUTZSqz76G/q3QzZ+0sL/pyOcb4lpWvcBnCW2z0zGw20ZgdfRISrfHtxhNraF754REJlLoEZNPK6bBJFATVMEC+QyF8RCDfJpJvAeGp5/c+yBv4r/eANbvQqRbTAgezhawQBIlOrEZmAcG04+0CAJvIqDTxGAw6LZzDKsLhS+pukT9Hod8nkd9HoT8F+TlBXe9fhBDV1//riERGVmVYzaKR9OSSKAsZR7d72Zj2t2SkgfEy4SSbfJBC+IZG/BrHK+N4P4kDVYi6grS9SgkkUF6mZaazdtxso528Hp+Yj9lhnNqCvJ3bg5aqs5smwvPzeVk1U/cSF0cwjd+GLe+pxeY7b49+eq6g/UI4XRUlbv99hILoq6BIfkaVno6va8X/4sZQqq4Ipft4o8eLZGnr9tBbME4RBIvJqUTeCfw6dqa/9D76hHxe/8Y+tBry7zCxvSbUA5WeC23u6n4MwOQ4uk+lEuHy2i8Fx8jhsB8ICO/o6AqtPHJiuODDjeGDcZl6bY1ob2ziPH5yhODj9xEKPmTAJEGh4MShrpl+bK1uGO6bCHts7IUgLTPEjE8K9uIdjM/7cw7i2F1z6UjStDioBtxIjTjaltA5Us2OpGDDc0FRpwJ+C24IbuuHnCy7kfX9Q1S35cXDQsU5lM8pEWVM2bjaVraGMo8wg8tZmtIW8pnS1yYQ0eS3avPlFzU/pHQvuTnB43J+p/7j2K/cjtyk/c3mcRshc4a28guqdXZtRO7sXdbXSW2GGQOZE7tdVXuVX1WTUrGKvVOp6NHLwnJ8ptxElMerP656gcyJ9Ghq8Myj4GU/fSUOn0qCtz/qDckHZmKmlxVg/uRMofzfUnTju7ZzKmV/ca2wBbddtxdie4rWmcnDZVRjfS4nt3WrbFSzQ4ln6Jm9N/5OmAPeRsrJ4SRm4sjaxU97TJ9vX3KjcPzCwV5UcOBZJ/LvHz5rv0Unkcq0Uvyqs5Nk8Ca9J1J+ElUKdYF1uYVRNn1pXmYP9EEVagWnVxV2rNtqaew7Eo0dnDQUO7Q91Iwu5xwr/CjA7KjsqGVoBKSoXV/LpOg7ZL5XHASpLn6LzHQIGxghDhbf3/UO0UpgUvZ3IZ+lwa+n4N2Hlc2UnPywZrhueAuunuMhriJnrdjYFm8s3piWQWhJg5Wd9fP3vnzdi3BiRRdHopCGUivfqPoKezptdTXoM/jLxqzzIZQekEnYwyFGANCyaLwL3XodasY8PQaNQPkZukgiILaQurumjnQQKxZrZeiwHIxHa41S5vBF96+AvgXqG2CgREqqfT17g3R0EKtlS2XI0FyMSORPUyYIq8qcLozTozofVbEZNFemzBVE6O2OyD6MAWyXrYmEyKVxstQkX0rlIaLMtEibIL7RZhYuntFCoWg9FBNxGWMONRbgQ2Va7fNbWF1CwyWGySXtg1ItbB5bZ63gpTT/L42P1a7Wsfo83iWm0ZLyX0zeLZez8WGmyvi6tHf85ojVCEqlRrn4VvXKCNV/HWrAcqrGcfemnJHU9gbCAlgQb3FpXKRPKVa3n/i3fhy3bh5X9W60sXv2YPP64RAleXUPVkIgwlUpUa4hUKkxUoOF4h1vIGWTKNDKpgUIuK7vy4Yk0kgbhWTbE5iTdvh5Abf+iT09FYd5MnZrbHtFc/XKNdhWZHcUcO3TSWEsy+5pcbm+TmWSqffXgxQiOoxkDtuojJnNPjY1Kq7bNM1kOd1W+sNRSqaaa6wbz60bT/IJOo13MtSbT4WXsczNxyeX6pmKmhUVzcjiaaWF/wLSy6Ami/1vAAqX984sMYD75QT18X4OzFrG9LlhAf15X0FQWLA0ELVJxKMXXTH1jrnbuRbiLEnxrOImXm4MGGXPpN03lidKo1yiReJrYcMafY2ChZOxWGUZyfZNpRd9bJTm14NIoxWhJrt8w3K0yylM0+S0Ldg2GY6Ny/Tkw+i3FOyh0bk4J6h3FKydyYG7ARuVg1uDMNxUpGmDrG580KhrnQaxQnG2UdJG1hVdDWC796Je0hS8oXnii04NpJ16TvxbFePsLfjNHvpeWfyeN3DIX7PuFYZ0A5xNXv3J/A0364hPlJx9BH13LfgFEz5S/U4Iu7sk3rOn1CToZRsTxH/kY844Tp9C0SddPKW4oQL/u9Dny6fPa619DAI274GEi7anz5FPnQO68w58oPzkMkUbpPDXbec+tIsM7b+5xbMmtn3+ZooK59GLS/uPun0vq113KZsJc8P13Hx5U3igE7FVfXYfIac6fIo8LYhM7EDqt9SGBertBwyw9DG+nrIcuhYAOo2vzZ9wFXdXYng97v9wjsHJJCW1LsNcpsHDJca3WHRaemSmwm0NgY7L4tmjz7XlR/nMg14V6HTopATn0DOwJG4tJ2cFMQE34/L4MHwPUbvGOe/vHd3eb/CafnAxsPCIii8rnfy7PSAQiAVBHXHjW13KWeND9i2BvDOg8ax/j4vDGZiqgARu7jcH+HcPi7P9gMLftNZgRNGoEg16BQnWwpONHdrGOUaEdcB3Pr7mhWyPRjixXb1HvKai5Dnpx72BXp2uK6PGcVXmV7bJJbgmppD5GH8mtaCsfMPlMAV/1/5sdviDC9p/HjL0s+EariniG1AXlXV5D7AlPhPvHvd7x92HR97GGWF7JGCAUFHRVFp2q/JL2ZS0Th62Ovt9eXgQYJ8Pz2Zr6Vs0v988H3qus+bskH1WWy73zrCK8PHP6/0051Y5oRdWLpWDqBDHi9pR3+72r2zlWJ7M1ewAzVgBQjzccCaePRJRGG+x9ptEj1imuaBpsqoH7+khwuo1o/J7H+0NMXA0JB8HdFLzQv7GbksMr/KhHpeVU/Xz7tlyjqlIfxdeByrKM/6MmB6Bndl23oi2not0yiR1P1xTfnK+4la1sk7/DLf5ljdlv9rnk+HnE93FF/Dmvrt3IjBweU6QXHSxFCcnCLBA9qF/3rn4zROT/ohUTYtqB3UDt46Iy8gJWXu5MbI/3q76ifFnHwNaVB9/2luaClzKgbgi8oxsTRIZID3CC8Jhw8cgiPsCCfbES75nSdr2vUY63gjORCrz1HMX3ctmoYZZraMBAaJBC9K1hvBUtRijRoEt74bJAO7HL9bgqn0dD9B5GKNNGkqIhgBHKtLFsgdJvuSL8bxOMUKKJNp8x8w5Wwe1/k2CEMm2swTtxkhhB0sACCkxyD4HcA+yyx/pKs/PRTzRGm7NBExrQiC1ps2XlThwtL5DvTNCEhrQxKPyjQPNPJmwKG8LfxGh9ohIP6yfEd6RoQgMa02apqjXngtCEBgeMMXon7NscA7wGVoGgcAz+AM1dEKiHV16oL4K3c2uv2Ii3QOnuiFh6CZBrZGqYpcwyZjmzglnJfMd87/nhqQLVtK7JjHAfbWk7gLV2eelZLludqAjp2Oo56DU5gxSiJN6DxESVs7rO6L3AXPBeZC56r9Resct7lbnqvY4x0EYQvdbAyBiZZsbEtEwz70kMpAeIpM9PwfiDbYf7S3notybcVgPJBwHV+6cIKmv9SVd7YCfXegz0F/vMpjD3y/0iYSbP0JzbkKQ3zGEleGXadajfHOgUiprtEXiDWeY1ZUuhtt5LXcwf/2+Ooje9dAqLLu85nzChK8zthTBThOu3r8D6HUjJ/DbjHL2fwyKxrk7NZwywh91zqQtv083kXu8jMOjbWi+kaQ+x9UAOEJOlElAUg6FGMxFY07+3a9rvzvTj74k3mHuhA+1hcR1yLun5fCFNe4mtlvU9fBUh8T1KUGYWzhn6mTQgp4qUL5/3pG5i62cf31QUnPdlpSbTTPJXioBQsIAvNKk6Z6wQSEOE9uAALxoh9QH4crPmqzFtvqQwkPFdrTD3JglYpcGyvU7f6JJnzdAbLCl/6H5PS86N9IUJirKqA3SEucmkHOWXMPaEJpszL+teUpXzl/sCO2EwrBlrVn3rWznIrL3jczuHvsdy6tXN5LpoEQACAax/RADYQADgwIO/DiIkyNBRpVqHnPLEG8YYqcmumig5S9ReXyMtaEG1NXSgqz3r3TgOaojDHOGoxjCds3zWza2RqRd3c+Ycnuvnz3PNXD+3zwPz6jRntQSaL8yirNhqWd1rcM1bS1fNerKvs5PN3cG9eR/cJze/O3uyIcKAIIY29GIYY5iPZdiAQ2jC4WNKqWaKXUxzLpdwE3cKs7UcGtK4DvuinKyy0YhDbnK/V3i1t/tvH3bTAyu5rnyqY0pnVqc2RwKOhb49HWf4TJw397YZr/oO3vG7+765RYVVS3XXYM2rpVVTP1RtrasttbuOFFvdksuuuJqbRypSke+qRod7T2lVW7ule3per+nGftNpm5770zzHC7/U65LH59Nv7lv6fn+73v2vquinqKFIUgRjAqGVuSxhCb+xkR00xqk4ldn5UFXJv/1udrX1bvOAb+pfmujeHu3TfmjLQtlvGbGMXSYvMy60uVu2FWvYp/Gvy//KieWccnm5+R1f9V2/26AuWdIyP8qf5F814TKf+9END8TklXdlR8Xnlt6Ovd+/nU5YULRyp+zqsbz9NQQBEwDwaTKNSdo0w1C2TZM30O9+/67UACH4e7sATy7j6vDoZ+FFfmdOMlXHs505++ZiFxZF5ZsmKdQtcri/uqmgr0tkhd23iJZl0qbkIBMncDNwgUc/dQe9rM06vHFB34sruOBUloJnxIEJzSX9SPNElsPYQKeBRlWXBdU9PHUaXKJiE2oVDRzhchl0AKEmdGwTZS0bmktzMV/CEEk7XM4XaXXAGU1lQ5yMcaUC/95U61Va5Qjx1zkCB2iZmeuyjGAICCMceVVDToBkbGpWIBy9hXAMT9aiDNX5gAQVprgh4ae1Zy9oRdWbseXrcH81gvUA1xpnUX5LoGGc+uxTsibvSrO/9jcRkNYBGyfwTHO3XRcRwQgN3DiUcWOPyCKOCVFKshBoeslFHdHDLV5aRgKw4eY5Dw9xjk8goRE3MIJk/VluhIsC2TfMnq0IAYrx77CeoFjjLGCddp8q2e0NPXCT1RWIg1mW3PfoRpaitqOLB00i2GYaCNWVHiUEwII4j2j0I8qbKNugnIjMg443A0pSQNmPD+xB5Xby2TMhZp+O98kcuASF3327vTKCfqcDqlHorO2uu6MmhgQF4XH9/gffjpudYzx1oRAGc+cB8mxrkHZ4KMZEDeAYBf6sIEAonBgB6ehAVjUhzoHwBmeMOmlzxo2SG1GMM5QDSNc4i2bcEhiR8K0XF9Q3QI5haRjQVBnG4OVmo/V2q7VjQcjCCzG+B6IcMOXGKPvNX8u9AO5MyE1nLiZb0zqwUCHnlCtyhciJmg2t7IwARPt49Ur0gePgKadwRQFXqXJrClEq1hdcEB9OD40JARrhshAJZ6/hCJ4tkdAQpldHMuUnQsha67vhWvwIN+f6Q2yBzrFy3bxQ6nr8Yt5AysmXZcL5J3Ko8bZKqRcSyDgJJVA6ZTfv8vdcx/5bqwU+0OOwadyQdL+iiT2fW3bEqB9CEPj+1G+qOCnLy1IyQRlPfKm37IzvDJoB5eh0JQpsKaWQS1QxTU5p2iHLbeuTvI59P9iNqkWlTCHldkNFJbgiGDMNIkKpLEQxl6RRilyB7ca0KAXtHYcD4pl1Dow3R7nyFDM4c66ikVeiNW2lYKRmsWTZbIjPL0XGqEFRbjsTJAwnpyZMNhf/hr+jDSInIYFAIefCs4AO7gagjEamFq1JbmSDNUX8xrWa1QJljbOe4iAvbv5wP3VuPeOEYp7/MApswu8P1j8+gtzz49+lHdr9a4JcSUQ/G33Rt+N6C0qDywO3/mgPp0uv8uGsXFx/A+oBaQR4QnWcQEY05A7Uy6GNn3btlZf5rnIcQBhB7M9T5VVG/OJHjTp7IEDNtodmdWeW85Z5D+gxqCntSd7llHhyT8Ker74GULvqrifbwARTZAsS9lWW+La5ZJI8tZCl5IkE8lwdH7tzaRa6TkTLprvvk8oej1bRl2CmXqPc3TJCQMyIRdD3KSjuhyl3Jd9o8iN/a14yxIbCzEcdC3usN4PAjSmzYu88jDpv0oIUuwdmcjlBqBLSoqrilULRRDjU3DMLZdTqnra2VDzsswu+c3a258/s7WxJJxOJhGGkLioxgFo1PlwjWiokCUepNSNrRii2rM0au6Vvrw1xmLNJ9lH0INOoyhfca8vlvb5UOUA7iZWsNbdtCONYD41qd0fjd22uO64WJH7oBLgZ/5fzYXghMKc5OzEnkJuKrntuCaWGgtjuBPEhXP0sbzbb1apRIpLqQjZdMwwd0OiUJGThQ6gknJX1Fxv04/ywgaCRoozT2BkODZ2IJEHats5dkWJRNcpVAkdKSjKU4Ewcb9ahDb6dhlwA3fX3LPW62SiBN/I7q+PMFGHgfczDhCspRDvqw8b4JmdlxZUsi2wGYAcCyObS1F98T4u/DM/GSOOLlwbizeBJr0LsvWJKLhVvNTeHBzN3UFEXG+9l1fbQzfdXTcMxv5MtiajUquu3rQResYI335d3UZmnAFOnrCzFuZX+tZBZf/CucRZ4ztLzDMP3LChXp1v0rqIPFB+PlAIPUsScQwNC+uuy6IA7kxFrATS5XhnuYmkuLM+MWrSlCMure2m0w6zrtuRLlxU1VzAcumPgcCNSu97E57KfffLTRXpLXUiDVy/s5h77jcK+z54n5j73c7SuFYRBUOlKNpujokbQ6rLI4mzgFmEXl1V+NBo9u6DikpHciH7E3Qjj7uJBZpRpELIJbaOgLTUTwF/rLFBdkiu6jf/jjtRgs+3zWYSKcQ+H7AYUGcvrIWcSNeWCAdzA1utcMR4eNBm+Dox4odQ7XnUA6Rj2/3iJwxGzBkQrhg7cY5g4cg0rSAUNz153YTzH8C8H55wPSi3wTuoEQsfhopCqOWxfOI02ZyhhyMv7HUZYhXq+rEQaVQJpxDmXojZQpX5JTNbcxYgXYGxbyyAqKsjrm/a8vNJRg9F1Wy8iaFjqughwg6K1Y8koYSdMrbbGrxSTmpMsRsMkwM4VmznfFZwZQ2E/BCsuNgy2GWJbg32Ns6AbeBKjV71yNUNuR4hRqQWhjnHgHFm+uNbjFmhj8dXlKAqYXJNsI+HqiHs1joQhkTRajc4WiLGcWOx3u102vV4lkUno7GaH1xf22PVGs0FLotJQnnBdaQhVwUl89cXgOAODXLKRSKxd6cC7ziA32sQrUrsfRU7SemBzf1wWU6XnWo3DTsK53KuwAvoTryC0ba61PH24dKoZdBzndWfzdX4O0TEY85jDac5ezevkDafT1d+5WmceuxbQ8j4VoWqQtziXbo0FUWcj3Xj0Nk0r3tIoMrdt0yAhUR+NEFOcFrvd8ZifQiAFXBb86bTut+JU/aVjn1vTTD02fYAGxcXdjQld3NWRaQWgMDJy9+LwwfvbXM54hJj7pRIhNCwnEbk+GX8YMn+hG8FPXNb39bCqExS74IOkOjx0VQuBT8+YYu4k2KkKwdM+ejJfWLCOFoIvXT9IIhyyMLvcq6pIbHPpJhkDX8jhroHTqXZ7XlPKYgT3gygvd48Mi/0yo92kHHpMvamAlruKddCUErHAVHhS0+WSUl7zcpEg5ri/sqjJ1HD1XZFWFMdSI+D5JFFxPJgQRtEQe2K+jF8Kvb+rkdYgxYnYKud9X87Nwa5UShkHorJpkPBEFM0q/45accixAD4Yls7sZtolZ4xv/XWuY8Rmagy5974ypbVkQuVbB7Ibmmvv+DABzBGmye+dTHNGgTAZ/9fYn++KnXrLnDYe+70DdBnJlo8vtaEj3mi7Tbj8F/rj/5/w7sVxIq/sPUWXqpIznV4n7tGUoNpdP9eH8+DauzGigF33c/XnvnfmorrHOgG7TxbqK4fOvXluGJuND7fb43okKdiVd9lkcP5g+ofs4N/ey+8u4np3AubxOEBKf0kAXp4o+6FsVWa28dFvsVy7P7chCEghHhc82QimJKXHrNyoEULuxk+a/VcsnFcXDmbwmyfwPFnQtvR92zZhwDZNFzldC87PUpfqAUG1MEQBBMzx/OLlk45i+kDgM2cZurU/2/WjtDig7TkuxQ/RNHm2dlowHyRRotXt8mqCaA9Vnlfg8jxLppCBjMGLqeoEifae0umLOvW88HQ6S+p7cP5GWYgEszZhCMSQWFoZ4UbcIDFoXqRxf4TNcNJzVDBmPRbNFjzA7QHo//LLaP+nlhw+vX5c2BTA8N9w5UwhG5Do7NZVXUOOVE0aF2srycWm7V9bYTouCEdzfMXC30YrJpPi1lCc2tsqPoSaU1GBsPbkWi4KAVFa2bvWqTA3b95cFEG/T5VYHrQcdq0qbOWAel7tigIPZmjlLrmCPJJjtJvCjlalyDGlAtKYassRMTh4E9scf7mN8C0G1uCP86a5oKyKsMpLrlkwl3KE3Mk7+TtN4bze7mhNxQ6N5fBgvebAoeoV+cOMJueronJRXXkWwDLGBptcZd9zykwY2XPX6UUhMg0y1axGJqw2P2DPNGcdwzcuUi6jHz5ZRbHEJzv1lhCY9r/MSFwoAY+dP9De6sXPFbswwq0USrmDv3HXjHL6bMe4SBpgxOm0S7TCHHMWm8HAMTAnrAKVpflBGeW1bnPI8WV8BYk53eXCNhZTcHhY3ci5YEZtwXcRGZkwGFhlNSJz7YKYqbAF3VwuFKjp/gzRggt6JB02IK3EOO8KbuTWSRE6/Z8wTpwOLYfBNhEHLRqtpVh1rugGKiuIm2EomVX1XRsvVRC3u3v+Zt6vkT1OciaZslwlGDZWPvVS2YurTLzlNchWZV5Sipl61g1Io1NZub3c7S+C8HT6sus46LMk5LqZ2pZLBCBzBK57x+oxV72iQR4MquH4zCu6w1g2PgVubZR2aaXntVqy1N36DXDiQmN+mZ5yu8tdG9ooaQ/TA06tmNLhtltNvWKF7+1Ibx4EIPAGAr5AyN0Jg2FFCy0pmHAiKjyE2khe3RG0o5e5pKlpnBkt8F4eVDVooq6Crcfq3Vf3fFody5x/lXPUOyYgUtMBbqpxDJLPLMNG1er0yiahlrYYmeZbd4Ulyqa/ZfNIBQgMi1t46b40ZeRNjA8Xi76va0KSECEPnskopGSNg5hndF/dMQVjfo9BORQpUiFXze6uO8p7dPKHbs4o1ziqie1c2vQINDovpLCgYdsKUim25jO2jwkdnEYbOj9Tj6fFMm3fB9DRpwATDMuBbqXsew0dZruXHnk/CHzEqf3jMB8PhSIxziJ/5ONM8iqSqwdhRo5J+KroFq/QpgmhVPWoLiinCTy3odjr1s50xMWcT1iHkkzUslhkCRIGUXe5bnGQ8m531+6PQOiymFQrGvBZd3id5H0axWM/Z1I0jKQgazxGqgWE0uYXkPYCMyS87p04OCNQ6691VmAII7E/9qbjN/4OgfMsFIzOwwETrgo4EmMnaQJNwYJ/GoHkPu+deY/Ma18giB+QBV6NRnipuBHnyyvnMJGaYJfnvU+LsgjLK+baNyAj+3/Q1wuNOdt0rW+apHiCH1xeCV85x1mcNPkO+2McuX5qnzPkxi++lLNQkG4QlRd28B/fkNgaF0+1is+UkETYRXIXrpqiONpx0T1X1JyK9BK0BtSMF7rqc2cCiyW/cFZl8D51xpd9EXdndzK1Tvb9NssL7g4ZDDG5y7sNv3w3PaCSBd8mdExT5Nb0cTANcC7uAKQQFhzdlQ8rmsPJuzFuu9eNb9M4+1feeMjivO6qHOMROwwwxAOHoNxt7q42nee8YHC+O676SDjGmHojoOhLpewswh2DGfGVEGCBOE7aYdWNya2nu84G+Yyrm6O+P25rX0rwisW7z5P4W542CyzTKOPf9Wv83FYtC5B+n4aSv3lZCXpfAP88N+p4wS9O3s4ne5QSic1FBhvJQ2MhR1yc14xJhAnMa7EEhsj31JlksIsLNkDrE8U61oFcXH77LH0FAeWGvkd0sHpgX8Q2FTcTH/L37gH81QDE7/DFBOO28azaYdMAwp0JRlAG2dOEVR0PCnCC31J+dqCgMpSOayV3a4vcOrY4QQMxaE4UstxRjDMLdGWvc5XQZ52oZs7eg1BiyYc0focxUVD/46TcHeJSvJNL1amYhstQ6JQ6nsIzWCHL6zrPGGKhKyr9N4qs6VcYDkjjkkyorJZ9rRw83S54ceo8SgNRTdZF1p5U5ggPyH116BZUJqVEPWxv2O/Eix0Kt/uZr9RzLslAX7ZoO2T9Q6dyssGu+L6lxQ9BwK3VZsUQZK68xyZumirP2nowEfmjOwoir/S132o0GCJFg9tG1HSNzv98+r3O4ooYST4/5cCO4NInC9rfjgjN4oZuwIiBDGHnRT2A3QE9FgzbeIPmt4l0IdgAjtLD1QdRKRlsYXPbm4+KBwrlPFpt33WPG+aNq3IP5VBkpFMQWno+q7rGmuvSw1GUZdW0wB9RidIQmqtyf7igNJsGNM8TaI9emgVNb5oasQR+HUzj3qvysJON8KS8d1DoeQ6kOTHNui3ZqCRyhX1yxjY0Q9YWrKD4Pnu66/kK7crcIcGXQ2W6DW9VXZf7/vkmifUgcwiG4OhiC5JKdAneTbozS76EMYYA+7gLTdXT2liEqjZ5R5NGkurBJERIUONYawOziuvQXloF0W5p4VbxO0OtCpaAw79/r6mKyWo0w/M7zQshjktAxHKiPLz/Ht7wrDV7ZpzI3H/4rX3THU/EZ/Y8e1YTCJOYb3GaLmoUr2MfOzhURmA4i15ZzRU654c7C2pPBjORENJkJgZVKTJJVzncYCBRZhYxhI9oumBErZFsUb23QLZ6n0Kj5GAIxbXlT7RDvIR1Q5xPHAExohJxljKjsQ1BVmcBIrEbIbDx55nDlUkmW+KB0rbgiXAKiCqb+hxJM5bLJSLidgzatCxODswqhT+QiENXPBKmGj93N7dSaHSOkMn8eNWu7AjYSIKBIYM8HFlSViHNarc73ixMd4X++ubBaDv8RyJdohq+jsgBIUq1z/DxbMX723KsmX8M7qVLAYjjghCjuxzQnfiRvVEuspSsT4pSPROmO9y/oTcSTOXMpUEaA+rFUpRtTgmTrWAjBxqWBzQyuSMz+O/LGmEd8kg4EUYQ8dmbnTsZOQESLM/aKW7g/4gcoJY7D1Tt/ruF6gFC1cFiEhVs/nKSauKbAyapN5uX9T0Z16ayddJ3Gx858wHKxZzTpsOKTRFt8ixNGsoCJ+kLAncwf0mCEFCVm2MU/yPrEF2l/rcaYn46x8CxLIyMevtlCUpYma4OsuE9tOpIbeyvz9FAzAOxUVoWFejZkrnBVu56E+cpaAaDWc5z1OXbQdQxigmAESLPAkZCpAhyl/J+mno/3eNeZXbrBC6ppK8O2ZV94XxL19ycNLHzXQhlexbNEoax4mCrOJMOCEfgebaoZ1ar2o3U2z90WKrMi8JAjhEJW62gn3exYqvcTy7gnXdEavtVODCwQvWWLOdazhW7sR8K5kozQWYpc3RS63B76FgNljmV3vqkxUELxMbfVU/r6LBOKlWT29jF013deApRHRVza5oL3OyGv17/nrZQM0TQPi+iGXA3N6LBRuEYYik5luhRZZV+JuKp1Or5WukK1cP7h3XAK4yL9uwYuXUBxdAC2uDjYhxkOjwFjAXG5khwCCvqBfi2vwNYjPAjrp4qWltckbU77NDPv/geZ//toyp2Kiv/Gv2ofo2xTOq9bz2QbYtwkc/Fzh2N3JszaqBQ1dut0pYyh6DcHIMMaKW4K4uvHKEdUmbAtVa0GRklrxW0iQ5wGYAnMO1givhcknO0R0IPfgjza/T7aZY8kfFlQRPUpkbinpLq7UmFdv2KkA04SsnuKkXKecSl2IT97yceGNURHJM4f2qP43qOacjI2xjDwMmYlE8vdVWKet965td93625rh/K7gPwaMxjLV4RxmgNPhEdWpDjkORpeM9PIVNgTnBBRBPMJvVz0A7vT7+v3Z7uqWIntwb1vpK7KbP8tAgHfno6jmxC72Vk/PrAyWZvZIVi8Tj6Qy4B96oYuUvZpvorsyKZufM6KZqZCHauwbmN6QI2B7eDaaH//20HiLIWx20ilWTgxc/xHYO8xwb4pJlj6ob4EsiZxS5KcTtb3jvXWhA/PpVBrU7/3b3DRazd41k9ec1aw+I2V9BjMc53R8/bkoNyRVtXKo/5V1imlJaVOk+nqh4Imhx5bVcoSfjpp6v0/EP2uJpC6rfGhdss4bM4tqG+8+qsXd8nWoTbk/psdtfoXdu5uedd/PI0DZyQco113749uAO4Ro/9ra5zrV6aIayXyZ1Y9s1X/WkfpPHvtvCbPAXPp+KR3xmGeHN4uFEkuzf8wYRVys/cqrq0VvKS2bks/hQ8Br3Ck3NK0b9LUi72LsJbkRSX3iBZJqO5Du8rIsyv2g3owoHqtT1En75jR5k9GccOW9sqOv7oGDV7xseAlZCGzZvSJSwV/l629tvF9bbLB32Z2rbB3DNbglR310cu6+jm77FPvS23Aljqwe1R17CAzq9h8Rw84wvlZhKjjcwvOHqed8qb7wY71np72B/iraUWxkwBkv60gB1tnr4o7vYTAjnfU3h4FUDSPOnbxfLEe2hC4Qt5qDtvxS451qAmkpFya58dz0SNOLi7ZK0B5RjACxH65lgO0gYfpTqpehy7oG9oJqix8BY59iWSiUMHqA+Z0prmgn+Pvl2vgv9n7tYzk1tx7FafWVTy0CepnFXHW7DZp6K4GM9TvxJzg1+w4VQIuuab7rxu07u5m6YJGRwhNuaf51lAQGwjxBMps9UQJtXjQ7mLjViRNS9AU9IMYdSzdBS+4BULpHi2oxb9Hbg/GK23PJ4TbuhujrNuXdz8Wcc1f79N4cHzrxXiRXpZieYYCcRRvzIMQK11fHd6s4ZfUg556LVqMMN3zLitNkfrKY0Gx2crCQgAd/k3v/Zjx7i1/H+J81cA3N37OBQAeHQWe/D/pS3qgL2eAVCAAQAI+PAo2rGEhIsjqD/EFNBtof2SvTbs+HQLpk5J90tQ/NeUHOMNTZYSwNPPqujB/ADUyI/AnHkh6ZthRiIYrWT4desVEa/WMyT4lipiHYE26kx3x0CrkJ7d+BCB3dKVTvS/TV66zrMrqVnh9lU5YEfB1Sp5tUpE+kb0MDXQ5zJdTQ3AehZlGbFRsFzNFNN7JRXT9DVzSqMEMjua3k0CgjTRh2yNgHxPEa8Wnc431pCIIiinSwt9fhTc1rjxMQILkQP3aVDzHM7NhxVjSSMsuihKurL5hL4sCjaWguVTY+AWN6cGRBAma8mAcK0zC2kQkg7PHL6ELPBnfEEHgdAevM4UH2eBTXPEOmSMuejLU5tStFEiNTgFeIVnkgb1ONOe1zCoztbx8tAl7/BpgG9qt/c4nJD5IvWyk7ehqkIxrY3CYAZ8kxASkChO+QElPJOclUoSCL9oSbwqQRO6ZChk0GU5f1/S+P+EfVFirToUq+1g0ZHs3SQazd+ReFjJRk9S34Ae4As6sEHBvq25xmImGlKf3WgIOXKf8ZxokKdBGVyBvtpTFhaAvrQ/nlmZVu890AZOyIfH0IcpeWZBz6oX5KSFmkwgdIf7MBhmaZlMoC5pRv4WTyOAAhQQkUcAQY2whXYe4CBBxboGaCBEamhgsMKrBo5ihgYBmbE2iIjNhgYFknNhHytENu8gxKBhqQ0capbfIMC5AU0KSdBgBa/2UutfMMsabCjYbw22JLaWOlWZDQ/GmZod+t0aPXqN6NeuVZsBGO7ybQmMZwOpTLu0bu0l2tPv1y2p26yEUz9pR1Vt8pGApUHberXfSSX7xj3tXedKWaxWf7Stnm7EbOrTXVh6qt1WmuzxC39Kd1FwqX36KBF1cri9YlidYdpfaLLGV84lpVVapyQ6eUxOvGmZncMVnaGPsJL/PtsDMLA2BA6E6VCfkjSq7dL0x0SMCS20J9DO4m/SMDZTwuSKokn0njMc1abyIDw4UZmR0c5Iskxba6d00LPyS/mmfqrNHdXhTtuvNDmqGA46ekCtV3UoVmJDMo5ZavSl2oOoXe6KkEuKhZqcmAm36iofEmvzVKC+K1nBf0aIAvidzaDV6FiT4+sIxGakX5BTnxcll0Kl0Zfj63nJZQwmS/6vZAvuBz7U6mPrT/yXR+G8Fy5CZKYhSrRrrhvqhhix4sR7KyEZJCL9Aw17Dleh3GoZBZ+b5Y1sVdkuN1KOXHn0bo7DjTM+MzBWx2SW52e2sy4m6GqiyaaYZI2ptivwQaEixRYoUWqaajNM/4wsn2pP7+zTK1mkwiGHo8bvatkv1xhe6nChG/cPNf4oVmRNNksb29VUWzVRHwr/P2vyL0OtwoQNV0N4nPwjRmLLGh48bSTgDz7WOmoeSyhgJylkNqFosEMqC2jQW1+Jkh1z3E677LbHehsccJAINXypMN9ciyy02Ky0jaaPV2bbT0ntzfFDOrDCR5/s5cVbKyv1UyclTBIFxY4TN178BAkTJU6SNFnyFClTBQWnTpM2XfoMGTNlzpI1W/YcOUNy5c6jRpolbrnvtjsepCjfjzsDbuxPDaYy093tHJ1EV2RKNqUHUnEzs7OnqdNu1eaamObs9nbS47LsBfEvm9sO562p/q5kd3Nj5yzmcuvzovbbyXZ47Uwv+7f+cJ/Avsnq6U7tmg8Mmfo5X6GfnV72N+tvGhbtg86VWe3D/CEBusHvBqAbi+72fWso90ntDtzlQBBqIbhBkDpwXUGq4BbBdfZCzL4j0dPcJO+Cyx66ixpXxt8urtbSbfai3mB+p+InAVjTD0HgUYo1sGevuXbGzykYzPhFAb2M761JHzFX9wFVr/Lq9aThvmasc3ocbvxxgz9TfyNgPzs/ztB0sEbfup090N7ZvCm5vLZaL80W9/HaiYGcnp6oqDYTrm/1rK2nZ2aysUfQOq+5Z+AXD7xYqzTDtLf+2wP9ovjevEm6UcGWbvJA27C8WF9twkpujwo2Xv27oJX1L1VH4n0X6Sxvq2XXTs2bN9WtRfslPfU6kYe23y3rZGbMvaPRe2oAAA==) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Nunito Sans;font-style:normal;font-weight:700;font-stretch:100%;font-display:swap;src:url(data:font/woff2;base64,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) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Nunito Sans;font-style:normal;font-weight:800;font-stretch:100%;font-display:swap;src:url(data:font/woff2;base64,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) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}.vuu-theme{color:var(--salt-text-primary-foreground);font-family:var(--salt-typography-fontFamily);font-size:var(--salt-text-fontSize);letter-spacing:var(--salt-text-letterSpacing);line-height:var(--salt-text-lineHeight)}::selection{background:var(--salt-text-background-selected);color:var(--salt-text-color-selected, inherit)}.vuu-theme[data-mode=light]{color-scheme:light}.vuu-theme[data-mode=dark]{color-scheme:dark}*,*:before,*:after{box-sizing:border-box}.salt-visuallyHidden{position:absolute;height:1px;width:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.vuu-density-touch,.vuu-density-low,.vuu-density-medium,.vuu-density-high{--salt-animation-opacity-start: 0;--salt-animation-opacity-end: 1;--salt-animation-scale-start: 0;--salt-animation-scale-end: 1;--salt-animation-transform-start: 100%;--salt-animation-transform-end: 0;--salt-animation-duration: .3s;--salt-animation-timing-function: ease-in;--salt-animation-slide-in-top: slide-in-top var(--salt-animation-duration) var(--salt-animation-timing-function);--salt-animation-slide-in-left: slide-in-left var(--salt-animation-duration) var(--salt-animation-timing-function);--salt-animation-slide-in-right: slide-in-right var(--salt-animation-duration) var(--salt-animation-timing-function);--salt-animation-slide-in-bottom: slide-in-bottom var(--salt-animation-duration) var(--salt-animation-timing-function);--salt-animation-slide-out-top: slide-out-top var(--salt-animation-duration) var(--salt-animation-timing-function) both;--salt-animation-slide-out-left: slide-out-left var(--salt-animation-duration) var(--salt-animation-timing-function) both;--salt-animation-slide-out-right: slide-out-right var(--salt-animation-duration) var(--salt-animation-timing-function) both;--salt-animation-slide-out-bottom: slide-out-bottom var(--salt-animation-duration) var(--salt-animation-timing-function) both;--salt-animation-fade-in-back: fade-in-back var(--salt-animation-duration) var(--salt-animation-timing-function);--salt-animation-fade-in-forward: fade-in-forward var(--salt-animation-duration) var(--salt-animation-timing-function);--salt-animation-fade-in-center: fade-in-center var(--salt-animation-duration) var(--salt-animation-timing-function);--salt-animation-fade-out-back: fade-out-back var(--salt-animation-duration) ease-out both}@keyframes slide-in-top{0%{opacity:var(--salt-animation-opacity-start);transform:translateY(var(--salt-animation-transform-start))}to{opacity:var(--salt-animation-opacity-end);transform:translateY(var(--salt-animation-transform-end))}}@keyframes slide-out-top{0%{opacity:var(--salt-animation-opacity-end);transform:translateY(var(--salt-animation-transform-end))}to{opacity:var(--salt-animation-opacity-start);transform:translateY(var(--salt-animation-transform-start))}}@keyframes slide-in-left{0%{opacity:var(--salt-animation-opacity-start);transform:translate(calc(-1 * var(--salt-animation-transform-start)))}to{opacity:var(--salt-animation-opacity-end);transform:translate(var(--salt-animation-transform-end))}}@keyframes slide-out-left{0%{opacity:var(--salt-animation-opacity-end);transform:translate(var(--salt-animation-transform-end))}to{opacity:var(--salt-animation-opacity-start);transform:translate(calc(-1 * var(--salt-animation-transform-start)))}}@keyframes slide-in-right{0%{opacity:var(--salt-animation-opacity-start);transform:translate(var(--salt-animation-transform-start))}to{opacity:var(--salt-animation-opacity-end);transform:translate(var(--salt-animation-transform-end))}}@keyframes slide-out-right{0%{opacity:var(--salt-animation-opacity-end);transform:translate(var(--salt-animation-transform-end))}to{opacity:var(--salt-animation-opacity-start);transform:translate(var(--salt-animation-transform-start))}}@keyframes slide-in-bottom{0%{opacity:var(--salt-animation-opacity-start);transform:translateY(calc(-1 * var(--salt-animation-transform-start)))}to{opacity:var(--salt-animation-opacity-end);transform:translateY(var(--salt-animation-transform-end))}}@keyframes slide-out-bottom{0%{opacity:var(--salt-animation-opacity-end);transform:translateY(var(--salt-animation-transform-end))}to{opacity:var(--salt-animation-opacity-start);transform:translateY(calc(-1 * var(--salt-animation-transform-start)))}}@keyframes fade-in-back{0%{--salt-animation-scale-start: 1.4;opacity:var(--salt-animation-opacity-start);transform:scale(var(--salt-animation-scale-start))}to{opacity:var(--salt-animation-opacity-end);transform:scale(var(--salt-animation-scale-end))}}@keyframes fade-in-forward{0%{--salt-animation-scale-start: .6;opacity:var(--salt-animation-opacity-start);transform:scale(var(--salt-animation-scale-start))}to{opacity:var(--salt-animation-opacity-end);transform:scale(var(--salt-animation-scale-end))}}@keyframes fade-in-center{0%{opacity:var(--salt-animation-opacity-start)}to{opacity:var(--salt-animation-opacity-end)}}@keyframes fade-out-back{0%{opacity:var(--salt-animation-opacity-end)}to{opacity:var(--salt-animation-opacity-start)}}.vuu-theme{--vuu-fade-light: .13;--vuu-color-transparent: transparent;--vuu-color-black: black;--vuu-color-white: white;--vuu-color-blue-40: rgb(164, 213, 244);--vuu-color-purple-10: rgb(109,24,189);--vuu-color-purple-10-fade-light: rgba(109,24,189, var(--vuu-fade-light));--vuu-color-pink-10: rgb(234, 120, 128);--vuu-color-gray-05: rgb(222, 222, 222);--vuu-color-gray-10: rgb(228, 227, 231);--vuu-color-gray-20: rgb(245, 242, 248);--vuu-color-gray-25: rgb(244, 244, 244) ;--vuu-color-gray-28: rgb(249, 249, 251);--vuu-color-gray-30: rgb(214, 215, 218);--vuu-color-gray-35: rgb(155, 158, 168);--vuu-color-gray-40: rgb(169, 170, 173);--vuu-color-gray-42: rgb(135, 139, 158);--vuu-color-gray-45: rgb(119, 124, 148);--vuu-color-gray-50: rgb(96, 100, 119);--vuu-color-gray-80: rgb(21, 23, 27);--vuu-color-green-50: rgb(102, 174, 90);--vuu-color-green-60: rgb(36, 137, 19);--vuu-color-green-60-fade-30: rgba(36, 137, 19, .3);--vuu-color-red-50: rgb(226, 52, 52);--vuu-color-yellow-20: rgb(244, 202, 51);--salt-color-white: rgb(255, 255, 255);--salt-color-black: rgb(0, 0, 0);--salt-color-red-10: rgb(255, 227, 224);--salt-color-red-20: rgb(255, 207, 201);--salt-color-red-30: rgb(255, 187, 178);--salt-color-red-40: rgb(255, 167, 156);--salt-color-red-50: rgb(255, 148, 133);--salt-color-red-100: rgb(255, 128, 111);--salt-color-red-200: rgb(255, 108, 88);--salt-color-red-300: rgb(255, 89, 66);--salt-color-red-400: rgb(237, 65, 42);--salt-color-red-500: rgb(227, 43, 22);--salt-color-red-600: rgb(196, 32, 16);--salt-color-red-700: rgb(166, 21, 11);--salt-color-red-800: rgb(136, 10, 5);--salt-color-red-900: rgb(65, 37, 34);--salt-color-orange-10: rgb(255, 232, 191);--salt-color-orange-20: rgb(254, 223, 166);--salt-color-orange-30: rgb(254, 214, 142);--salt-color-orange-40: rgb(254, 205, 118);--salt-color-orange-50: rgb(254, 197, 94);--salt-color-orange-100: rgb(250, 181, 81);--salt-color-orange-200: rgb(246, 165, 68);--salt-color-orange-300: rgb(242, 149, 56);--salt-color-orange-400: rgb(238, 133, 43);--salt-color-orange-500: rgb(234, 115, 25);--salt-color-orange-600: rgb(224, 101, 25);--salt-color-orange-700: rgb(214, 85, 19);--salt-color-orange-800: rgb(204, 68, 13);--salt-color-orange-900: rgb(54, 44, 36);--salt-color-green-10: rgb(209, 244, 201);--salt-color-green-20: rgb(184, 232, 182);--salt-color-green-30: rgb(160, 221, 164);--salt-color-green-40: rgb(136, 210, 145);--salt-color-green-50: rgb(112, 199, 127);--salt-color-green-100: rgb(93, 189, 116);--salt-color-green-200: rgb(77, 180, 105);--salt-color-green-300: rgb(60, 171, 96);--salt-color-green-400: rgb(48, 156, 90);--salt-color-green-500: rgb(36, 135, 75);--salt-color-green-600: rgb(24, 114, 61);--salt-color-green-700: rgb(12, 93, 46);--salt-color-green-800: rgb(1, 73, 32);--salt-color-green-900: rgb(35, 52, 43);--salt-color-teal-10: rgb(218, 240, 240);--salt-color-teal-20: rgb(199, 232, 232);--salt-color-teal-30: rgb(180, 224, 225);--salt-color-teal-40: rgb(162, 217, 218);--salt-color-teal-50: rgb(141, 205, 209);--salt-color-teal-100: rgb(123, 193, 200);--salt-color-teal-200: rgb(99, 181, 192);--salt-color-teal-300: rgb(73, 160, 172);--salt-color-teal-400: rgb(48, 149, 166);--salt-color-teal-500: rgb(0, 130, 151);--salt-color-teal-600: rgb(27, 107, 133);--salt-color-teal-700: rgb(0, 85, 113);--salt-color-teal-800: rgb(1, 65, 86);--salt-color-teal-900: rgb(0, 49, 76);--salt-color-blue-10: rgb(203, 231, 249);--salt-color-blue-20: rgb(183, 222, 246);--salt-color-blue-30: rgb(164, 213, 244);--salt-color-blue-40: rgb(144, 204, 242);--salt-color-blue-50: rgb(125, 195, 240);--salt-color-blue-100: rgb(100, 177, 228);--salt-color-blue-200: rgb(75, 159, 216);--salt-color-blue-300: rgb(51, 141, 205);--salt-color-blue-400: rgb(46, 132, 198);--salt-color-blue-500: rgb(38, 112, 169);--salt-color-blue-600: rgb(21, 92, 147);--salt-color-blue-700: rgb(0, 71, 123);--salt-color-blue-800: rgb(39, 60, 77);--salt-color-blue-900: rgb(35, 47, 56);--salt-color-purple-10: rgb(249, 224, 247);--salt-color-purple-20: rgb(247, 212, 244);--salt-color-purple-30: rgb(245, 201, 241);--salt-color-purple-40: rgb(243, 189, 238);--salt-color-purple-50: rgb(241, 178, 235);--salt-color-purple-100: rgb(223, 156, 225);--salt-color-purple-200: rgb(205, 135, 215);--salt-color-purple-300: rgb(192, 116, 203);--salt-color-purple-400: rgb(169, 97, 181);--salt-color-purple-500: rgb(150, 78, 162);--salt-color-purple-600: rgb(129, 60, 141);--salt-color-purple-700: rgb(103, 46, 122);--salt-color-purple-800: rgb(83, 37, 109);--salt-color-purple-900: rgb(59, 16, 84);--salt-color-gray-10: rgb(242, 244, 246);--salt-color-gray-20: rgb(234, 237, 239);--salt-color-gray-30: rgb(224, 228, 233);--salt-color-gray-40: rgb(217, 221, 227);--salt-color-gray-50: rgb(206, 210, 217);--salt-color-gray-60: rgb(197, 201, 208);--salt-color-gray-70: rgb(180, 183, 190);--salt-color-gray-80: rgb(159, 163, 170);--salt-color-gray-90: rgb(132, 135, 142);--salt-color-gray-100: rgb(116, 119, 127);--salt-color-gray-200: rgb(97, 101, 110);--salt-color-gray-300: rgb(76, 80, 91);--salt-color-gray-400: rgb(68, 72, 79);--salt-color-gray-500: rgb(59, 63, 70);--salt-color-gray-600: rgb(47, 49, 54);--salt-color-gray-700: rgb(42, 44, 47);--salt-color-gray-800: rgb(36, 37, 38);--salt-color-gray-900: rgb(22, 22, 22)}.vuu-theme{--salt-duration-instant: 0ms;--salt-duration-perceptible: .3s;--salt-duration-notable: 1s;--salt-duration-cutoff: 10s}.vuu-theme{--salt-color-blue-100-fade-foreground: rgba(100, 177, 228, var(--salt-palette-opacity-disabled));--salt-color-blue-500-fade-foreground: rgba(38, 112, 169, var(--salt-palette-opacity-disabled));--salt-color-blue-600-fade-foreground: rgba(21, 92, 147, var(--salt-palette-opacity-disabled));--salt-color-gray-200-fade-foreground: rgba(97, 101, 110, var(--salt-palette-opacity-disabled));--salt-color-gray-70-fade-foreground: rgba(180, 183, 190, var(--salt-palette-opacity-disabled));--salt-color-gray-90-fade-foreground: rgba(132, 135, 142, var(--salt-palette-opacity-disabled));--salt-color-gray-900-fade-foreground: rgba(22, 22, 22, var(--salt-palette-opacity-disabled));--salt-color-green-300-fade-foreground: rgba(60, 171, 96, var(--salt-palette-opacity-disabled));--salt-color-green-400-fade-foreground: rgba(48, 156, 90, var(--salt-palette-opacity-disabled));--salt-color-green-500-fade-foreground: rgba(36, 135, 75, var(--salt-palette-opacity-disabled));--salt-color-green-700-fade-foreground: rgba(12, 93, 46, var(--salt-palette-opacity-disabled));--salt-color-red-300-fade-foreground: rgba(255, 89, 66, var(--salt-palette-opacity-disabled));--salt-color-red-500-fade-foreground: rgba(227, 43, 22, var(--salt-palette-opacity-disabled));--salt-color-red-700-fade-foreground: rgba(166, 21, 11, var(--salt-palette-opacity-disabled));--salt-color-white-fade-foreground: rgba(255, 255, 255, var(--salt-palette-opacity-disabled));--salt-color-blue-500-fade-border: rgba(38, 112, 169, var(--salt-palette-opacity-disabled));--salt-color-gray-60-fade-border: rgba(197, 201, 208, var(--salt-palette-opacity-disabled));--salt-color-gray-90-fade-border: rgba(132, 135, 142, var(--salt-palette-opacity-disabled));--salt-color-gray-200-fade-border: rgba(97, 101, 110, var(--salt-palette-opacity-disabled));--salt-color-gray-300-fade-border: rgba(76, 80, 91, var(--salt-palette-opacity-disabled));--salt-color-green-400-fade-border: rgba(48, 156, 90, var(--salt-palette-opacity-disabled));--salt-color-green-500-fade-border: rgba(36, 135, 75, var(--salt-palette-opacity-disabled));--salt-color-orange-400-fade-border: rgba(238, 133, 43, var(--salt-palette-opacity-disabled));--salt-color-orange-500-fade-border: rgba(234, 115, 25, var(--salt-palette-opacity-disabled));--salt-color-orange-600-fade-border: rgba(224, 101, 25, var(--salt-palette-opacity-disabled));--salt-color-orange-700-fade-border: rgba(214, 85, 19, var(--salt-palette-opacity-disabled));--salt-color-red-500-fade-border: rgba(227, 43, 22, var(--salt-palette-opacity-disabled));--salt-color-gray-90-fade-border-readonly: rgba(132, 135, 142, var(--salt-palette-opacity-border-readonly));--salt-color-gray-200-fade-border-readonly: rgba(97, 101, 110, var(--salt-palette-opacity-border-readonly));--salt-color-blue-30-fade-background: rgba(164, 213, 244, var(--salt-palette-opacity-disabled));--salt-color-blue-500-fade-background: rgba(38, 112, 169, var(--salt-palette-opacity-disabled));--salt-color-blue-600-fade-background: rgba(21, 92, 147, var(--salt-palette-opacity-disabled));--salt-color-blue-700-fade-background: rgba(0, 71, 123, var(--salt-palette-opacity-disabled));--salt-color-gray-20-fade-background: rgba(234, 237, 239, var(--salt-palette-opacity-disabled));--salt-color-gray-60-fade-background: rgba(197, 201, 208, var(--salt-palette-opacity-disabled));--salt-color-gray-70-fade-background: rgba(180, 183, 190, var(--salt-palette-opacity-disabled));--salt-color-gray-200-fade-background: rgba(97, 101, 110, var(--salt-palette-opacity-disabled));--salt-color-gray-300-fade-background: rgba(76, 80, 91, var(--salt-palette-opacity-disabled));--salt-color-gray-600-fade-background: rgba(47, 49, 54, var(--salt-palette-opacity-disabled));--salt-color-gray-800-fade-background: rgba(36, 37, 38, var(--salt-palette-opacity-disabled));--salt-color-white-fade-background: rgba(255, 255, 255, var(--salt-palette-opacity-disabled));--salt-color-white-fade-background-readonly: rgba(255, 255, 255, var(--salt-palette-opacity-background-readonly));--salt-color-gray-20-fade-background-readonly: rgba(234, 237, 239, var(--salt-palette-opacity-background-readonly));--salt-color-gray-600-fade-background-readonly: rgba(47, 49, 54, var(--salt-palette-opacity-background-readonly));--salt-color-gray-800-fade-background-readonly: rgba(36, 37, 38, var(--salt-palette-opacity-background-readonly));--salt-color-black-fade-backdrop: rgba(36, 37, 38, var(--salt-palette-opacity-backdrop));--salt-color-blue-100-fade-fill: rgba(100, 177, 228, var(--salt-palette-opacity-disabled));--salt-color-blue-600-fade-fill: rgba(21, 92, 147, var(--salt-palette-opacity-disabled));--salt-color-white-fade-separatorOpacity-primary: rgba(255, 255, 255, var(--salt-palette-opacity-primary-border));--salt-color-white-fade-separatorOpacity-secondary: rgba(255, 255, 255, var(--salt-palette-opacity-secondary-border));--salt-color-white-fade-separatorOpacity-tertiary: rgba(255, 255, 255, var(--salt-palette-opacity-tertiary-border));--salt-color-black-fade-separatorOpacity-primary: rgba(0, 0, 0, var(--salt-palette-opacity-primary-border));--salt-color-black-fade-separatorOpacity-secondary: rgba(0, 0, 0, var(--salt-palette-opacity-secondary-border));--salt-color-black-fade-separatorOpacity-tertiary: rgba(0, 0, 0, var(--salt-palette-opacity-tertiary-border))}.vuu-density-touch{--salt-icon-size-base: 16px;--salt-icon-size-status-adornment: 12px}.vuu-density-low{--salt-icon-size-base: 14px;--salt-icon-size-status-adornment: 10px}.vuu-density-medium{--salt-icon-size-base: 12px;--salt-icon-size-status-adornment: 8px}.vuu-density-high{--salt-icon-size-base: 10px;--salt-icon-size-status-adornment: 6px}.vuu-theme{--salt-opacity-0: 0;--salt-opacity-8: .08;--salt-opacity-15: .15;--salt-opacity-25: .25;--salt-opacity-40: .4;--salt-opacity-70: .7}.vuu-theme[data-mode=light]{--salt-shadow-1-color: rgba(0, 0, 0, .1);--salt-shadow-2-color: rgba(0, 0, 0, .1);--salt-shadow-3-color: rgba(0, 0, 0, .15);--salt-shadow-4-color: rgba(0, 0, 0, .2);--salt-shadow-5-color: rgba(0, 0, 0, .3)}.vuu-theme[data-mode=dark]{--salt-shadow-1-color: rgba(0, 0, 0, .5);--salt-shadow-2-color: rgba(0, 0, 0, .5);--salt-shadow-3-color: rgba(0, 0, 0, .55);--salt-shadow-4-color: rgba(0, 0, 0, .55);--salt-shadow-5-color: rgba(0, 0, 0, .65)}.vuu-theme{--salt-shadow-0: none;--salt-shadow-1: 0 1px 3px 0 var(--salt-shadow-1-color);--salt-shadow-2: 0 2px 4px 0 var(--salt-shadow-2-color);--salt-shadow-3: 0 4px 8px 0 var(--salt-shadow-3-color);--salt-shadow-4: 0 6px 10px 0 var(--salt-shadow-4-color);--salt-shadow-5: 0 12px 40px 0 var(--salt-shadow-5-color)}.vuu-density-touch,.vuu-density-low,.vuu-density-medium,.vuu-density-high{--salt-size-basis-unit: 4px;--salt-size-adornmentGap: calc(.75 * var(--salt-size-unit));--salt-size-container-spacing: calc(3 * var(--salt-size-unit));--salt-size-separator-strokeWidth: 1px;--salt-size-selectable: calc(var(--salt-size-base) - (1.5 * var(--salt-size-unit)) - (.5 * var(--salt-size-basis-unit)));--salt-size-separator-height: calc(var(--salt-size-compact) + 1.5 * var(--salt-size-basis-unit));--salt-size-sharktooth-height: 5px;--salt-size-sharktooth-width: 10px;--salt-size-stackable: calc(var(--salt-size-base) + var(--salt-size-unit))}.vuu-density-high{--salt-size-unit: calc(var(--salt-size-basis-unit) * 1);--salt-size-compact: calc(var(--salt-size-basis-unit) * 1.5);--salt-size-accent: calc(var(--salt-size-basis-unit) * .5);--salt-size-adornment: 6px;--salt-size-bar: 2px;--salt-size-base: 20px;--salt-size-border: 1px;--salt-size-selectable: 12px;--salt-size-icon: 12px}.vuu-density-medium{--salt-size-unit: calc(var(--salt-size-basis-unit) * 2);--salt-size-compact: calc(var(--salt-size-basis-unit) * 2);--salt-size-accent: calc(var(--salt-size-basis-unit) * 1);--salt-size-adornment: 8px;--salt-size-bar: 4px;--salt-size-base: 28px;--salt-size-border: 1px;--salt-size-selectable: 14px;--salt-size-icon: 12px}.vuu-density-low{--salt-size-unit: calc(var(--salt-size-basis-unit) * 3);--salt-size-compact: calc(var(--salt-size-basis-unit) * 2.5);--salt-size-accent: calc(var(--salt-size-basis-unit) * 1.5);--salt-size-adornment: 10px;--salt-size-bar: 6px;--salt-size-base: 36px;--salt-size-border: 1px;--salt-size-selectable: 16px;--salt-size-icon: 14px}.vuu-density-touch{--salt-size-unit: calc(var(--salt-size-basis-unit) * 4);--salt-size-compact: calc(var(--salt-size-basis-unit) * 3);--salt-size-accent: calc(var(--salt-size-basis-unit) * 2);--salt-size-adornment: 12px;--salt-size-bar: 8px;--salt-size-base: 44px;--salt-size-border: 1px;--salt-size-selectable: 18px;--salt-size-icon: 16px}.vuu-density-touch{--salt-spacing-100: 16px}.vuu-density-low{--salt-spacing-100: 12px}.vuu-density-medium{--salt-spacing-100: 8px}.vuu-density-high{--salt-spacing-100: 4px}.vuu-density-touch,.vuu-density-low,.vuu-density-medium,.vuu-density-high{--salt-spacing-25: calc(.25 * var(--salt-spacing-100));--salt-spacing-50: calc(.5 * var(--salt-spacing-100));--salt-spacing-75: calc(.75 * var(--salt-spacing-100));--salt-spacing-150: calc(1.5 * var(--salt-spacing-100));--salt-spacing-200: calc(2 * var(--salt-spacing-100));--salt-spacing-250: calc(2.5 * var(--salt-spacing-100));--salt-spacing-300: calc(3 * var(--salt-spacing-100));--salt-spacing-350: calc(3.5 * var(--salt-spacing-100));--salt-spacing-400: calc(4 * var(--salt-spacing-100))}.vuu-theme{--salt-typography-fontFamily: "Nunito Sans";--salt-typography-fontFamily-code: "PT Mono";--salt-typography-fontWeight-light: 300;--salt-typography-fontWeight-regular: 400;--salt-typography-fontWeight-medium: 500;--salt-typography-fontWeight-semiBold: 600;--salt-typography-fontWeight-bold: 700;--salt-typography-fontWeight-extraBold: 800}.vuu-density-touch,.vuu-density-low,.vuu-density-medium,.vuu-density-high{--salt-zIndex-default: 1;--salt-zIndex-popout: 1000;--salt-zIndex-docked: 1050;--salt-zIndex-appHeader: 1100;--salt-zIndex-drawer: 1200;--salt-zIndex-modal: 1300;--salt-zIndex-notification: 1400;--salt-zIndex-dragObject: 1420;--salt-zIndex-contextMenu: 1450;--salt-zIndex-flyover: 1500}.vuu-theme[data-mode=light],.vuu-theme[data-mode=dark]{--salt-palette-accent-background: var(--salt-color-blue-500);--salt-palette-accent-background-disabled: var(--salt-color-blue-500-fade-background);--salt-palette-accent-border: var(--salt-color-blue-500);--salt-palette-accent-border-disabled: var(--salt-color-blue-500-fade-border);--salt-palette-accent-foreground: var(--salt-color-white);--salt-palette-accent-foreground-disabled: var(--salt-color-white-fade-foreground)}.vuu-theme[data-mode=light]{--salt-palette-error-background: var(--salt-color-red-10);--salt-palette-error-background-selected: var(--salt-color-red-20);--salt-palette-error-border: var(--salt-color-red-500);--salt-palette-error-foreground: var(--salt-color-red-500)}.vuu-theme[data-mode=dark]{--salt-palette-error-background: var(--salt-color-red-900);--salt-palette-error-background-selected: var(--salt-color-red-900);--salt-palette-error-border: var(--salt-color-red-500);--salt-palette-error-foreground: var(--salt-color-red-500)}.vuu-theme[data-mode=light]{--salt-palette-info-background: var(--salt-color-blue-10);--salt-palette-info-border: var(--salt-color-blue-500);--salt-palette-info-foreground: var(--salt-color-blue-500)}.vuu-theme[data-mode=dark]{--salt-palette-info-background: var(--salt-color-blue-900);--salt-palette-info-border: var(--salt-color-blue-500);--salt-palette-info-foreground: var(--salt-color-blue-500)}.vuu-theme[data-mode=light]{--salt-palette-interact-background: transparent;--salt-palette-interact-background-blurSelected: var(--salt-color-gray-30);--salt-palette-interact-background-hover: var(--vuu-color-gray-10);--salt-palette-interact-background-active: var(--vuu-color-blue-40);--salt-palette-interact-background-disabled: var(--vuu-color-gray-35);--salt-palette-interact-background-activeDisabled: var(--salt-color-blue-30-fade-background);--salt-palette-interact-border: var(--vuu-color-gray-45);--salt-palette-interact-border-active: var(--vuu-color-purple-10);--salt-palette-interact-border-activeDisabled: var(--salt-color-blue-600-fade-fill);--salt-palette-interact-border-disabled: var(--salt-color-gray-200-fade-border);--salt-palette-interact-border-hover: var(--vuu-color-pink-10);--salt-palette-interact-border-readonly: var(--salt-color-gray-200-fade-border-readonly);--salt-palette-interact-foreground: var(--salt-color-gray-200);--salt-palette-interact-foreground-active: var(--vuu-color-purple-10);--salt-palette-interact-foreground-activeDisabled: var(--salt-color-blue-600-fade-foreground);--salt-palette-interact-foreground-disabled: var(--salt-color-gray-200-fade-foreground);--salt-palette-interact-foreground-hover: var(--salt-color-blue-500);--salt-palette-interact-outline: var(--salt-color-blue-600);--salt-palette-interact-cta-background: var(--vuu-color-purple-10);--salt-palette-interact-cta-background-active: var(--vuu-color-purple-10);--salt-palette-interact-cta-background-activeDisabled: var(--salt-color-blue-700-fade-background);--salt-palette-interact-cta-background-disabled: var(--salt-color-blue-600-fade-background);--salt-palette-interact-cta-background-hover: var(--vuu-color-pink-10);--salt-palette-interact-cta-foreground: var(--salt-color-white);--salt-palette-interact-cta-foreground-active: var(--salt-color-white);--salt-palette-interact-cta-foreground-activeDisabled: var(--salt-color-white-fade-foreground);--salt-palette-interact-cta-foreground-disabled: var(--salt-color-white-fade-foreground);--salt-palette-interact-cta-foreground-hover: var(--vuu-color-gray-80);--salt-palette-interact-primary-background: var(--vuu-color-white);--salt-palette-interact-primary-background-active: var(--vuu-color-gray-50);--salt-palette-interact-primary-background-activeDisabled: var(--salt-color-gray-200-fade-background);--salt-palette-interact-primary-background-disabled: var(--salt-color-gray-60-fade-background);--salt-palette-interact-primary-background-hover: var(--vuu-color-pink-10);--salt-palette-interact-primary-foreground: var(--vuu-color-gray-50);--salt-palette-interact-primary-foreground-active: var(--salt-color-white);--salt-palette-interact-primary-foreground-activeDisabled: var(--salt-color-white-fade-foreground);--salt-palette-interact-primary-foreground-disabled: var(--salt-color-gray-900-fade-foreground);--salt-palette-interact-primary-foreground-hover: var(--vuu-color-gray-80);--salt-palette-interact-secondary-background: transparent;--salt-palette-interact-secondary-background-active: var(--vuu-color-purple-10);--salt-palette-interact-secondary-background-activeDisabled: var(--salt-color-gray-200-fade-background);--salt-palette-interact-secondary-background-disabled: transparent;--salt-palette-interact-secondary-background-hover: var(--salt-color-gray-40);--salt-palette-interact-secondary-foreground: var(--salt-color-gray-900);--salt-palette-interact-secondary-foreground-active: var(--salt-color-white);--salt-palette-interact-secondary-foreground-activeDisabled: var(--salt-color-white-fade-foreground);--salt-palette-interact-secondary-foreground-disabled: var(--salt-color-gray-900-fade-foreground);--salt-palette-interact-secondary-foreground-hover: var(--salt-color-gray-900)}.vuu-theme[data-mode=dark]{--salt-palette-interact-background: transparent;--salt-palette-interact-background-active: var(--salt-color-blue-700);--salt-palette-interact-background-blurSelected: var(--salt-color-gray-600);--salt-palette-interact-background-hover: var(--salt-color-blue-800);--salt-palette-interact-background-disabled: transparent;--salt-palette-interact-background-activeDisabled: var(--salt-color-blue-700-fade-background);--salt-palette-interact-border: var(--salt-color-gray-90);--salt-palette-interact-border-active: var(--salt-color-blue-100);--salt-palette-interact-border-activeDisabled: var(--salt-color-blue-100-fade-fill);--salt-palette-interact-border-disabled: var(--salt-color-gray-90-fade-border);--salt-palette-interact-border-hover: var(--salt-color-blue-500);--salt-palette-interact-border-readonly: var(--salt-color-gray-90-fade-border-readonly);--salt-palette-interact-foreground: var(--salt-color-gray-90);--salt-palette-interact-foreground-active: var(--salt-color-blue-100);--salt-palette-interact-foreground-activeDisabled: var(--salt-color-blue-100-fade-foreground);--salt-palette-interact-foreground-disabled: var(--salt-color-gray-90-fade-foreground);--salt-palette-interact-foreground-hover: var(--salt-color-blue-500);--salt-palette-interact-outline: var(--vuu-color-pink-10);--salt-palette-interact-cta-background: var(--salt-color-blue-600);--salt-palette-interact-cta-background-active: var(--salt-color-blue-700);--salt-palette-interact-cta-background-activeDisabled: var(--salt-color-blue-700-fade-background);--salt-palette-interact-cta-background-disabled: var(--salt-color-blue-600-fade-background);--salt-palette-interact-cta-background-hover: var(--salt-color-blue-500);--salt-palette-interact-cta-foreground: var(--salt-color-white);--salt-palette-interact-cta-foreground-active: var(--salt-color-white);--salt-palette-interact-cta-foreground-activeDisabled: var(--salt-color-white-fade-foreground);--salt-palette-interact-cta-foreground-disabled: var(--salt-color-white-fade-foreground);--salt-palette-interact-cta-foreground-hover: var(--salt-color-white);--salt-palette-interact-primary-background: var(--salt-color-gray-300);--salt-palette-interact-primary-background-active: var(--salt-color-gray-70);--salt-palette-interact-primary-background-activeDisabled: var(--salt-color-gray-70-fade-background);--salt-palette-interact-primary-background-disabled: var(--salt-color-gray-300-fade-background);--salt-palette-interact-primary-background-hover: var(--salt-color-gray-200);--salt-palette-interact-primary-foreground: var(--salt-color-white);--salt-palette-interact-primary-foreground-active: var(--salt-color-gray-900);--salt-palette-interact-primary-foreground-activeDisabled: var(--salt-color-gray-900-fade-foreground);--salt-palette-interact-primary-foreground-disabled: var(--salt-color-white-fade-foreground);--salt-palette-interact-primary-foreground-hover: var(--salt-color-white);--salt-palette-interact-secondary-background: transparent;--salt-palette-interact-secondary-background-active: var(--salt-color-gray-70);--salt-palette-interact-secondary-background-activeDisabled: var(--salt-color-gray-70-fade-background);--salt-palette-interact-secondary-background-disabled: transparent;--salt-palette-interact-secondary-background-hover: var(--salt-color-gray-200);--salt-palette-interact-secondary-foreground: var(--salt-color-white);--salt-palette-interact-secondary-foreground-active: var(--salt-color-gray-900);--salt-palette-interact-secondary-foreground-activeDisabled: var(--salt-color-gray-900-fade-foreground);--salt-palette-interact-secondary-foreground-disabled: var(--salt-color-white-fade-foreground);--salt-palette-interact-secondary-foreground-hover: var(--salt-color-white)}.vuu-theme[data-mode=light]{--salt-palette-navigate-primary-background: transparent;--salt-palette-navigate-primary-background-active: transparent;--salt-palette-navigate-primary-background-hover: var(--salt-color-gray-20);--salt-palette-navigate-secondary-background: transparent;--salt-palette-navigate-secondary-background-active: transparent;--salt-palette-navigate-secondary-background-hover: var(--salt-color-gray-30);--salt-palette-navigate-tertiary-background: transparent;--salt-palette-navigate-tertiary-background-active: transparent;--salt-palette-navigate-tertiary-background-hover: var(--salt-color-gray-20);--salt-palette-navigate-foreground-hover: var(--salt-color-blue-600);--salt-palette-navigate-foreground-active: var(--salt-color-blue-700);--salt-palette-navigate-foreground-visited: var(--salt-color-purple-800);--salt-palette-navigate-indicator-hover: var(--salt-color-gray-90);--salt-palette-navigate-indicator-active: var(--vuu-color-purple-10);--salt-palette-navigate-indicator-activeDisabled: var(--salt-color-orange-600-fade-border)}.vuu-theme[data-mode=dark]{--salt-palette-navigate-primary-background: transparent;--salt-palette-navigate-primary-background-active: transparent;--salt-palette-navigate-primary-background-hover: var(--salt-color-gray-700);--salt-palette-navigate-secondary-background: transparent;--salt-palette-navigate-secondary-background-active: transparent;--salt-palette-navigate-secondary-background-hover: var(--salt-color-gray-600);--salt-palette-navigate-tertiary-background: transparent;--salt-palette-navigate-tertiary-background-active: transparent;--salt-palette-navigate-tertiary-background-hover: var(--salt-color-gray-700);--salt-palette-navigate-foreground-hover: var(--salt-color-blue-200);--salt-palette-navigate-foreground-active: var(--salt-color-blue-300);--salt-palette-navigate-foreground-visited: var(--salt-color-purple-100);--salt-palette-navigate-indicator-hover: var(--salt-color-gray-90);--salt-palette-navigate-indicator-active: var(--vuu-color-pink-10);--salt-palette-navigate-indicator-activeDisabled: var(--salt-color-orange-400-fade-border)}.vuu-theme[data-mode=light]{--salt-palette-negative-foreground: var(--salt-color-red-700)}.vuu-theme[data-mode=dark]{--salt-palette-negative-foreground: var(--salt-color-red-300)}.vuu-theme[data-mode=light]{--salt-palette-neutral-primary-background: var(--salt-color-white);--salt-palette-neutral-primary-background-disabled: var(--salt-color-white-fade-background);--salt-palette-neutral-primary-background-readonly: var(--salt-color-white-fade-background-readonly);--salt-palette-neutral-primary-foreground: var(--vuu-color-gray-80);--salt-palette-neutral-primary-foreground-disabled: var(--salt-color-gray-900-fade-foreground);--salt-palette-neutral-primary-separator: var(--salt-color-black-fade-separatorOpacity-primary);--salt-palette-neutral-primary-border: var(--vuu-color-purple-10);--salt-palette-neutral-primary-border-disabled: var(--salt-color-gray-60-fade-border);--salt-palette-neutral-secondary-background: var(--vuu-color-gray-20);--salt-palette-neutral-secondary-background-disabled: var(--salt-color-gray-20-fade-background);--salt-palette-neutral-secondary-background-readonly: var(--salt-color-gray-20-fade-background-readonly);--salt-palette-neutral-secondary-border: var(--salt-color-gray-90);--salt-palette-neutral-secondary-border-disabled: var(--salt-color-gray-90-fade-border);--salt-palette-neutral-secondary-foreground: var(--salt-color-gray-200);--salt-palette-neutral-secondary-foreground-disabled: var(--salt-color-gray-200-fade-foreground);--salt-palette-neutral-backdrop: var(--salt-color-black-fade-backdrop);--salt-palette-neutral-secondary-separator: var(--salt-color-black-fade-separatorOpacity-secondary);--salt-palette-neutral-tertiary-background: transparent;--salt-palette-neutral-tertiary-background-disabled: transparent;--salt-palette-neutral-tertiary-border: transparent;--salt-palette-neutral-tertiary-border-disabled: transparent;--salt-palette-neutral-tertiary-separator: var(--vuu-color-gray-05)}.vuu-theme[data-mode=dark]{--salt-palette-neutral-primary-background: var(--salt-color-gray-800);--salt-palette-neutral-primary-background-disabled: var(--salt-color-gray-800-fade-background);--salt-palette-neutral-primary-background-readonly: var(--salt-color-gray-800-fade-background-readonly);--salt-palette-neutral-primary-border: var(--salt-color-gray-300);--salt-palette-neutral-primary-border-disabled: var(--salt-color-gray-300-fade-border);--salt-palette-neutral-primary-foreground: var(--salt-color-white);--salt-palette-neutral-primary-foreground-disabled: var(--salt-color-white-fade-foreground);--salt-palette-neutral-primary-separator: var(--salt-color-white-fade-separatorOpacity-primary);--salt-palette-neutral-secondary-background: var(--salt-color-gray-600);--salt-palette-neutral-secondary-background-disabled: var(--salt-color-gray-600-fade-background);--salt-palette-neutral-secondary-background-readonly: var(--salt-color-gray-600-fade-background-readonly);--salt-palette-neutral-secondary-border: var(--salt-color-gray-90);--salt-palette-neutral-secondary-border-disabled: var(--salt-color-gray-90-fade-border);--salt-palette-neutral-secondary-foreground: var(--salt-color-gray-70);--salt-palette-neutral-secondary-foreground-disabled: var(--salt-color-gray-70-fade-foreground);--salt-palette-neutral-backdrop: var(--salt-color-black-fade-backdrop);--salt-palette-neutral-secondary-separator: var(--salt-color-white-fade-separatorOpacity-secondary);--salt-palette-neutral-tertiary-background: transparent;--salt-palette-neutral-tertiary-background-disabled: transparent;--salt-palette-neutral-tertiary-border: transparent;--salt-palette-neutral-tertiary-border-disabled: transparent;--salt-palette-neutral-tertiary-separator: var(--salt-color-white-fade-separatorOpacity-tertiary)}.vuu-theme{--salt-palette-opacity-backdrop: var(--salt-opacity-70);--salt-palette-opacity-disabled: var(--salt-opacity-40);--salt-palette-opacity-background-readonly: var(--salt-opacity-0);--salt-palette-opacity-border-readonly: var(--salt-opacity-15);--salt-palette-opacity-primary-border: var(--salt-opacity-40);--salt-palette-opacity-secondary-border: var(--salt-opacity-25);--salt-palette-opacity-tertiary-border: var(--salt-opacity-15)}.vuu-theme[data-mode=light]{--salt-palette-positive-foreground: var(--salt-color-green-700)}.vuu-theme[data-mode=dark]{--salt-palette-positive-foreground: var(--salt-color-green-300)}.vuu-theme[data-mode=light]{--salt-palette-success-background: var(--salt-color-green-10);--salt-palette-success-background-selected: var(--salt-color-green-20);--salt-palette-success-border: var(--salt-color-green-500);--salt-palette-success-foreground: var(--salt-color-green-500)}.vuu-theme[data-mode=dark]{--salt-palette-success-background: var(--salt-color-green-900);--salt-palette-success-background-selected: var(--salt-color-green-900);--salt-palette-success-border: var(--salt-color-green-400);--salt-palette-success-foreground: var(--salt-color-green-400)}.vuu-theme[data-mode=light]{--salt-palette-track-background: var(--salt-color-gray-60);--salt-palette-track-background-disabled: var(--salt-color-gray-60-fade-background);--salt-palette-track-border: var(--salt-color-gray-90);--salt-palette-track-border-disabled: var(--salt-color-gray-90-fade-border)}.vuu-theme[data-mode=dark]{--salt-palette-track-background: var(--salt-color-gray-300);--salt-palette-track-background-disabled: var(--salt-color-gray-300-fade-background);--salt-palette-track-border: var(--salt-color-gray-90);--salt-palette-track-border-disabled: var(--salt-color-gray-90-fade-border)}.vuu-theme[data-mode=light]{--salt-palette-warning-background: var(--salt-color-orange-10);--salt-palette-warning-background-selected: var(--salt-color-orange-20);--salt-palette-warning-border: var(--salt-color-orange-700);--salt-palette-warning-foreground: var(--salt-color-orange-700)}.vuu-theme[data-mode=dark]{--salt-palette-warning-background: var(--salt-color-orange-900);--salt-palette-warning-background-selected: var(--salt-color-orange-900);--salt-palette-warning-border: var(--salt-color-orange-500);--salt-palette-warning-foreground: var(--salt-color-orange-500)}.vuu-density-high{--salt-accent-fontSize: 8px;--salt-accent-lineHeight: 11px}.vuu-density-medium{--salt-accent-fontSize: 10px;--salt-accent-lineHeight: 13px}.vuu-density-low{--salt-accent-fontSize: 12px;--salt-accent-lineHeight: 16px}.vuu-density-touch{--salt-accent-fontSize: 14px;--salt-accent-lineHeight: 18px}.vuu-theme{--salt-accent-background: var(--salt-palette-accent-background);--salt-accent-background-disabled: var(--salt-palette-accent-background-disabled);--salt-accent-borderColor: var(--salt-palette-accent-border);--salt-accent-borderColor-disabled: var(--salt-palette-accent-border-disabled);--salt-accent-foreground: var(--salt-palette-accent-foreground);--salt-accent-foreground-disabled: var(--salt-palette-accent-foreground-disabled);--salt-accent-fontWeight: var(--salt-typography-fontWeight-semiBold)}.vuu-theme{--salt-actionable-cursor-hover: pointer;--salt-actionable-cursor-active: pointer;--salt-actionable-cursor-disabled: not-allowed;--salt-actionable-letterSpacing: .6px;--salt-actionable-textAlign: center;--salt-actionable-textTransform: uppercase;--salt-actionable-primary-foreground: var(--salt-palette-interact-primary-foreground);--salt-actionable-primary-foreground-hover: var(--salt-palette-interact-primary-foreground-hover);--salt-actionable-primary-foreground-active: var(--salt-palette-interact-primary-foreground-active);--salt-actionable-primary-foreground-disabled: var(--salt-palette-interact-primary-foreground-disabled);--salt-actionable-primary-background: var(--salt-palette-interact-primary-background);--salt-actionable-primary-background-hover: var(--salt-palette-interact-primary-background-hover);--salt-actionable-primary-background-active: var(--salt-palette-interact-primary-background-active);--salt-actionable-primary-background-disabled: var(--salt-palette-interact-primary-background-disabled);--salt-actionable-primary-fontWeight: var(--salt-typography-fontWeight-bold);--salt-actionable-cta-foreground: var(--salt-palette-interact-cta-foreground);--salt-actionable-cta-foreground-hover: var(--salt-palette-interact-cta-foreground-hover);--salt-actionable-cta-foreground-active: var(--salt-palette-interact-cta-foreground-active);--salt-actionable-cta-foreground-disabled: var(--salt-palette-interact-cta-foreground-disabled);--salt-actionable-cta-background: var(--salt-palette-interact-cta-background);--salt-actionable-cta-background-hover: var(--salt-palette-interact-cta-background-hover);--salt-actionable-cta-background-active: var(--salt-palette-interact-cta-background-active);--salt-actionable-cta-background-disabled: var(--salt-palette-interact-cta-background-disabled);--salt-actionable-cta-fontWeight: var(--salt-typography-fontWeight-bold);--salt-actionable-secondary-foreground: var(--salt-palette-interact-secondary-foreground);--salt-actionable-secondary-foreground-hover: var(--salt-palette-interact-secondary-foreground-hover);--salt-actionable-secondary-foreground-active: var(--salt-palette-interact-secondary-foreground-active);--salt-actionable-secondary-foreground-disabled: var(--salt-palette-interact-secondary-foreground-disabled);--salt-actionable-secondary-background: var(--salt-palette-interact-secondary-background);--salt-actionable-secondary-background-hover: var(--salt-palette-interact-secondary-background-hover);--salt-actionable-secondary-background-active: var(--salt-palette-interact-secondary-background-active);--salt-actionable-secondary-background-disabled: var(--salt-palette-interact-secondary-background-disabled);--salt-actionable-secondary-fontWeight: var(--salt-typography-fontWeight-semiBold)}.vuu-theme{--salt-container-borderStyle: solid;--salt-container-primary-background: var(--salt-palette-neutral-primary-background);--salt-container-primary-background-disabled: var(--salt-palette-neutral-primary-background-disabled);--salt-container-primary-borderColor: var(--salt-palette-neutral-primary-border);--salt-container-primary-borderColor-disabled: var(--salt-palette-neutral-primary-border-disabled);--salt-container-secondary-background: var(--salt-palette-neutral-secondary-background);--salt-container-secondary-background-disabled: var(--salt-palette-neutral-secondary-background-disabled);--salt-container-secondary-borderColor: var(--salt-palette-neutral-secondary-border);--salt-container-secondary-borderColor-disabled: var(--salt-palette-neutral-secondary-border-disabled);--salt-container-tertiary-background: var(--salt-palette-neutral-tertiary-background);--salt-container-tertiary-background-disabled: var(--salt-palette-neutral-tertiary-background-disabled);--salt-container-tertiary-borderColor: var(--salt-palette-neutral-tertiary-border);--salt-container-tertiary-borderColor-disabled: var(--salt-palette-neutral-tertiary-border-disabled)}.vuu-theme{--salt-draggable-horizontal-cursor-hover: row-resize;--salt-draggable-horizontal-cursor-active: row-resize;--salt-draggable-vertical-cursor-hover: col-resize;--salt-draggable-vertical-cursor-active: col-resize;--salt-draggable-grab-cursor-hover: grab;--salt-draggable-grab-cursor-active: grabbing}.vuu-theme{--salt-target-background-hover: var(--salt-palette-interact-background-hover);--salt-target-borderColor-hover: var(--salt-palette-interact-border-hover);--salt-target-borderStyle: dashed;--salt-target-borderStyle-hover: solid;--salt-target-borderStyle-disabled: dashed;--salt-target-cursor-disabled: not-allowed}.vuu-theme{--salt-editable-cursor-hover: text;--salt-editable-cursor-active: text;--salt-editable-cursor-disabled: not-allowed;--salt-editable-cursor-readonly: text;--salt-editable-borderStyle: solid;--salt-editable-borderStyle-hover: solid;--salt-editable-borderStyle-active: solid;--salt-editable-borderStyle-disabled: solid;--salt-editable-borderStyle-readonly: solid;--salt-editable-borderWidth-active: 2px;--salt-editable-borderColor: var(--salt-palette-interact-border);--salt-editable-borderColor-active: var(--salt-palette-interact-border-active);--salt-editable-borderColor-disabled: var(--salt-palette-interact-border-disabled);--salt-editable-borderColor-hover: var(--salt-palette-interact-border-hover);--salt-editable-borderColor-readonly: var(--salt-palette-interact-border-readonly);--salt-editable-primary-background: var(--salt-palette-neutral-primary-background);--salt-editable-primary-background-active: var(--salt-palette-neutral-primary-background);--salt-editable-primary-background-disabled: var(--salt-palette-neutral-primary-background-disabled);--salt-editable-primary-background-hover: var(--salt-palette-neutral-primary-background);--salt-editable-primary-background-readonly: var(--salt-palette-neutral-primary-background-readonly);--salt-editable-secondary-background: var(--salt-palette-neutral-secondary-background);--salt-editable-secondary-background-active: var(--salt-palette-neutral-secondary-background);--salt-editable-secondary-background-disabled: var(--salt-palette-neutral-secondary-background-disabled);--salt-editable-secondary-background-hover: var(--salt-palette-neutral-secondary-background);--salt-editable-secondary-background-readonly: var(--salt-palette-neutral-secondary-background-readonly);--salt-editable-help-fontStyle: italic}.vuu-theme{--vuu-editable-borderColor-active: var(--editable-border-active, #6D18BD)}.saltInput-focused{border-color:var(--vuu-editable-borderColor-active)!important}.vuu-theme{--salt-navigable-cursor-active: pointer;--salt-navigable-cursor-hover: pointer;--salt-navigable-cursor-disabled: not-allowed;--salt-navigable-cursor-edit: text;--salt-navigable-fontWeight: var(--salt-typography-fontWeight-regular);--salt-navigable-fontWeight-hover: var(--salt-typography-fontWeight-regular);--salt-navigable-fontWeight-active: var(--salt-typography-fontWeight-semiBold);--salt-navigable-fontWeight-edit: var(--salt-typography-fontWeight-regular);--salt-navigable-indicator-hover: var(--salt-palette-navigate-indicator-hover);--salt-navigable-indicator-active: var(--salt-palette-navigate-indicator-active);--salt-navigable-indicator-activeDisabled: var(--salt-palette-navigate-indicator-activeDisabled);--salt-navigable-primary-background: var(--salt-palette-navigate-primary-background);--salt-navigable-primary-background-hover: var(--salt-palette-navigate-primary-background-hover);--salt-navigable-primary-background-active: var(--salt-palette-navigate-primary-background-active);--salt-navigable-secondary-background: var(--salt-palette-navigate-secondary-background);--salt-navigable-secondary-background-hover: var(--salt-palette-navigate-secondary-background-hover);--salt-navigable-secondary-background-active: var(--salt-palette-navigate-secondary-background-active);--salt-navigable-tertiary-background: var(--salt-palette-navigate-tertiary-background);--salt-navigable-tertiary-background-hover: var(--salt-palette-navigate-tertiary-background-hover);--salt-navigable-tertiary-background-active: var(--salt-palette-navigate-tertiary-background-active)}.vuu-theme{--salt-overlayable-shadow-scroll: var(--salt-shadow-1);--salt-overlayable-shadow-borderRegion: var(--salt-shadow-2);--salt-overlayable-shadow: var(--salt-shadow-2);--salt-overlayable-shadow-hover: var(--salt-shadow-3);--salt-overlayable-shadow-popout: var(--salt-shadow-4);--salt-overlayable-shadow-drag: var(--salt-shadow-4);--salt-overlayable-shadow-modal: var(--salt-shadow-5);--salt-overlayable-background: var(--salt-palette-neutral-backdrop)}.vuu-theme{--salt-selectable-cursor-hover: pointer;--salt-selectable-cursor-selected: pointer;--salt-selectable-cursor-blurSelected: pointer;--salt-selectable-cursor-disabled: not-allowed;--salt-selectable-cursor-readonly: not-allowed;--salt-selectable-borderStyle: solid;--salt-selectable-borderStyle-hover: solid;--salt-selectable-borderStyle-selected: solid;--salt-selectable-borderStyle-blurSelected: solid;--salt-selectable-borderColor: var(--salt-palette-interact-border);--salt-selectable-borderColor-hover: var(--salt-palette-interact-border-hover);--salt-selectable-borderColor-selected: var(--salt-palette-interact-border-active);--salt-selectable-borderColor-selectedDisabled: var(--salt-palette-interact-border-activeDisabled);--salt-selectable-borderColor-disabled: var(--salt-palette-interact-border-disabled);--salt-selectable-borderColor-readonly: var(--salt-palette-interact-border-readonly);--salt-selectable-foreground: var(--salt-palette-interact-foreground);--salt-selectable-foreground-disabled: var(--salt-palette-interact-foreground-disabled);--salt-selectable-foreground-hover: var(--salt-palette-interact-foreground-hover);--salt-selectable-foreground-selected: var(--salt-palette-interact-foreground-active);--salt-selectable-foreground-selectedDisabled: var(--salt-palette-interact-foreground-activeDisabled);--salt-selectable-background: var(--salt-palette-interact-background);--salt-selectable-background-hover: var(--salt-palette-interact-background-hover);--salt-selectable-background-selected: var(--salt-palette-interact-background-active);--salt-selectable-background-blurSelected: var(--salt-palette-interact-background-blurSelected);--salt-selectable-background-disabled: var(--salt-palette-interact-background-disabled);--salt-selectable-background-selectedDisabled: var(--salt-palette-interact-background-activeDisabled);--salt-selectable-cta-foreground-hover: var(--salt-palette-interact-cta-foreground-hover);--salt-selectable-cta-foreground-selected: var(--salt-palette-interact-cta-foreground-active);--salt-selectable-cta-foreground-selectedDisabled: var(--salt-palette-interact-cta-foreground-activeDisabled);--salt-selectable-cta-background: var(--salt-palette-interact-background);--salt-selectable-cta-background-disabled: var(--salt-palette-interact-background-disabled);--salt-selectable-cta-background-hover: var(--salt-palette-interact-cta-background-hover);--salt-selectable-cta-background-selected: var(--salt-palette-interact-cta-background-active);--salt-selectable-cta-background-selectedDisabled: var(--salt-palette-interact-cta-background-activeDisabled);--salt-selectable-primary-foreground-hover: var(--salt-palette-interact-primary-foreground-hover);--salt-selectable-primary-foreground-selected: var(--salt-palette-interact-primary-foreground-active);--salt-selectable-primary-foreground-selectedDisabled: var(--salt-palette-interact-primary-foreground-activeDisabled);--salt-selectable-primary-background: var(--salt-palette-interact-background);--salt-selectable-primary-background-disabled: var(--salt-palette-interact-background-disabled);--salt-selectable-primary-background-hover: var(--salt-palette-interact-primary-background-hover);--salt-selectable-primary-background-selected: var(--salt-palette-interact-primary-background-active);--salt-selectable-primary-background-selectedDisabled: var(--salt-palette-interact-primary-background-activeDisabled);--salt-selectable-secondary-foreground-hover: var(--salt-palette-interact-secondary-foreground-hover);--salt-selectable-secondary-foreground-selected: var(--salt-palette-interact-secondary-foreground-active);--salt-selectable-secondary-foreground-selectedDisabled: var(--salt-palette-interact-secondary-foreground-activeDisabled);--salt-selectable-secondary-background: var(--salt-palette-interact-background);--salt-selectable-secondary-background-disabled: var(--salt-palette-interact-background-disabled);--salt-selectable-secondary-background-hover: var(--salt-palette-interact-secondary-background-hover);--salt-selectable-secondary-background-selected: var(--salt-palette-interact-secondary-background-active);--salt-selectable-secondary-background-selectedDisabled: var(--salt-palette-interact-secondary-background-activeDisabled)}.vuu-theme{--salt-separable-borderStyle: solid;--salt-separable-primary-borderColor: var(--salt-palette-neutral-primary-separator);--salt-separable-secondary-borderColor: var(--salt-palette-neutral-secondary-separator);--salt-separable-tertiary-borderColor: var(--salt-palette-neutral-tertiary-separator)}.vuu-theme{--salt-status-info-foreground: var(--salt-palette-info-foreground);--salt-status-success-foreground: var(--salt-palette-success-foreground);--salt-status-warning-foreground: var(--salt-palette-warning-foreground);--salt-status-error-foreground: var(--salt-palette-error-foreground);--salt-status-static-foreground: var(--salt-palette-neutral-secondary-foreground);--salt-status-negative-foreground: var(--salt-palette-negative-foreground);--salt-status-positive-foreground: var(--salt-palette-positive-foreground);--salt-status-info-borderColor: var(--salt-palette-info-border);--salt-status-success-borderColor: var(--salt-palette-success-border);--salt-status-warning-borderColor: var(--salt-palette-warning-border);--salt-status-error-borderColor: var(--salt-palette-error-border);--salt-status-info-background: var(--salt-palette-info-background);--salt-status-success-background: var(--salt-palette-success-background);--salt-status-warning-background: var(--salt-palette-warning-background);--salt-status-error-background: var(--salt-palette-error-background);--salt-status-success-background-selected: var(--salt-palette-success-background-selected);--salt-status-warning-background-selected: var(--salt-palette-warning-background-selected);--salt-status-error-background-selected: var(--salt-palette-error-background-selected)}.vuu-theme{--salt-taggable-cursor-hover: pointer;--salt-taggable-cursor-active: pointer;--salt-taggable-cursor-disabled: not-allowed;--salt-taggable-background: var(--salt-palette-interact-primary-background);--salt-taggable-background-hover: var(--salt-palette-interact-primary-background-hover);--salt-taggable-background-active: var(--salt-palette-interact-primary-background-active);--salt-taggable-background-disabled: var(--salt-palette-interact-primary-background-disabled);--salt-taggable-foreground: var(--salt-palette-interact-primary-foreground);--salt-taggable-foreground-hover: var(--salt-palette-interact-primary-foreground-hover);--salt-taggable-foreground-active: var(--salt-palette-interact-primary-foreground-active);--salt-taggable-foreground-disabled: var(--salt-palette-interact-primary-foreground-disabled)}.vuu-theme{--salt-text-letterSpacing: 0;--salt-text-textAlign: left;--salt-text-textAlign-embedded: center;--salt-text-textDecoration: none;--salt-text-textTransform: none;--salt-text-fontFamily: var(--salt-typography-fontFamily);--salt-text-fontWeight: var(--salt-typography-fontWeight-regular);--salt-text-fontWeight-small: var(--salt-typography-fontWeight-light);--salt-text-fontWeight-strong: var(--salt-typography-fontWeight-semiBold);--salt-text-h1-fontFamily: var(--salt-typography-fontFamily);--salt-text-h1-fontWeight: var(--salt-typography-fontWeight-bold);--salt-text-h1-fontWeight-small: var(--salt-typography-fontWeight-medium);--salt-text-h1-fontWeight-strong: var(--salt-typography-fontWeight-extraBold);--salt-text-h2-fontFamily: var(--salt-typography-fontFamily);--salt-text-h2-fontWeight: var(--salt-typography-fontWeight-semiBold);--salt-text-h2-fontWeight-small: var(--salt-typography-fontWeight-regular);--salt-text-h2-fontWeight-strong: var(--salt-typography-fontWeight-bold);--salt-text-h3-fontFamily: var(--salt-typography-fontFamily);--salt-text-h3-fontWeight: var(--salt-typography-fontWeight-semiBold);--salt-text-h3-fontWeight-small: var(--salt-typography-fontWeight-regular);--salt-text-h3-fontWeight-strong: var(--salt-typography-fontWeight-bold);--salt-text-h4-fontFamily: var(--salt-typography-fontFamily);--salt-text-h4-fontWeight: var(--salt-typography-fontWeight-semiBold);--salt-text-h4-fontWeight-small: var(--salt-typography-fontWeight-regular);--salt-text-h4-fontWeight-strong: var(--salt-typography-fontWeight-bold);--salt-text-label-fontFamily: var(--salt-typography-fontFamily);--salt-text-label-fontWeight: var(--salt-typography-fontWeight-regular);--salt-text-label-fontWeight-small: var(--salt-typography-fontWeight-light);--salt-text-label-fontWeight-strong: var(--salt-typography-fontWeight-semiBold);--salt-text-display1-fontFamily: var(--salt-typography-fontFamily);--salt-text-display1-fontWeight: var(--salt-typography-fontWeight-semiBold);--salt-text-display1-fontWeight-strong: var(--salt-typography-fontWeight-bold);--salt-text-display1-fontWeight-small: var(--salt-typography-fontWeight-regular);--salt-text-display2-fontFamily: var(--salt-typography-fontFamily);--salt-text-display2-fontWeight: var(--salt-typography-fontWeight-semiBold);--salt-text-display2-fontWeight-strong: var(--salt-typography-fontWeight-bold);--salt-text-display2-fontWeight-small: var(--salt-typography-fontWeight-regular);--salt-text-display3-fontFamily: var(--salt-typography-fontFamily);--salt-text-display3-fontWeight: var(--salt-typography-fontWeight-semiBold);--salt-text-display3-fontWeight-strong: var(--salt-typography-fontWeight-bold);--salt-text-display3-fontWeight-small: var(--salt-typography-fontWeight-regular);--salt-text-background-selected: var(--salt-palette-interact-background-active);--salt-text-primary-foreground: var(--salt-palette-neutral-primary-foreground);--salt-text-primary-foreground-disabled: var(--salt-palette-neutral-primary-foreground-disabled);--salt-text-secondary-foreground: var(--salt-palette-neutral-secondary-foreground);--salt-text-secondary-foreground-disabled: var(--salt-palette-neutral-secondary-foreground-disabled);--salt-text-link-foreground-hover: var(--salt-palette-navigate-foreground-hover);--salt-text-link-foreground-active: var(--salt-palette-navigate-foreground-active);--salt-text-link-foreground-visited: var(--salt-palette-navigate-foreground-visited);--salt-text-link-textDecoration: underline;--salt-text-link-textDecoration-hover: none;--salt-text-link-textDecoration-selected: underline;--salt-text-code-fontFamily: var(--salt-typography-fontFamily-code)}.vuu-density-touch{--salt-text-h1-fontSize: 42px;--salt-text-h1-lineHeight: 54px;--salt-text-h2-fontSize: 32px;--salt-text-h2-lineHeight: 42px;--salt-text-h3-fontSize: 24px;--salt-text-h3-lineHeight: 32px;--salt-text-h4-fontSize: 16px;--salt-text-h4-lineHeight: 20px;--salt-text-label-fontSize: 14px;--salt-text-label-lineHeight: 18px;--salt-text-fontSize: 16px;--salt-text-lineHeight: 20px;--salt-text-minHeight: 20px;--salt-text-display1-fontSize: 84px;--salt-text-display1-lineHeight: 109px;--salt-text-display2-fontSize: 58px;--salt-text-display2-lineHeight: 76px;--salt-text-display3-fontSize: 42px;--salt-text-display3-lineHeight: 54px}.vuu-density-low{--salt-text-h1-fontSize: 32px;--salt-text-h1-lineHeight: 42px;--salt-text-h2-fontSize: 24px;--salt-text-h2-lineHeight: 32px;--salt-text-h3-fontSize: 18px;--salt-text-h3-lineHeight: 24px;--salt-text-h4-fontSize: 14px;--salt-text-h4-lineHeight: 18px;--salt-text-label-fontSize: 12px;--salt-text-label-lineHeight: 16px;--salt-text-fontSize: 14px;--salt-text-lineHeight: 18px;--salt-text-minHeight: 18px;--salt-text-display1-fontSize: 68px;--salt-text-display1-lineHeight: 88px;--salt-text-display2-fontSize: 46px;--salt-text-display2-lineHeight: 60px;--salt-text-display3-fontSize: 32px;--salt-text-display3-lineHeight: 42px}.vuu-density-medium{--salt-text-h1-fontSize: 24px;--salt-text-h1-lineHeight: 32px;--salt-text-h2-fontSize: 18px;--salt-text-h2-lineHeight: 24px;--salt-text-h3-fontSize: 14px;--salt-text-h3-lineHeight: 18px;--salt-text-h4-fontSize: 12px;--salt-text-h4-lineHeight: 16px;--salt-text-label-fontSize: 11px;--salt-text-label-lineHeight: 14px;--salt-text-fontSize: 12px;--salt-text-lineHeight: 16px;--salt-text-minHeight: 16px;--salt-text-display1-fontSize: 54px;--salt-text-display1-lineHeight: 70px;--salt-text-display2-fontSize: 36px;--salt-text-display2-lineHeight: 47px;--salt-text-display3-fontSize: 24px;--salt-text-display3-lineHeight: 32px}.vuu-density-high{--salt-text-h1-fontSize: 18px;--salt-text-h1-lineHeight: 24px;--salt-text-h2-fontSize: 14px;--salt-text-h2-lineHeight: 18px;--salt-text-h3-fontSize: 12px;--salt-text-h3-lineHeight: 16px;--salt-text-h4-fontSize: 11px;--salt-text-h4-lineHeight: 14px;--salt-text-label-fontSize: 10px;--salt-text-label-lineHeight: 13px;--salt-text-fontSize: 12px;--salt-text-lineHeight: 14px;--salt-text-minHeight: 14px;--salt-text-display1-fontSize: 42px;--salt-text-display1-lineHeight: 54px;--salt-text-display2-fontSize: 28px;--salt-text-display2-lineHeight: 36px;--salt-text-display3-fontSize: 18px;--salt-text-display3-lineHeight: 24px}.vuu-theme{--salt-track-borderStyle: solid;--salt-track-borderStyle-active: solid;--salt-track-borderStyle-complete: solid;--salt-track-borderStyle-incomplete: dotted;--salt-track-borderWidth: 2px;--salt-track-borderWidth-active: 2px;--salt-track-borderWidth-complete: 2px;--salt-track-borderWidth-incomplete: 2px;--salt-track-fontWeight: var(--salt-typography-fontWeight-semiBold);--salt-track-textAlign: center;--salt-track-background: var(--salt-palette-track-background);--salt-track-background-disabled: var(--salt-palette-track-background-disabled);--salt-track-borderColor: var(--salt-palette-track-border);--salt-track-borderColor-disabled: var(--salt-palette-track-border-disabled)}.vuu-theme{--salt-differential-positive-foreground: var(--salt-palette-positive-foreground);--salt-differential-negative-foreground: var(--salt-palette-negative-foreground);--salt-editable-tertiary-background: var(--salt-palette-neutral-tertiary-background);--salt-editable-tertiary-background-active: var(--salt-palette-neutral-tertiary-background);--salt-editable-tertiary-background-disabled: var(--salt-palette-neutral-tertiary-background-disabled);--salt-editable-tertiary-background-hover: var(--salt-palette-neutral-tertiary-background);--salt-editable-tertiary-background-readonly: var(--salt-palette-neutral-tertiary-background-readonly);--salt-measured-borderStyle: solid;--salt-measured-borderStyle-active: solid;--salt-measured-borderStyle-complete: solid;--salt-measured-borderStyle-incomplete: dotted;--salt-measured-borderWidth: 2px;--salt-measured-borderWidth-active: 2px;--salt-measured-borderWidth-complete: 2px;--salt-measured-borderWidth-incomplete: 2px;--salt-measured-fontWeight: var(--salt-typography-fontWeight-semiBold);--salt-measured-textAlign: center;--salt-measured-background: var(--salt-palette-measured-background);--salt-measured-background-disabled: var(--salt-palette-measured-background-disabled);--salt-measured-borderColor: var(--salt-palette-measured-border);--salt-measured-borderColor-disabled: var(--salt-palette-measured-border-disabled);--salt-measured-fill: var(--salt-palette-measured-fill);--salt-measured-fill-disabled: var(--salt-palette-measured-fill-disabled);--salt-measured-foreground: var(--salt-palette-measured-foreground);--salt-measured-foreground-hover: var(--salt-palette-measured-foreground-active);--salt-measured-foreground-active: var(--salt-palette-measured-foreground-active);--salt-measured-foreground-undo: var(--salt-palette-measured-foreground-active);--salt-measured-foreground-activeDisabled: var(--salt-palette-measured-foreground-activeDisabled);--salt-measured-foreground-disabled: var(--salt-palette-measured-foreground-disabled);--salt-overlayable-shadow-scroll-color: var(--salt-shadow-1-color);--salt-selectable-foreground-partial: var(--salt-palette-interact-foreground-partial);--salt-selectable-foreground-partialDisabled: var(--salt-palette-interact-foreground-partialDisabled);--salt-selectable-cta-foreground: var(--salt-palette-interact-foreground);--salt-selectable-cta-foreground-disabled: var(--salt-palette-interact-foreground-disabled);--salt-selectable-primary-foreground: var(--salt-palette-interact-foreground);--salt-selectable-primary-foreground-disabled: var(--salt-palette-interact-foreground-disabled);--salt-selectable-secondary-foreground: var(--salt-palette-interact-foreground);--salt-selectable-secondary-foreground-disabled: var(--salt-palette-interact-foreground-disabled);--salt-status-info-background-emphasize: var(--salt-status-info-background);--salt-status-success-background-emphasize: var(--salt-status-success-background);--salt-status-warning-background-emphasize: var(--salt-status-warning-background);--salt-status-error-background-emphasize: var(--salt-status-error-background);--salt-status-info-foreground-disabled: var(--salt-palette-info-foreground-disabled);--salt-status-success-foreground-disabled: var(--salt-palette-success-foreground-disabled);--salt-status-warning-foreground-disabled: var(--salt-palette-warning-foreground-disabled);--salt-status-error-foreground-disabled: var(--salt-palette-error-foreground-disabled);--salt-status-static-foreground-disabled: var(--salt-palette-neutral-secondary-foreground-disabled);--salt-status-negative-foreground-disabled: var(--salt-palette-negative-foreground-disabled);--salt-status-positive-foreground-disabled: var(--salt-palette-positive-foreground-disabled);--salt-status-info-borderColor-disabled: var(--salt-palette-info-border-disabled);--salt-status-success-borderColor-disabled: var(--salt-palette-success-border-disabled);--salt-status-warning-borderColor-disabled: var(--salt-palette-warning-border-disabled);--salt-status-error-borderColor-disabled: var(--salt-palette-error-border-disabled)}.vuu-theme{--salt-color-orange-500-fade-foreground: rgba(234, 115, 25, var(--salt-palette-opacity-foreground));--salt-color-orange-700-fade-foreground: rgba(214, 85, 19, var(--salt-palette-opacity-foreground));--salt-color-orange-400-fade-background: rgba(238, 133, 43, var(--salt-palette-opacity-background));--salt-color-orange-600-fade-background: rgba(224, 101, 25, var(--salt-palette-opacity-background));--salt-color-blue-300-fade-fill: rgba(51, 141, 205, var(--salt-palette-opacity-fill));--salt-color-blue-500-fade-fill: rgba(38, 112, 169, var(--salt-palette-opacity-fill))}.vuu-theme{--salt-delay-instant: .1s;--salt-delay-perceptible: .3s;--salt-delay-notable: 1s;--salt-delay-cutoff: 10s;--salt-size-icon-base: var(--salt-icon-size-base);--salt-opacity-1: .15;--salt-opacity-2: .25;--salt-opacity-3: .4;--salt-opacity-4: .7}.vuu-density-touch,.vuu-density-low,.vuu-density-medium,.vuu-density-high{--salt-size-selection: var(--salt-size-selectable);--salt-size-brandBar: 4px;--salt-size-graphic-small: 12px;--salt-size-graphic-medium: 24px;--salt-size-graphic-large: 48px;--salt-size-divider-height: var(--salt-size-separator-height);--salt-size-divider-strokeWidth: var(--salt-size-separator-strokeWidth);--salt-size-detail: var(--salt-size-compact)}.vuu-theme{--salt-palette-error-background-emphasize: var(--salt-palette-error-background);--salt-palette-warning-background-emphasize: var(--salt-palette-warning-background);--salt-palette-success-background-emphasize: var(--salt-palette-success-background);--salt-palette-info-background-emphasize: var(--salt-palette-info-background);--salt-palette-opacity-fill: var(--salt-palette-opacity-disabled);--salt-palette-opacity-stroke: var(--salt-palette-opacity-disabled);--salt-palette-opacity-background: var(--salt-palette-opacity-disabled);--salt-palette-opacity-border: var(--salt-palette-opacity-disabled);--salt-palette-opacity-foreground: var(--salt-palette-opacity-disabled)}.vuu-theme[data-mode=light]{--salt-palette-interact-foreground-partial: var(--salt-color-blue-600);--salt-palette-interact-foreground-partialDisabled: var(--salt-color-blue-600-fade-foreground);--salt-palette-measured-fill: var(--salt-color-blue-500);--salt-palette-measured-fill-disabled: var(--salt-color-blue-500-fade-fill);--salt-palette-measured-foreground: var(--salt-color-gray-90);--salt-palette-measured-foreground-active: var(--salt-color-blue-500);--salt-palette-measured-foreground-disabled: var(--salt-color-gray-90-fade-foreground);--salt-palette-measured-foreground-activeDisabled: var(--salt-color-blue-500-fade-fill);--salt-palette-measured-background: var(--salt-color-gray-60);--salt-palette-measured-background-disabled: var(--salt-color-gray-60-fade-background);--salt-palette-measured-border: var(--salt-color-gray-90);--salt-palette-measured-border-disabled: var(--salt-color-gray-90-fade-border);--salt-palette-neutral-tertiary-background-readonly: transparent;--salt-palette-error-foreground-disabled: var(--salt-color-red-500-fade-foreground);--salt-palette-error-border-disabled: var(--salt-color-red-500-fade-border);--salt-palette-info-border-disabled: var(--salt-color-blue-500-fade-border);--salt-palette-info-foreground-disabled: var(--salt-color-blue-500-fade-foreground);--salt-palette-negative-foreground-disabled: var(--salt-color-red-700-fade-foreground);--salt-palette-positive-foreground-disabled: var(--salt-color-green-700-fade-foreground);--salt-palette-success-border-disabled: var(--salt-color-green-500-fade-border);--salt-palette-success-foreground-disabled: var(--salt-color-green-500-fade-foreground);--salt-palette-warning-foreground-disabled: var(--salt-color-orange-700-fade-foreground);--salt-palette-warning-border-disabled: var(--salt-color-orange-700-fade-border)}.vuu-theme[data-mode=dark]{--salt-palette-interact-foreground-partial: var(--salt-color-blue-100);--salt-palette-interact-foreground-partialDisabled: var(--salt-color-blue-100-fade-foreground);--salt-palette-measured-fill: var(--salt-color-blue-300);--salt-palette-measured-fill-disabled: var(--salt-color-blue-300-fade-fill);--salt-palette-measured-foreground: var(--salt-color-gray-90);--salt-palette-measured-foreground-active: var(--salt-color-blue-300);--salt-palette-measured-foreground-disabled: var(--salt-color-gray-90-fade-foreground);--salt-palette-measured-foreground-activeDisabled: var(--salt-color-blue-300-fade-fill);--salt-palette-measured-background: var(--salt-color-gray-300);--salt-palette-measured-background-disabled: var(--salt-color-gray-300-fade-background);--salt-palette-measured-border: var(--salt-color-gray-90);--salt-palette-measured-border-disabled: var(--salt-color-gray-90-fade-border);--salt-palette-neutral-tertiary-background-readonly: transparent;--salt-palette-error-foreground-disabled: var(--salt-color-red-500-fade-foreground);--salt-palette-error-border-disabled: var(--salt-color-red-500-fade-border);--salt-palette-info-border-disabled: var(--salt-color-blue-500-fade-border);--salt-palette-info-foreground-disabled: var(--salt-color-blue-500-fade-foreground);--salt-palette-negative-foreground-disabled: var(--salt-color-red-300-fade-foreground);--salt-palette-positive-foreground-disabled: var(--salt-color-green-300-fade-foreground);--salt-palette-success-border-disabled: var(--salt-color-green-400-fade-border);--salt-palette-success-foreground-disabled: var(--salt-color-green-400-fade-foreground);--salt-palette-warning-foreground-disabled: var(--salt-color-orange-500-fade-foreground);--salt-palette-warning-border-disabled: var(--salt-color-orange-500-fade-border)}.saltButton{white-space:nowrap}.saltButton-primary{--saltButton-borderColor: var(--salt-actionable-primary-foreground);--saltButton-borderWidth: 1px;--saltButton-borderRadius: 6px;--saltButton-borderStyle: solid;--vuu-icon-color: var(--saltIcon-color)}.saltButton-primary:hover{--saltButton-borderColor: var(--salt-actionable-primary-background-hover) }.saltCheckbox{--vuu-icon-size: 12px;--vuu-icon-left: -1px;--vuu-icon-top: -1px}.saltCheckboxIcon{border-radius:3px;height:12px;width:12px}.saltCheckboxIcon-checked{background-color:var(--vuuCheckboxIcon-background-checked, var(--salt-selectable-background-selected))}.saltCheckboxIcon-checked.saltCheckboxIcon-disabled,.saltCheckbox:hover .saltCheckboxIcon-checked.saltCheckboxIcon-disabled{background-color:var(--salt-selectable-background-disabled);border-color:transparent}.saltCheckboxIcon-checked:after{content:"";background-color:#fff;left:var(--vuu-icon-left, auto);height:var(--vuu-icon-height, var(--vuu-icon-size, 12px));-webkit-mask:var(--vuu-svg-tick) center center/var(--vuu-icon-size) var(--vuu-icon-size);mask:var(--vuu-icon-svg) center center/var(--vuu-icon-size) var(--vuu-icon-size);mask-repeat:no-repeat;-webkit-mask-repeat:no-repeat;position:absolute;top:var(--vuu-icon-top, auto);width:var(--vuu-icon-width, var(--vuu-icon-size, 12px))}.saltIcon{display:none}.saltInput-activationIndicator{display:none}.saltInput-primary{--saltInput-height: 24px;border:solid 1px var(--input-borderColor, var(--salt-editable-borderColor));border-radius:6px}.saltInput-focused:hover,.saltInput-focused{--input-borderColor: var(--vuu-color-purple-10)}.vuu-theme .vuuSplitter{--splitter-background: var(--vuu-color-gray-05);--splitter-size: 9px;--splitter-borderColor: white;--splitter-borderStyle: none solid none solid;--splitter-borderWidth: 4px}.vuu-theme .vuuSplitter-column{--splitter-borderStyle: solid none solid none}.saltSwitch{--vuu-icon-left: -1px}.saltSwitch-track,.saltSwitch-track:hover{background-color:var(--vuu-color-gray-45);border:none;border-radius:4px;height:14px;padding:0 2px;width:26px}.saltSwitch-thumb{background-color:var(--vuu-color-white);border:none;border-radius:3px;height:10px;margin:0;width:10px}.saltSwitch-checked .saltSwitch-track{background-color:var(--salt-selectable-background-selected)}.saltSwitch-checked .saltSwitch-thumb,.saltSwitch-checked:hover .saltSwitch-thumb{background-color:#fff;transform:translate(calc(100% + 2px))}.saltSwitch-checked .saltSwitch-thumb:after{background-color:var(--vuu-color-purple-10);content:"";left:var(--vuu-icon-left, auto);height:var(--vuu-icon-height, var(--vuu-icon-size, 12px));-webkit-mask:var(--vuu-svg-tick) center center/var(--vuu-icon-size) var(--vuu-icon-size);mask:var(--vuu-icon-svg) center center/var(--vuu-icon-size) var(--vuu-icon-size);mask-repeat:no-repeat;-webkit-mask-repeat:no-repeat;position:absolute;top:var(--vuu-icon-top, auto);width:var(--vuu-icon-width, var(--vuu-icon-size, 12px))}.saltToggleButtonGroup{border-radius:6px;gap:0;padding:0}.saltToggleButtonGroup-horizontal .saltToggleButton{height:24px}.vuuIconToggleButton{--vuu-icon-size: var(--vuuIconToggleButton-iconSize, 48px);width:48px}.vuuIconToggleButton:first-child{border-radius:4px 0 0 4px}.vuuIconToggleButton:last-child{border-radius:0 4px 4px 0} /*# sourceMappingURL=index.css.map */ diff --git a/vuu-ui/cypress/support/component/index.css.map b/vuu-ui/cypress/support/component/index.css.map new file mode 100644 index 000000000..53d6f6e6f --- /dev/null +++ b/vuu-ui/cypress/support/component/index.css.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../../packages/vuu-theme/fonts/NunitoSans.css", "../../../packages/vuu-theme/css/global.css", "../../../packages/vuu-theme/css/foundations/animation.css", "../../../packages/vuu-theme/css/foundations/color.css", "../../../packages/vuu-theme/css/foundations/duration.css", "../../../packages/vuu-theme/css/foundations/fade.css", "../../../packages/vuu-theme/css/foundations/icon.css", "../../../packages/vuu-theme/css/foundations/opacity.css", "../../../packages/vuu-theme/css/foundations/shadow.css", "../../../packages/vuu-theme/css/foundations/size.css", "../../../packages/vuu-theme/css/foundations/spacing.css", "../../../packages/vuu-theme/css/foundations/typography.css", "../../../packages/vuu-theme/css/foundations/zindex.css", "../../../packages/vuu-theme/css/palette/accent.css", "../../../packages/vuu-theme/css/palette/error.css", "../../../packages/vuu-theme/css/palette/info.css", "../../../packages/vuu-theme/css/palette/interact.css", "../../../packages/vuu-theme/css/palette/navigate.css", "../../../packages/vuu-theme/css/palette/negative.css", "../../../packages/vuu-theme/css/palette/neutral.css", "../../../packages/vuu-theme/css/palette/opacity.css", "../../../packages/vuu-theme/css/palette/positive.css", "../../../packages/vuu-theme/css/palette/success.css", "../../../packages/vuu-theme/css/palette/track.css", "../../../packages/vuu-theme/css/palette/warning.css", "../../../packages/vuu-theme/css/characteristics/accent.css", "../../../packages/vuu-theme/css/characteristics/actionable.css", "../../../packages/vuu-theme/css/characteristics/container.css", "../../../packages/vuu-theme/css/characteristics/draggable.css", "../../../packages/vuu-theme/css/characteristics/target.css", "../../../packages/vuu-theme/css/characteristics/editable.css", "../../../packages/vuu-theme/css/characteristics/focused.css", "../../../packages/vuu-theme/css/characteristics/navigable.css", "../../../packages/vuu-theme/css/characteristics/overlayable.css", "../../../packages/vuu-theme/css/characteristics/selectable.css", "../../../packages/vuu-theme/css/characteristics/separable.css", "../../../packages/vuu-theme/css/characteristics/status.css", "../../../packages/vuu-theme/css/characteristics/taggable.css", "../../../packages/vuu-theme/css/characteristics/text.css", "../../../packages/vuu-theme/css/characteristics/track.css", "../../../packages/vuu-theme/css/deprecated/characteristics.css", "../../../packages/vuu-theme/css/deprecated/fade.css", "../../../packages/vuu-theme/css/deprecated/foundations.css", "../../../packages/vuu-theme/css/deprecated/palette.css", "../../../packages/vuu-theme/css/components/button.css", "../../../packages/vuu-theme/css/components/checkbox.css", "../../../packages/vuu-theme/css/components/icon.css", "../../../packages/vuu-theme/css/components/input.css", "../../../packages/vuu-theme/css/components/splitter.css", "../../../packages/vuu-theme/css/components/switch.css", "../../../packages/vuu-theme/css/components/toggle-button.css"], + "sourcesContent": ["/* latin */\n@font-face {\n font-family: 'Nunito Sans';\n font-style: normal;\n font-weight: 300;\n font-stretch: 100%;\n font-display: swap;\n src: url(./NunitoSansv15.woff2) format('woff2');\n unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\n} /* latin */\n@font-face {\n font-family: 'Nunito Sans';\n font-style: normal;\n font-weight: 400;\n font-stretch: 100%;\n font-display: swap;\n src: url(./NunitoSansv15.woff2) format('woff2');\n unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\n} /* latin */\n@font-face {\n font-family: 'Nunito Sans';\n font-style: normal;\n font-weight: 500;\n font-stretch: 100%;\n font-display: swap;\n src: url(./NunitoSansv15.woff2) format('woff2');\n unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\n}\n /* latin */\n@font-face {\n font-family: 'Nunito Sans';\n font-style: normal;\n font-weight: 600;\n font-stretch: 100%;\n font-display: swap;\n src: url(./NunitoSansv15.woff2) format('woff2');\n unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\n}\n /* latin */\n @font-face {\n font-family: 'Nunito Sans';\n font-style: normal;\n font-weight: 700;\n font-stretch: 100%;\n font-display: swap;\n src: url(./NunitoSansv15.woff2) format('woff2');\n unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\n }\n /* latin */\n @font-face {\n font-family: 'Nunito Sans';\n font-style: normal;\n font-weight: 800;\n font-stretch: 100%;\n font-display: swap;\n src: url(./NunitoSansv15.woff2) format('woff2');\n unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\n }", "\n .vuu-theme {\n color: var(--salt-text-primary-foreground);\n font-family: var(--salt-typography-fontFamily);\n font-size: var(--salt-text-fontSize);\n letter-spacing: var(--salt-text-letterSpacing);\n line-height: var(--salt-text-lineHeight);\n}\n\n::selection {\n background: var(--salt-text-background-selected);\n color: var(--salt-text-color-selected, inherit);\n}\n\n.vuu-theme[data-mode=\"light\"] {\n color-scheme: light;\n}\n\n.vuu-theme[data-mode=\"dark\"] {\n color-scheme: dark;\n}\n\n/* Setting every element's box-sizing to border-box ensures the declared width\nof the element is never exceeded due to padding or border. */\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n.salt-visuallyHidden {\n position: absolute;\n height: 1px;\n width: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border-width: 0;\n}\n", ".vuu-density-touch,\n.vuu-density-low,\n.vuu-density-medium,\n.vuu-density-high {\n --salt-animation-opacity-start: 0;\n --salt-animation-opacity-end: 1;\n --salt-animation-scale-start: 0;\n --salt-animation-scale-end: 1;\n --salt-animation-transform-start: 100%;\n --salt-animation-transform-end: 0;\n --salt-animation-duration: 0.3s;\n --salt-animation-timing-function: ease-in;\n\n /* Slide Animations */\n --salt-animation-slide-in-top: slide-in-top var(--salt-animation-duration) var(--salt-animation-timing-function);\n --salt-animation-slide-in-left: slide-in-left var(--salt-animation-duration) var(--salt-animation-timing-function);\n --salt-animation-slide-in-right: slide-in-right var(--salt-animation-duration) var(--salt-animation-timing-function);\n --salt-animation-slide-in-bottom: slide-in-bottom var(--salt-animation-duration) var(--salt-animation-timing-function);\n\n --salt-animation-slide-out-top: slide-out-top var(--salt-animation-duration) var(--salt-animation-timing-function) both;\n --salt-animation-slide-out-left: slide-out-left var(--salt-animation-duration) var(--salt-animation-timing-function) both;\n --salt-animation-slide-out-right: slide-out-right var(--salt-animation-duration) var(--salt-animation-timing-function) both;\n --salt-animation-slide-out-bottom: slide-out-bottom var(--salt-animation-duration) var(--salt-animation-timing-function) both;\n\n /* Fade Animations */\n --salt-animation-fade-in-back: fade-in-back var(--salt-animation-duration) var(--salt-animation-timing-function);\n --salt-animation-fade-in-forward: fade-in-forward var(--salt-animation-duration) var(--salt-animation-timing-function);\n --salt-animation-fade-in-center: fade-in-center var(--salt-animation-duration) var(--salt-animation-timing-function);\n --salt-animation-fade-out-back: fade-out-back var(--salt-animation-duration) ease-out both;\n}\n\n/*Slide keyframes */\n@keyframes slide-in-top {\n 0% {\n opacity: var(--salt-animation-opacity-start);\n transform: translateY(var(--salt-animation-transform-start));\n }\n 100% {\n opacity: var(--salt-animation-opacity-end);\n transform: translateY(var(--salt-animation-transform-end));\n }\n}\n@keyframes slide-out-top {\n 0% {\n opacity: var(--salt-animation-opacity-end);\n transform: translateY(var(--salt-animation-transform-end));\n }\n 100% {\n opacity: var(--salt-animation-opacity-start);\n transform: translateY(var(--salt-animation-transform-start));\n }\n}\n@keyframes slide-in-left {\n 0% {\n opacity: var(--salt-animation-opacity-start);\n transform: translateX(calc(-1 * var(--salt-animation-transform-start)));\n }\n 100% {\n opacity: var(--salt-animation-opacity-end);\n transform: translateX(var(--salt-animation-transform-end));\n }\n}\n@keyframes slide-out-left {\n 0% {\n opacity: var(--salt-animation-opacity-end);\n transform: translateX(var(--salt-animation-transform-end));\n }\n 100% {\n opacity: var(--salt-animation-opacity-start);\n transform: translateX(calc(-1 * var(--salt-animation-transform-start)));\n }\n}\n@keyframes slide-in-right {\n 0% {\n opacity: var(--salt-animation-opacity-start);\n transform: translateX(var(--salt-animation-transform-start));\n }\n 100% {\n opacity: var(--salt-animation-opacity-end);\n transform: translateX(var(--salt-animation-transform-end));\n }\n}\n@keyframes slide-out-right {\n 0% {\n opacity: var(--salt-animation-opacity-end);\n transform: translateX(var(--salt-animation-transform-end));\n }\n 100% {\n opacity: var(--salt-animation-opacity-start);\n transform: translateX(var(--salt-animation-transform-start));\n }\n}\n@keyframes slide-in-bottom {\n 0% {\n opacity: var(--salt-animation-opacity-start);\n transform: translateY(calc(-1 * var(--salt-animation-transform-start)));\n }\n 100% {\n opacity: var(--salt-animation-opacity-end);\n transform: translateY(var(--salt-animation-transform-end));\n }\n}\n@keyframes slide-out-bottom {\n 0% {\n opacity: var(--salt-animation-opacity-end);\n transform: translateY(var(--salt-animation-transform-end));\n }\n 100% {\n opacity: var(--salt-animation-opacity-start);\n transform: translateY(calc(-1 * var(--salt-animation-transform-start)));\n }\n}\n/* Fade keyframes */\n@keyframes fade-in-back {\n 0% {\n --salt-animation-scale-start: 1.4;\n opacity: var(--salt-animation-opacity-start);\n transform: scale(var(--salt-animation-scale-start));\n }\n\n 100% {\n opacity: var(--salt-animation-opacity-end);\n transform: scale(var(--salt-animation-scale-end));\n }\n}\n@keyframes fade-in-forward {\n 0% {\n --salt-animation-scale-start: 0.6;\n opacity: var(--salt-animation-opacity-start);\n transform: scale(var(--salt-animation-scale-start));\n }\n\n 100% {\n opacity: var(--salt-animation-opacity-end);\n transform: scale(var(--salt-animation-scale-end));\n }\n}\n@keyframes fade-in-center {\n 0% {\n opacity: var(--salt-animation-opacity-start);\n }\n\n 100% {\n opacity: var(--salt-animation-opacity-end);\n }\n}\n\n@keyframes fade-out-back {\n 0% {\n opacity: var(--salt-animation-opacity-end);\n }\n 100% {\n opacity: var(--salt-animation-opacity-start);\n }\n}\n", ".vuu-theme {\n\n --vuu-fade-light : 0.13;\n\n --vuu-color-transparent: transparent;\n --vuu-color-black: black;\n --vuu-color-white: white;\n\n /** text-selection */\n --vuu-color-blue-40: rgb(164, 213, 244); /* #A4D5F4 */\n\n\n --vuu-color-purple-10: rgb(109,24,189); /* #6D18BD */\n --vuu-color-purple-10-fade-light: rgba(109,24,189, var(--vuu-fade-light)); \n\n --vuu-color-pink-10: rgb(234, 120, 128); /* #F37880 */\n\n\n --vuu-color-gray-05: rgb(222, 222, 222); /* #DEDEDE */\n --vuu-color-gray-10: rgb(228, 227, 231); /* #E4E3E7 */\n --vuu-color-gray-20: rgb(245, 242, 248); /* #F5F2F8 */\n --vuu-color-gray-25: rgb(244, 244, 244) ; /* #F4F4F4 */\n --vuu-color-gray-28: rgb(249, 249, 251); /* #F9F9FB */\n --vuu-color-gray-30: rgb(214, 215, 218); /* #D6D7Da */\n --vuu-color-gray-35: rgb(155, 158, 168); /* #9B9EA8; */\n --vuu-color-gray-40: rgb(169, 170, 173); /* #A9AAAD */ \n --vuu-color-gray-42: rgb(135, 139, 158); /* #878b9e */ \n --vuu-color-gray-45: rgb(119, 124, 148); /* #777C94 */ \n --vuu-color-gray-50: rgb(96, 100, 119); /* #606477 */\n --vuu-color-gray-80: rgb(21, 23, 27); /* #15171B */ \n\n--vuu-color-green-50: rgb(102, 174, 90); /* #66AE5A */\n--vuu-color-green-60: rgb(36, 137, 19); /* #248913 */\n--vuu-color-green-60-fade-30: rgba(36, 137, 19, .3); /* #248913 */\n\n--vuu-color-red-50: rgb(226, 52, 52); /* #E23434 */\n\n --vuu-color-yellow-20: rgb(244, 202, 51); /* #F4CA33 */\n\n\n\n /* Color palette will stay the same no matter of theming */\n --salt-color-white: rgb(255, 255, 255);\n --salt-color-black: rgb(0, 0, 0);\n\n --salt-color-red-10: rgb(255, 227, 224);\n --salt-color-red-20: rgb(255, 207, 201);\n --salt-color-red-30: rgb(255, 187, 178);\n --salt-color-red-40: rgb(255, 167, 156);\n --salt-color-red-50: rgb(255, 148, 133);\n --salt-color-red-100: rgb(255, 128, 111);\n --salt-color-red-200: rgb(255, 108, 88);\n --salt-color-red-300: rgb(255, 89, 66);\n --salt-color-red-400: rgb(237, 65, 42);\n --salt-color-red-500: rgb(227, 43, 22);\n --salt-color-red-600: rgb(196, 32, 16);\n --salt-color-red-700: rgb(166, 21, 11);\n --salt-color-red-800: rgb(136, 10, 5);\n --salt-color-red-900: rgb(65, 37, 34);\n\n --salt-color-orange-10: rgb(255, 232, 191);\n --salt-color-orange-20: rgb(254, 223, 166);\n --salt-color-orange-30: rgb(254, 214, 142);\n --salt-color-orange-40: rgb(254, 205, 118);\n --salt-color-orange-50: rgb(254, 197, 94);\n --salt-color-orange-100: rgb(250, 181, 81);\n --salt-color-orange-200: rgb(246, 165, 68);\n --salt-color-orange-300: rgb(242, 149, 56);\n --salt-color-orange-400: rgb(238, 133, 43);\n --salt-color-orange-500: rgb(234, 115, 25);\n --salt-color-orange-600: rgb(224, 101, 25);\n --salt-color-orange-700: rgb(214, 85, 19);\n --salt-color-orange-800: rgb(204, 68, 13);\n --salt-color-orange-900: rgb(54, 44, 36);\n\n --salt-color-green-10: rgb(209, 244, 201);\n --salt-color-green-20: rgb(184, 232, 182);\n --salt-color-green-30: rgb(160, 221, 164);\n --salt-color-green-40: rgb(136, 210, 145);\n --salt-color-green-50: rgb(112, 199, 127);\n --salt-color-green-100: rgb(93, 189, 116);\n --salt-color-green-200: rgb(77, 180, 105);\n --salt-color-green-300: rgb(60, 171, 96);\n --salt-color-green-400: rgb(48, 156, 90);\n --salt-color-green-500: rgb(36, 135, 75);\n --salt-color-green-600: rgb(24, 114, 61);\n --salt-color-green-700: rgb(12, 93, 46);\n --salt-color-green-800: rgb(1, 73, 32);\n --salt-color-green-900: rgb(35, 52, 43);\n\n --salt-color-teal-10: rgb(218, 240, 240);\n --salt-color-teal-20: rgb(199, 232, 232);\n --salt-color-teal-30: rgb(180, 224, 225);\n --salt-color-teal-40: rgb(162, 217, 218);\n --salt-color-teal-50: rgb(141, 205, 209);\n --salt-color-teal-100: rgb(123, 193, 200);\n --salt-color-teal-200: rgb(99, 181, 192);\n --salt-color-teal-300: rgb(73, 160, 172);\n --salt-color-teal-400: rgb(48, 149, 166);\n --salt-color-teal-500: rgb(0, 130, 151);\n --salt-color-teal-600: rgb(27, 107, 133);\n --salt-color-teal-700: rgb(0, 85, 113);\n --salt-color-teal-800: rgb(1, 65, 86);\n --salt-color-teal-900: rgb(0, 49, 76);\n\n --salt-color-blue-10: rgb(203, 231, 249);\n --salt-color-blue-20: rgb(183, 222, 246);\n --salt-color-blue-30: rgb(164, 213, 244);\n --salt-color-blue-40: rgb(144, 204, 242);\n --salt-color-blue-50: rgb(125, 195, 240);\n --salt-color-blue-100: rgb(100, 177, 228);\n --salt-color-blue-200: rgb(75, 159, 216);\n --salt-color-blue-300: rgb(51, 141, 205);\n --salt-color-blue-400: rgb(46, 132, 198);\n --salt-color-blue-500: rgb(38, 112, 169);\n --salt-color-blue-600: rgb(21, 92, 147);\n --salt-color-blue-700: rgb(0, 71, 123);\n --salt-color-blue-800: rgb(39, 60, 77);\n --salt-color-blue-900: rgb(35, 47, 56);\n\n --salt-color-purple-10: rgb(249, 224, 247);\n --salt-color-purple-20: rgb(247, 212, 244);\n --salt-color-purple-30: rgb(245, 201, 241);\n --salt-color-purple-40: rgb(243, 189, 238);\n --salt-color-purple-50: rgb(241, 178, 235);\n --salt-color-purple-100: rgb(223, 156, 225);\n --salt-color-purple-200: rgb(205, 135, 215);\n --salt-color-purple-300: rgb(192, 116, 203);\n --salt-color-purple-400: rgb(169, 97, 181);\n --salt-color-purple-500: rgb(150, 78, 162);\n --salt-color-purple-600: rgb(129, 60, 141);\n --salt-color-purple-700: rgb(103, 46, 122);\n --salt-color-purple-800: rgb(83, 37, 109);\n --salt-color-purple-900: rgb(59, 16, 84);\n\n --salt-color-gray-10: rgb(242, 244, 246);\n --salt-color-gray-20: rgb(234, 237, 239);\n --salt-color-gray-30: rgb(224, 228, 233);\n --salt-color-gray-40: rgb(217, 221, 227);\n --salt-color-gray-50: rgb(206, 210, 217);\n --salt-color-gray-60: rgb(197, 201, 208);\n --salt-color-gray-70: rgb(180, 183, 190);\n --salt-color-gray-80: rgb(159, 163, 170);\n --salt-color-gray-90: rgb(132, 135, 142);\n --salt-color-gray-100: rgb(116, 119, 127);\n --salt-color-gray-200: rgb(97, 101, 110);\n --salt-color-gray-300: rgb(76, 80, 91);\n --salt-color-gray-400: rgb(68, 72, 79);\n --salt-color-gray-500: rgb(59, 63, 70);\n --salt-color-gray-600: rgb(47, 49, 54);\n --salt-color-gray-700: rgb(42, 44, 47);\n --salt-color-gray-800: rgb(36, 37, 38);\n --salt-color-gray-900: rgb(22, 22, 22);\n}\n", ".vuu-theme {\n --salt-duration-instant: 0ms;\n --salt-duration-perceptible: 300ms;\n --salt-duration-notable: 1000ms;\n --salt-duration-cutoff: 10000ms;\n}\n", ".vuu-theme {\n --salt-color-blue-100-fade-foreground: rgba(100, 177, 228, var(--salt-palette-opacity-disabled));\n --salt-color-blue-500-fade-foreground: rgba(38, 112, 169, var(--salt-palette-opacity-disabled));\n --salt-color-blue-600-fade-foreground: rgba(21, 92, 147, var(--salt-palette-opacity-disabled));\n --salt-color-gray-200-fade-foreground: rgba(97, 101, 110, var(--salt-palette-opacity-disabled));\n --salt-color-gray-70-fade-foreground: rgba(180, 183, 190, var(--salt-palette-opacity-disabled));\n --salt-color-gray-90-fade-foreground: rgba(132, 135, 142, var(--salt-palette-opacity-disabled));\n --salt-color-gray-900-fade-foreground: rgba(22, 22, 22, var(--salt-palette-opacity-disabled));\n --salt-color-green-300-fade-foreground: rgba(60, 171, 96, var(--salt-palette-opacity-disabled));\n --salt-color-green-400-fade-foreground: rgba(48, 156, 90, var(--salt-palette-opacity-disabled));\n --salt-color-green-500-fade-foreground: rgba(36, 135, 75, var(--salt-palette-opacity-disabled));\n --salt-color-green-700-fade-foreground: rgba(12, 93, 46, var(--salt-palette-opacity-disabled));\n --salt-color-red-300-fade-foreground: rgba(255, 89, 66, var(--salt-palette-opacity-disabled));\n --salt-color-red-500-fade-foreground: rgba(227, 43, 22, var(--salt-palette-opacity-disabled));\n --salt-color-red-700-fade-foreground: rgba(166, 21, 11, var(--salt-palette-opacity-disabled));\n --salt-color-white-fade-foreground: rgba(255, 255, 255, var(--salt-palette-opacity-disabled));\n\n --salt-color-blue-500-fade-border: rgba(38, 112, 169, var(--salt-palette-opacity-disabled));\n --salt-color-gray-60-fade-border: rgba(197, 201, 208, var(--salt-palette-opacity-disabled));\n --salt-color-gray-90-fade-border: rgba(132, 135, 142, var(--salt-palette-opacity-disabled));\n --salt-color-gray-200-fade-border: rgba(97, 101, 110, var(--salt-palette-opacity-disabled));\n --salt-color-gray-300-fade-border: rgba(76, 80, 91, var(--salt-palette-opacity-disabled));\n --salt-color-green-400-fade-border: rgba(48, 156, 90, var(--salt-palette-opacity-disabled));\n --salt-color-green-500-fade-border: rgba(36, 135, 75, var(--salt-palette-opacity-disabled));\n --salt-color-orange-400-fade-border: rgba(238, 133, 43, var(--salt-palette-opacity-disabled));\n --salt-color-orange-500-fade-border: rgba(234, 115, 25, var(--salt-palette-opacity-disabled));\n --salt-color-orange-600-fade-border: rgba(224, 101, 25, var(--salt-palette-opacity-disabled));\n --salt-color-orange-700-fade-border: rgba(214, 85, 19, var(--salt-palette-opacity-disabled));\n --salt-color-red-500-fade-border: rgba(227, 43, 22, var(--salt-palette-opacity-disabled));\n\n --salt-color-gray-90-fade-border-readonly: rgba(132, 135, 142, var(--salt-palette-opacity-border-readonly));\n --salt-color-gray-200-fade-border-readonly: rgba(97, 101, 110, var(--salt-palette-opacity-border-readonly));\n\n --salt-color-blue-30-fade-background: rgba(164, 213, 244, var(--salt-palette-opacity-disabled));\n --salt-color-blue-500-fade-background: rgba(38, 112, 169, var(--salt-palette-opacity-disabled));\n --salt-color-blue-600-fade-background: rgba(21, 92, 147, var(--salt-palette-opacity-disabled));\n --salt-color-blue-700-fade-background: rgba(0, 71, 123, var(--salt-palette-opacity-disabled));\n --salt-color-gray-20-fade-background: rgba(234, 237, 239, var(--salt-palette-opacity-disabled));\n --salt-color-gray-60-fade-background: rgba(197, 201, 208, var(--salt-palette-opacity-disabled));\n --salt-color-gray-70-fade-background: rgba(180, 183, 190, var(--salt-palette-opacity-disabled));\n --salt-color-gray-200-fade-background: rgba(97, 101, 110, var(--salt-palette-opacity-disabled));\n --salt-color-gray-300-fade-background: rgba(76, 80, 91, var(--salt-palette-opacity-disabled));\n --salt-color-gray-600-fade-background: rgba(47, 49, 54, var(--salt-palette-opacity-disabled));\n --salt-color-gray-800-fade-background: rgba(36, 37, 38, var(--salt-palette-opacity-disabled));\n --salt-color-white-fade-background: rgba(255, 255, 255, var(--salt-palette-opacity-disabled));\n\n --salt-color-white-fade-background-readonly: rgba(255, 255, 255, var(--salt-palette-opacity-background-readonly));\n --salt-color-gray-20-fade-background-readonly: rgba(234, 237, 239, var(--salt-palette-opacity-background-readonly));\n --salt-color-gray-600-fade-background-readonly: rgba(47, 49, 54, var(--salt-palette-opacity-background-readonly));\n --salt-color-gray-800-fade-background-readonly: rgba(36, 37, 38, var(--salt-palette-opacity-background-readonly));\n\n --salt-color-black-fade-backdrop: rgba(36, 37, 38, var(--salt-palette-opacity-backdrop));\n\n --salt-color-blue-100-fade-fill: rgba(100, 177, 228, var(--salt-palette-opacity-disabled));\n --salt-color-blue-600-fade-fill: rgba(21, 92, 147, var(--salt-palette-opacity-disabled));\n\n --salt-color-white-fade-separatorOpacity-primary: rgba(255, 255, 255, var(--salt-palette-opacity-primary-border));\n --salt-color-white-fade-separatorOpacity-secondary: rgba(255, 255, 255, var(--salt-palette-opacity-secondary-border));\n --salt-color-white-fade-separatorOpacity-tertiary: rgba(255, 255, 255, var(--salt-palette-opacity-tertiary-border));\n --salt-color-black-fade-separatorOpacity-primary: rgba(0, 0, 0, var(--salt-palette-opacity-primary-border));\n --salt-color-black-fade-separatorOpacity-secondary: rgba(0, 0, 0, var(--salt-palette-opacity-secondary-border));\n --salt-color-black-fade-separatorOpacity-tertiary: rgba(0, 0, 0, var(--salt-palette-opacity-tertiary-border));\n}\n", ".vuu-density-touch {\n --salt-icon-size-base: 16px;\n --salt-icon-size-status-adornment: 12px;\n}\n\n.vuu-density-low {\n --salt-icon-size-base: 14px;\n --salt-icon-size-status-adornment: 10px;\n}\n\n.vuu-density-medium {\n --salt-icon-size-base: 12px;\n --salt-icon-size-status-adornment: 8px;\n}\n\n.vuu-density-high {\n --salt-icon-size-base: 10px;\n --salt-icon-size-status-adornment: 6px;\n}\n", ".vuu-theme {\n --salt-opacity-0: 0;\n --salt-opacity-8: 0.08;\n --salt-opacity-15: 0.15;\n --salt-opacity-25: 0.25;\n --salt-opacity-40: 0.4;\n --salt-opacity-70: 0.7;\n}\n", ".vuu-theme[data-mode=\"light\"] {\n --salt-shadow-1-color: rgba(0, 0, 0, 0.1);\n --salt-shadow-2-color: rgba(0, 0, 0, 0.1);\n --salt-shadow-3-color: rgba(0, 0, 0, 0.15);\n --salt-shadow-4-color: rgba(0, 0, 0, 0.2);\n --salt-shadow-5-color: rgba(0, 0, 0, 0.3);\n}\n\n.vuu-theme[data-mode=\"dark\"] {\n --salt-shadow-1-color: rgba(0, 0, 0, 0.5);\n --salt-shadow-2-color: rgba(0, 0, 0, 0.5);\n --salt-shadow-3-color: rgba(0, 0, 0, 0.55);\n --salt-shadow-4-color: rgba(0, 0, 0, 0.55);\n --salt-shadow-5-color: rgba(0, 0, 0, 0.65);\n}\n\n.vuu-theme {\n --salt-shadow-0: none;\n --salt-shadow-1: 0 1px 3px 0 var(--salt-shadow-1-color);\n --salt-shadow-2: 0 2px 4px 0 var(--salt-shadow-2-color);\n --salt-shadow-3: 0 4px 8px 0 var(--salt-shadow-3-color);\n --salt-shadow-4: 0 6px 10px 0 var(--salt-shadow-4-color);\n --salt-shadow-5: 0 12px 40px 0 var(--salt-shadow-5-color);\n}\n", "/** Size */\n.vuu-density-touch,\n.vuu-density-low,\n.vuu-density-medium,\n.vuu-density-high {\n --salt-size-basis-unit: 4px;\n\n --salt-size-adornmentGap: calc(0.75 * var(--salt-size-unit));\n --salt-size-container-spacing: calc(3 * var(--salt-size-unit));\n --salt-size-separator-strokeWidth: 1px;\n --salt-size-selectable: calc(var(--salt-size-base) - (1.5 * var(--salt-size-unit)) - (0.5 * var(--salt-size-basis-unit)));\n --salt-size-separator-height: calc(var(--salt-size-compact) + 1.5 * var(--salt-size-basis-unit));\n --salt-size-sharktooth-height: 5px;\n --salt-size-sharktooth-width: 10px;\n --salt-size-stackable: calc(var(--salt-size-base) + var(--salt-size-unit));\n}\n\n.vuu-density-high {\n --salt-size-unit: calc(var(--salt-size-basis-unit) * 1);\n --salt-size-compact: calc(var(--salt-size-basis-unit) * 1.5);\n --salt-size-accent: calc(var(--salt-size-basis-unit) * 0.5);\n\n /* New size work */\n --salt-size-adornment: 6px;\n --salt-size-bar: 2px;\n --salt-size-base: 20px;\n --salt-size-border: 1px;\n --salt-size-selectable: 12px;\n --salt-size-icon: 12px;\n}\n\n.vuu-density-medium {\n --salt-size-unit: calc(var(--salt-size-basis-unit) * 2);\n --salt-size-compact: calc(var(--salt-size-basis-unit) * 2);\n --salt-size-accent: calc(var(--salt-size-basis-unit) * 1);\n\n /* New size work */\n --salt-size-adornment: 8px;\n --salt-size-bar: 4px;\n --salt-size-base: 28px;\n --salt-size-border: 1px;\n --salt-size-selectable: 14px;\n --salt-size-icon: 12px;\n}\n\n.vuu-density-low {\n --salt-size-unit: calc(var(--salt-size-basis-unit) * 3);\n --salt-size-compact: calc(var(--salt-size-basis-unit) * 2.5);\n --salt-size-accent: calc(var(--salt-size-basis-unit) * 1.5);\n\n /* New size work */\n --salt-size-adornment: 10px;\n --salt-size-bar: 6px;\n --salt-size-base: 36px;\n --salt-size-border: 1px;\n --salt-size-selectable: 16px;\n --salt-size-icon: 14px;\n}\n\n.vuu-density-touch {\n --salt-size-unit: calc(var(--salt-size-basis-unit) * 4);\n --salt-size-compact: calc(var(--salt-size-basis-unit) * 3);\n --salt-size-accent: calc(var(--salt-size-basis-unit) * 2);\n\n /* New size work */\n --salt-size-adornment: 12px;\n --salt-size-bar: 8px;\n --salt-size-base: 44px;\n --salt-size-border: 1px;\n --salt-size-selectable: 18px;\n --salt-size-icon: 16px;\n}\n", ".vuu-density-touch {\n --salt-spacing-100: 16px;\n}\n\n.vuu-density-low {\n --salt-spacing-100: 12px;\n}\n\n.vuu-density-medium {\n --salt-spacing-100: 8px;\n}\n\n.vuu-density-high {\n --salt-spacing-100: 4px;\n}\n\n.vuu-density-touch,\n.vuu-density-low,\n.vuu-density-medium,\n.vuu-density-high {\n --salt-spacing-25: calc(0.25 * var(--salt-spacing-100));\n --salt-spacing-50: calc(0.5 * var(--salt-spacing-100));\n --salt-spacing-75: calc(0.75 * var(--salt-spacing-100));\n\n --salt-spacing-150: calc(1.5 * var(--salt-spacing-100));\n --salt-spacing-200: calc(2 * var(--salt-spacing-100));\n --salt-spacing-250: calc(2.5 * var(--salt-spacing-100));\n --salt-spacing-300: calc(3 * var(--salt-spacing-100));\n --salt-spacing-350: calc(3.5 * var(--salt-spacing-100));\n --salt-spacing-400: calc(4 * var(--salt-spacing-100));\n}\n", ".vuu-theme {\n --salt-typography-fontFamily: \"Nunito Sans\";\n --salt-typography-fontFamily-code: \"PT Mono\";\n\n --salt-typography-fontWeight-light: 300;\n --salt-typography-fontWeight-regular: 400;\n --salt-typography-fontWeight-medium: 500;\n --salt-typography-fontWeight-semiBold: 600;\n --salt-typography-fontWeight-bold: 700;\n --salt-typography-fontWeight-extraBold: 800;\n}\n", ".vuu-density-touch,\n.vuu-density-low,\n.vuu-density-medium,\n.vuu-density-high {\n --salt-zIndex-default: 1;\n --salt-zIndex-popout: 1000;\n --salt-zIndex-docked: 1050;\n --salt-zIndex-appHeader: 1100;\n --salt-zIndex-drawer: 1200;\n --salt-zIndex-modal: 1300;\n --salt-zIndex-notification: 1400;\n --salt-zIndex-dragObject: 1420;\n --salt-zIndex-contextMenu: 1450;\n --salt-zIndex-flyover: 1500;\n}\n", ".vuu-theme[data-mode=\"light\"] {\n --salt-palette-accent-background: var(--salt-color-blue-500);\n --salt-palette-accent-background-disabled: var(--salt-color-blue-500-fade-background);\n --salt-palette-accent-border: var(--salt-color-blue-500);\n --salt-palette-accent-border-disabled: var(--salt-color-blue-500-fade-border);\n --salt-palette-accent-foreground: var(--salt-color-white);\n --salt-palette-accent-foreground-disabled: var(--salt-color-white-fade-foreground);\n}\n\n.vuu-theme[data-mode=\"dark\"] {\n --salt-palette-accent-background: var(--salt-color-blue-500);\n --salt-palette-accent-background-disabled: var(--salt-color-blue-500-fade-background);\n --salt-palette-accent-border: var(--salt-color-blue-500);\n --salt-palette-accent-border-disabled: var(--salt-color-blue-500-fade-border);\n --salt-palette-accent-foreground: var(--salt-color-white);\n --salt-palette-accent-foreground-disabled: var(--salt-color-white-fade-foreground);\n}\n", ".vuu-theme[data-mode=\"light\"] {\n --salt-palette-error-background: var(--salt-color-red-10);\n --salt-palette-error-background-selected: var(--salt-color-red-20);\n --salt-palette-error-border: var(--salt-color-red-500);\n --salt-palette-error-foreground: var(--salt-color-red-500);\n}\n\n.vuu-theme[data-mode=\"dark\"] {\n --salt-palette-error-background: var(--salt-color-red-900);\n --salt-palette-error-background-selected: var(--salt-color-red-900);\n --salt-palette-error-border: var(--salt-color-red-500);\n --salt-palette-error-foreground: var(--salt-color-red-500);\n}\n", ".vuu-theme[data-mode=\"light\"] {\n --salt-palette-info-background: var(--salt-color-blue-10);\n --salt-palette-info-border: var(--salt-color-blue-500);\n --salt-palette-info-foreground: var(--salt-color-blue-500);\n}\n\n.vuu-theme[data-mode=\"dark\"] {\n --salt-palette-info-background: var(--salt-color-blue-900);\n --salt-palette-info-border: var(--salt-color-blue-500);\n --salt-palette-info-foreground: var(--salt-color-blue-500);\n}\n", ".vuu-theme[data-mode=\"light\"] {\n --salt-palette-interact-background: transparent;\n --salt-palette-interact-background-blurSelected: var(--salt-color-gray-30);\n --salt-palette-interact-background-hover: var(--vuu-color-gray-10);\n --salt-palette-interact-background-active: var(--vuu-color-blue-40);\n --salt-palette-interact-background-disabled: var(--vuu-color-gray-35);\n --salt-palette-interact-background-activeDisabled: var(--salt-color-blue-30-fade-background);\n --salt-palette-interact-border: var(--vuu-color-gray-45);\n --salt-palette-interact-border-active: var(--vuu-color-purple-10);\n --salt-palette-interact-border-activeDisabled: var(--salt-color-blue-600-fade-fill);\n --salt-palette-interact-border-disabled: var(--salt-color-gray-200-fade-border);\n --salt-palette-interact-border-hover: var(--vuu-color-pink-10);\n --salt-palette-interact-border-readonly: var(--salt-color-gray-200-fade-border-readonly);\n --salt-palette-interact-foreground: var(--salt-color-gray-200);\n --salt-palette-interact-foreground-active: var(--vuu-color-purple-10);\n --salt-palette-interact-foreground-activeDisabled: var(--salt-color-blue-600-fade-foreground);\n --salt-palette-interact-foreground-disabled: var(--salt-color-gray-200-fade-foreground);\n --salt-palette-interact-foreground-hover: var(--salt-color-blue-500);\n --salt-palette-interact-outline: var(--salt-color-blue-600);\n\n --salt-palette-interact-cta-background: var(--vuu-color-purple-10);\n --salt-palette-interact-cta-background-active: var(--vuu-color-purple-10);\n --salt-palette-interact-cta-background-activeDisabled: var(--salt-color-blue-700-fade-background);\n --salt-palette-interact-cta-background-disabled: var(--salt-color-blue-600-fade-background);\n --salt-palette-interact-cta-background-hover: var(--vuu-color-pink-10);\n --salt-palette-interact-cta-foreground: var(--salt-color-white);\n --salt-palette-interact-cta-foreground-active: var(--salt-color-white);\n --salt-palette-interact-cta-foreground-activeDisabled: var(--salt-color-white-fade-foreground);\n --salt-palette-interact-cta-foreground-disabled: var(--salt-color-white-fade-foreground);\n --salt-palette-interact-cta-foreground-hover: var(--vuu-color-gray-80);\n --salt-palette-interact-primary-background: var(--vuu-color-white);\n --salt-palette-interact-primary-background-active: var(--vuu-color-gray-50);\n --salt-palette-interact-primary-background-activeDisabled: var(--salt-color-gray-200-fade-background);\n --salt-palette-interact-primary-background-disabled: var(--salt-color-gray-60-fade-background);\n --salt-palette-interact-primary-background-hover: var(--vuu-color-pink-10);\n --salt-palette-interact-primary-foreground: var(--vuu-color-gray-50);\n --salt-palette-interact-primary-foreground-active: var(--salt-color-white);\n --salt-palette-interact-primary-foreground-activeDisabled: var(--salt-color-white-fade-foreground);\n --salt-palette-interact-primary-foreground-disabled: var(--salt-color-gray-900-fade-foreground);\n --salt-palette-interact-primary-foreground-hover: var(--vuu-color-gray-80);\n --salt-palette-interact-secondary-background: transparent;\n --salt-palette-interact-secondary-background-active: var(--vuu-color-purple-10);\n --salt-palette-interact-secondary-background-activeDisabled: var(--salt-color-gray-200-fade-background);\n --salt-palette-interact-secondary-background-disabled: transparent;\n --salt-palette-interact-secondary-background-hover: var(--salt-color-gray-40);\n --salt-palette-interact-secondary-foreground: var(--salt-color-gray-900);\n --salt-palette-interact-secondary-foreground-active: var(--salt-color-white);\n --salt-palette-interact-secondary-foreground-activeDisabled: var(--salt-color-white-fade-foreground);\n --salt-palette-interact-secondary-foreground-disabled: var(--salt-color-gray-900-fade-foreground);\n --salt-palette-interact-secondary-foreground-hover: var(--salt-color-gray-900);\n}\n\n.vuu-theme[data-mode=\"dark\"] {\n --salt-palette-interact-background: transparent;\n --salt-palette-interact-background-active: var(--salt-color-blue-700);\n --salt-palette-interact-background-blurSelected: var(--salt-color-gray-600);\n --salt-palette-interact-background-hover: var(--salt-color-blue-800);\n --salt-palette-interact-background-disabled: transparent;\n --salt-palette-interact-background-activeDisabled: var(--salt-color-blue-700-fade-background);\n --salt-palette-interact-border: var(--salt-color-gray-90);\n --salt-palette-interact-border-active: var(--salt-color-blue-100);\n --salt-palette-interact-border-activeDisabled: var(--salt-color-blue-100-fade-fill);\n --salt-palette-interact-border-disabled: var(--salt-color-gray-90-fade-border);\n --salt-palette-interact-border-hover: var(--salt-color-blue-500);\n --salt-palette-interact-border-readonly: var(--salt-color-gray-90-fade-border-readonly);\n --salt-palette-interact-foreground: var(--salt-color-gray-90);\n --salt-palette-interact-foreground-active: var(--salt-color-blue-100);\n --salt-palette-interact-foreground-activeDisabled: var(--salt-color-blue-100-fade-foreground);\n --salt-palette-interact-foreground-disabled: var(--salt-color-gray-90-fade-foreground);\n --salt-palette-interact-foreground-hover: var(--salt-color-blue-500);\n --salt-palette-interact-outline: var(--vuu-color-pink-10);\n\n --salt-palette-interact-cta-background: var(--salt-color-blue-600);\n --salt-palette-interact-cta-background-active: var(--salt-color-blue-700);\n --salt-palette-interact-cta-background-activeDisabled: var(--salt-color-blue-700-fade-background);\n --salt-palette-interact-cta-background-disabled: var(--salt-color-blue-600-fade-background);\n --salt-palette-interact-cta-background-hover: var(--salt-color-blue-500);\n --salt-palette-interact-cta-foreground: var(--salt-color-white);\n --salt-palette-interact-cta-foreground-active: var(--salt-color-white);\n --salt-palette-interact-cta-foreground-activeDisabled: var(--salt-color-white-fade-foreground);\n --salt-palette-interact-cta-foreground-disabled: var(--salt-color-white-fade-foreground);\n --salt-palette-interact-cta-foreground-hover: var(--salt-color-white);\n --salt-palette-interact-primary-background: var(--salt-color-gray-300);\n --salt-palette-interact-primary-background-active: var(--salt-color-gray-70);\n --salt-palette-interact-primary-background-activeDisabled: var(--salt-color-gray-70-fade-background);\n --salt-palette-interact-primary-background-disabled: var(--salt-color-gray-300-fade-background);\n --salt-palette-interact-primary-background-hover: var(--salt-color-gray-200);\n --salt-palette-interact-primary-foreground: var(--salt-color-white);\n --salt-palette-interact-primary-foreground-active: var(--salt-color-gray-900);\n --salt-palette-interact-primary-foreground-activeDisabled: var(--salt-color-gray-900-fade-foreground);\n --salt-palette-interact-primary-foreground-disabled: var(--salt-color-white-fade-foreground);\n --salt-palette-interact-primary-foreground-hover: var(--salt-color-white);\n --salt-palette-interact-secondary-background: transparent;\n --salt-palette-interact-secondary-background-active: var(--salt-color-gray-70);\n --salt-palette-interact-secondary-background-activeDisabled: var(--salt-color-gray-70-fade-background);\n --salt-palette-interact-secondary-background-disabled: transparent;\n --salt-palette-interact-secondary-background-hover: var(--salt-color-gray-200);\n --salt-palette-interact-secondary-foreground: var(--salt-color-white);\n --salt-palette-interact-secondary-foreground-active: var(--salt-color-gray-900);\n --salt-palette-interact-secondary-foreground-activeDisabled: var(--salt-color-gray-900-fade-foreground);\n --salt-palette-interact-secondary-foreground-disabled: var(--salt-color-white-fade-foreground);\n --salt-palette-interact-secondary-foreground-hover: var(--salt-color-white);\n}\n", ".vuu-theme[data-mode=\"light\"] {\n --salt-palette-navigate-primary-background: transparent;\n --salt-palette-navigate-primary-background-active: transparent;\n --salt-palette-navigate-primary-background-hover: var(--salt-color-gray-20);\n --salt-palette-navigate-secondary-background: transparent;\n --salt-palette-navigate-secondary-background-active: transparent;\n --salt-palette-navigate-secondary-background-hover: var(--salt-color-gray-30);\n --salt-palette-navigate-tertiary-background: transparent;\n --salt-palette-navigate-tertiary-background-active: transparent;\n --salt-palette-navigate-tertiary-background-hover: var(--salt-color-gray-20);\n --salt-palette-navigate-foreground-hover: var(--salt-color-blue-600);\n --salt-palette-navigate-foreground-active: var(--salt-color-blue-700);\n --salt-palette-navigate-foreground-visited: var(--salt-color-purple-800);\n --salt-palette-navigate-indicator-hover: var(--salt-color-gray-90);\n --salt-palette-navigate-indicator-active: var(--vuu-color-purple-10);\n --salt-palette-navigate-indicator-activeDisabled: var(--salt-color-orange-600-fade-border);\n}\n\n.vuu-theme[data-mode=\"dark\"] {\n --salt-palette-navigate-primary-background: transparent;\n --salt-palette-navigate-primary-background-active: transparent;\n --salt-palette-navigate-primary-background-hover: var(--salt-color-gray-700);\n --salt-palette-navigate-secondary-background: transparent;\n --salt-palette-navigate-secondary-background-active: transparent;\n --salt-palette-navigate-secondary-background-hover: var(--salt-color-gray-600);\n --salt-palette-navigate-tertiary-background: transparent;\n --salt-palette-navigate-tertiary-background-active: transparent;\n --salt-palette-navigate-tertiary-background-hover: var(--salt-color-gray-700);\n --salt-palette-navigate-foreground-hover: var(--salt-color-blue-200);\n --salt-palette-navigate-foreground-active: var(--salt-color-blue-300);\n --salt-palette-navigate-foreground-visited: var(--salt-color-purple-100);\n --salt-palette-navigate-indicator-hover: var(--salt-color-gray-90);\n --salt-palette-navigate-indicator-active: var(--vuu-color-pink-10);\n --salt-palette-navigate-indicator-activeDisabled: var(--salt-color-orange-400-fade-border);\n}\n", ".vuu-theme[data-mode=\"light\"] {\n --salt-palette-negative-foreground: var(--salt-color-red-700);\n}\n\n.vuu-theme[data-mode=\"dark\"] {\n --salt-palette-negative-foreground: var(--salt-color-red-300);\n}\n", ".vuu-theme[data-mode=\"light\"] {\n --salt-palette-neutral-primary-background: var(--salt-color-white);\n --salt-palette-neutral-primary-background-disabled: var(--salt-color-white-fade-background);\n --salt-palette-neutral-primary-background-readonly: var(--salt-color-white-fade-background-readonly);\n --salt-palette-neutral-primary-foreground: var(--vuu-color-gray-80);\n --salt-palette-neutral-primary-foreground-disabled: var(--salt-color-gray-900-fade-foreground);\n --salt-palette-neutral-primary-separator: var(--salt-color-black-fade-separatorOpacity-primary);\n --salt-palette-neutral-primary-border: var(--vuu-color-purple-10);\n --salt-palette-neutral-primary-border-disabled: var(--salt-color-gray-60-fade-border);\n --salt-palette-neutral-secondary-background: var(--vuu-color-gray-20);\n --salt-palette-neutral-secondary-background-disabled: var(--salt-color-gray-20-fade-background);\n --salt-palette-neutral-secondary-background-readonly: var(--salt-color-gray-20-fade-background-readonly);\n --salt-palette-neutral-secondary-border: var(--salt-color-gray-90);\n --salt-palette-neutral-secondary-border-disabled: var(--salt-color-gray-90-fade-border);\n --salt-palette-neutral-secondary-foreground: var(--salt-color-gray-200);\n --salt-palette-neutral-secondary-foreground-disabled: var(--salt-color-gray-200-fade-foreground);\n --salt-palette-neutral-backdrop: var(--salt-color-black-fade-backdrop);\n --salt-palette-neutral-secondary-separator: var(--salt-color-black-fade-separatorOpacity-secondary);\n --salt-palette-neutral-tertiary-background: transparent;\n --salt-palette-neutral-tertiary-background-disabled: transparent;\n --salt-palette-neutral-tertiary-border: transparent;\n --salt-palette-neutral-tertiary-border-disabled: transparent;\n --salt-palette-neutral-tertiary-separator: var(--vuu-color-gray-05);\n}\n\n.vuu-theme[data-mode=\"dark\"] {\n --salt-palette-neutral-primary-background: var(--salt-color-gray-800);\n --salt-palette-neutral-primary-background-disabled: var(--salt-color-gray-800-fade-background);\n --salt-palette-neutral-primary-background-readonly: var(--salt-color-gray-800-fade-background-readonly);\n --salt-palette-neutral-primary-border: var(--salt-color-gray-300);\n --salt-palette-neutral-primary-border-disabled: var(--salt-color-gray-300-fade-border);\n --salt-palette-neutral-primary-foreground: var(--salt-color-white);\n --salt-palette-neutral-primary-foreground-disabled: var(--salt-color-white-fade-foreground);\n --salt-palette-neutral-primary-separator: var(--salt-color-white-fade-separatorOpacity-primary);\n --salt-palette-neutral-secondary-background: var(--salt-color-gray-600);\n --salt-palette-neutral-secondary-background-disabled: var(--salt-color-gray-600-fade-background);\n --salt-palette-neutral-secondary-background-readonly: var(--salt-color-gray-600-fade-background-readonly);\n --salt-palette-neutral-secondary-border: var(--salt-color-gray-90);\n --salt-palette-neutral-secondary-border-disabled: var(--salt-color-gray-90-fade-border);\n --salt-palette-neutral-secondary-foreground: var(--salt-color-gray-70);\n --salt-palette-neutral-secondary-foreground-disabled: var(--salt-color-gray-70-fade-foreground);\n --salt-palette-neutral-backdrop: var(--salt-color-black-fade-backdrop);\n --salt-palette-neutral-secondary-separator: var(--salt-color-white-fade-separatorOpacity-secondary);\n --salt-palette-neutral-tertiary-background: transparent;\n --salt-palette-neutral-tertiary-background-disabled: transparent;\n --salt-palette-neutral-tertiary-border: transparent;\n --salt-palette-neutral-tertiary-border-disabled: transparent;\n --salt-palette-neutral-tertiary-separator: var(--salt-color-white-fade-separatorOpacity-tertiary);\n}\n", ".vuu-theme {\n --salt-palette-opacity-backdrop: var(--salt-opacity-70);\n --salt-palette-opacity-disabled: var(--salt-opacity-40);\n --salt-palette-opacity-background-readonly: var(--salt-opacity-0);\n --salt-palette-opacity-border-readonly: var(--salt-opacity-15);\n --salt-palette-opacity-primary-border: var(--salt-opacity-40);\n --salt-palette-opacity-secondary-border: var(--salt-opacity-25);\n --salt-palette-opacity-tertiary-border: var(--salt-opacity-15);\n}\n", ".vuu-theme[data-mode=\"light\"] {\n --salt-palette-positive-foreground: var(--salt-color-green-700);\n}\n\n.vuu-theme[data-mode=\"dark\"] {\n --salt-palette-positive-foreground: var(--salt-color-green-300);\n}\n", ".vuu-theme[data-mode=\"light\"] {\n --salt-palette-success-background: var(--salt-color-green-10);\n --salt-palette-success-background-selected: var(--salt-color-green-20);\n --salt-palette-success-border: var(--salt-color-green-500);\n --salt-palette-success-foreground: var(--salt-color-green-500);\n}\n\n.vuu-theme[data-mode=\"dark\"] {\n --salt-palette-success-background: var(--salt-color-green-900);\n --salt-palette-success-background-selected: var(--salt-color-green-900);\n --salt-palette-success-border: var(--salt-color-green-400);\n --salt-palette-success-foreground: var(--salt-color-green-400);\n}\n", ".vuu-theme[data-mode=\"light\"] {\n --salt-palette-track-background: var(--salt-color-gray-60);\n --salt-palette-track-background-disabled: var(--salt-color-gray-60-fade-background);\n --salt-palette-track-border: var(--salt-color-gray-90);\n --salt-palette-track-border-disabled: var(--salt-color-gray-90-fade-border);\n}\n\n.vuu-theme[data-mode=\"dark\"] {\n --salt-palette-track-background: var(--salt-color-gray-300);\n --salt-palette-track-background-disabled: var(--salt-color-gray-300-fade-background);\n --salt-palette-track-border: var(--salt-color-gray-90);\n --salt-palette-track-border-disabled: var(--salt-color-gray-90-fade-border);\n}\n", ".vuu-theme[data-mode=\"light\"] {\n --salt-palette-warning-background: var(--salt-color-orange-10);\n --salt-palette-warning-background-selected: var(--salt-color-orange-20);\n --salt-palette-warning-border: var(--salt-color-orange-700);\n --salt-palette-warning-foreground: var(--salt-color-orange-700);\n}\n\n.vuu-theme[data-mode=\"dark\"] {\n --salt-palette-warning-background: var(--salt-color-orange-900);\n --salt-palette-warning-background-selected: var(--salt-color-orange-900);\n --salt-palette-warning-border: var(--salt-color-orange-500);\n --salt-palette-warning-foreground: var(--salt-color-orange-500);\n}\n", ".vuu-density-high {\n --salt-accent-fontSize: 8px;\n --salt-accent-lineHeight: 11px;\n}\n.vuu-density-medium {\n --salt-accent-fontSize: 10px;\n --salt-accent-lineHeight: 13px;\n}\n.vuu-density-low {\n --salt-accent-fontSize: 12px;\n --salt-accent-lineHeight: 16px;\n}\n.vuu-density-touch {\n --salt-accent-fontSize: 14px;\n --salt-accent-lineHeight: 18px;\n}\n\n.vuu-theme {\n --salt-accent-background: var(--salt-palette-accent-background);\n --salt-accent-background-disabled: var(--salt-palette-accent-background-disabled);\n --salt-accent-borderColor: var(--salt-palette-accent-border);\n --salt-accent-borderColor-disabled: var(--salt-palette-accent-border-disabled);\n --salt-accent-foreground: var(--salt-palette-accent-foreground);\n --salt-accent-foreground-disabled: var(--salt-palette-accent-foreground-disabled);\n --salt-accent-fontWeight: var(--salt-typography-fontWeight-semiBold);\n}\n", ".vuu-theme {\n --salt-actionable-cursor-hover: pointer;\n --salt-actionable-cursor-active: pointer;\n --salt-actionable-cursor-disabled: not-allowed;\n\n --salt-actionable-letterSpacing: 0.6px;\n --salt-actionable-textAlign: center;\n --salt-actionable-textTransform: uppercase;\n\n /* Primary variant */\n --salt-actionable-primary-foreground: var(--salt-palette-interact-primary-foreground);\n --salt-actionable-primary-foreground-hover: var(--salt-palette-interact-primary-foreground-hover);\n --salt-actionable-primary-foreground-active: var(--salt-palette-interact-primary-foreground-active);\n --salt-actionable-primary-foreground-disabled: var(--salt-palette-interact-primary-foreground-disabled);\n --salt-actionable-primary-background: var(--salt-palette-interact-primary-background);\n --salt-actionable-primary-background-hover: var(--salt-palette-interact-primary-background-hover);\n --salt-actionable-primary-background-active: var(--salt-palette-interact-primary-background-active);\n --salt-actionable-primary-background-disabled: var(--salt-palette-interact-primary-background-disabled);\n --salt-actionable-primary-fontWeight: var(--salt-typography-fontWeight-bold);\n\n /* CTA variant */\n --salt-actionable-cta-foreground: var(--salt-palette-interact-cta-foreground);\n --salt-actionable-cta-foreground-hover: var(--salt-palette-interact-cta-foreground-hover);\n --salt-actionable-cta-foreground-active: var(--salt-palette-interact-cta-foreground-active);\n --salt-actionable-cta-foreground-disabled: var(--salt-palette-interact-cta-foreground-disabled);\n --salt-actionable-cta-background: var(--salt-palette-interact-cta-background);\n --salt-actionable-cta-background-hover: var(--salt-palette-interact-cta-background-hover);\n --salt-actionable-cta-background-active: var(--salt-palette-interact-cta-background-active);\n --salt-actionable-cta-background-disabled: var(--salt-palette-interact-cta-background-disabled);\n --salt-actionable-cta-fontWeight: var(--salt-typography-fontWeight-bold);\n\n /* Secondary variant */\n --salt-actionable-secondary-foreground: var(--salt-palette-interact-secondary-foreground);\n --salt-actionable-secondary-foreground-hover: var(--salt-palette-interact-secondary-foreground-hover);\n --salt-actionable-secondary-foreground-active: var(--salt-palette-interact-secondary-foreground-active);\n --salt-actionable-secondary-foreground-disabled: var(--salt-palette-interact-secondary-foreground-disabled);\n --salt-actionable-secondary-background: var(--salt-palette-interact-secondary-background);\n --salt-actionable-secondary-background-hover: var(--salt-palette-interact-secondary-background-hover);\n --salt-actionable-secondary-background-active: var(--salt-palette-interact-secondary-background-active);\n --salt-actionable-secondary-background-disabled: var(--salt-palette-interact-secondary-background-disabled);\n --salt-actionable-secondary-fontWeight: var(--salt-typography-fontWeight-semiBold);\n}\n", ".vuu-theme {\n --salt-container-borderStyle: solid;\n\n --salt-container-primary-background: var(--salt-palette-neutral-primary-background);\n --salt-container-primary-background-disabled: var(--salt-palette-neutral-primary-background-disabled);\n --salt-container-primary-borderColor: var(--salt-palette-neutral-primary-border);\n --salt-container-primary-borderColor-disabled: var(--salt-palette-neutral-primary-border-disabled);\n\n --salt-container-secondary-background: var(--salt-palette-neutral-secondary-background);\n --salt-container-secondary-background-disabled: var(--salt-palette-neutral-secondary-background-disabled);\n --salt-container-secondary-borderColor: var(--salt-palette-neutral-secondary-border);\n --salt-container-secondary-borderColor-disabled: var(--salt-palette-neutral-secondary-border-disabled);\n\n --salt-container-tertiary-background: var(--salt-palette-neutral-tertiary-background);\n --salt-container-tertiary-background-disabled: var(--salt-palette-neutral-tertiary-background-disabled);\n --salt-container-tertiary-borderColor: var(--salt-palette-neutral-tertiary-border);\n --salt-container-tertiary-borderColor-disabled: var(--salt-palette-neutral-tertiary-border-disabled);\n}\n", ".vuu-theme {\n --salt-draggable-horizontal-cursor-hover: row-resize;\n --salt-draggable-horizontal-cursor-active: row-resize;\n\n --salt-draggable-vertical-cursor-hover: col-resize;\n --salt-draggable-vertical-cursor-active: col-resize;\n\n --salt-draggable-grab-cursor-hover: grab;\n --salt-draggable-grab-cursor-active: grabbing;\n}\n", ".vuu-theme {\n --salt-target-background-hover: var(--salt-palette-interact-background-hover);\n\n --salt-target-borderColor-hover: var(--salt-palette-interact-border-hover);\n --salt-target-borderStyle: dashed;\n --salt-target-borderStyle-hover: solid;\n --salt-target-borderStyle-disabled: dashed;\n\n --salt-target-cursor-disabled: not-allowed;\n}\n", ".vuu-theme {\n --salt-editable-cursor-hover: text;\n --salt-editable-cursor-active: text;\n --salt-editable-cursor-disabled: not-allowed;\n --salt-editable-cursor-readonly: text;\n\n --salt-editable-borderStyle: solid;\n --salt-editable-borderStyle-hover: solid;\n --salt-editable-borderStyle-active: solid;\n --salt-editable-borderStyle-disabled: solid;\n --salt-editable-borderStyle-readonly: solid;\n --salt-editable-borderWidth-active: 2px;\n\n --salt-editable-borderColor: var(--salt-palette-interact-border);\n --salt-editable-borderColor-active: var(--salt-palette-interact-border-active);\n --salt-editable-borderColor-disabled: var(--salt-palette-interact-border-disabled);\n --salt-editable-borderColor-hover: var(--salt-palette-interact-border-hover);\n --salt-editable-borderColor-readonly: var(--salt-palette-interact-border-readonly);\n\n --salt-editable-primary-background: var(--salt-palette-neutral-primary-background);\n --salt-editable-primary-background-active: var(--salt-palette-neutral-primary-background);\n --salt-editable-primary-background-disabled: var(--salt-palette-neutral-primary-background-disabled);\n --salt-editable-primary-background-hover: var(--salt-palette-neutral-primary-background);\n --salt-editable-primary-background-readonly: var(--salt-palette-neutral-primary-background-readonly);\n\n --salt-editable-secondary-background: var(--salt-palette-neutral-secondary-background);\n --salt-editable-secondary-background-active: var(--salt-palette-neutral-secondary-background);\n --salt-editable-secondary-background-disabled: var(--salt-palette-neutral-secondary-background-disabled);\n --salt-editable-secondary-background-hover: var(--salt-palette-neutral-secondary-background);\n --salt-editable-secondary-background-readonly: var(--salt-palette-neutral-secondary-background-readonly);\n\n --salt-editable-help-fontStyle: italic;\n}\n", ".vuu-theme {\n --vuu-editable-borderColor-active: var(--editable-border-active, #6D18BD);\n}\n\n.saltInput-focused {\n border-color: var(--vuu-editable-borderColor-active) !important;\n}", ".vuu-theme {\n --salt-navigable-cursor-active: pointer;\n --salt-navigable-cursor-hover: pointer;\n --salt-navigable-cursor-disabled: not-allowed;\n --salt-navigable-cursor-edit: text;\n\n --salt-navigable-fontWeight: var(--salt-typography-fontWeight-regular);\n --salt-navigable-fontWeight-hover: var(--salt-typography-fontWeight-regular);\n --salt-navigable-fontWeight-active: var(--salt-typography-fontWeight-semiBold);\n --salt-navigable-fontWeight-edit: var(--salt-typography-fontWeight-regular);\n\n --salt-navigable-indicator-hover: var(--salt-palette-navigate-indicator-hover);\n --salt-navigable-indicator-active: var(--salt-palette-navigate-indicator-active);\n --salt-navigable-indicator-activeDisabled: var(--salt-palette-navigate-indicator-activeDisabled);\n\n --salt-navigable-primary-background: var(--salt-palette-navigate-primary-background);\n --salt-navigable-primary-background-hover: var(--salt-palette-navigate-primary-background-hover);\n --salt-navigable-primary-background-active: var(--salt-palette-navigate-primary-background-active);\n\n --salt-navigable-secondary-background: var(--salt-palette-navigate-secondary-background);\n --salt-navigable-secondary-background-hover: var(--salt-palette-navigate-secondary-background-hover);\n --salt-navigable-secondary-background-active: var(--salt-palette-navigate-secondary-background-active);\n\n --salt-navigable-tertiary-background: var(--salt-palette-navigate-tertiary-background);\n --salt-navigable-tertiary-background-hover: var(--salt-palette-navigate-tertiary-background-hover);\n --salt-navigable-tertiary-background-active: var(--salt-palette-navigate-tertiary-background-active);\n}\n", ".vuu-theme {\n --salt-overlayable-shadow-scroll: var(--salt-shadow-1);\n --salt-overlayable-shadow-borderRegion: var(--salt-shadow-2);\n --salt-overlayable-shadow: var(--salt-shadow-2);\n --salt-overlayable-shadow-hover: var(--salt-shadow-3);\n --salt-overlayable-shadow-popout: var(--salt-shadow-4);\n --salt-overlayable-shadow-drag: var(--salt-shadow-4);\n --salt-overlayable-shadow-modal: var(--salt-shadow-5);\n\n --salt-overlayable-background: var(--salt-palette-neutral-backdrop);\n}\n", ".vuu-theme {\n --salt-selectable-cursor-hover: pointer;\n --salt-selectable-cursor-selected: pointer;\n --salt-selectable-cursor-blurSelected: pointer;\n --salt-selectable-cursor-disabled: not-allowed;\n --salt-selectable-cursor-readonly: not-allowed;\n\n --salt-selectable-borderStyle: solid;\n --salt-selectable-borderStyle-hover: solid;\n --salt-selectable-borderStyle-selected: solid;\n --salt-selectable-borderStyle-blurSelected: solid;\n\n --salt-selectable-borderColor: var(--salt-palette-interact-border);\n --salt-selectable-borderColor-hover: var(--salt-palette-interact-border-hover);\n --salt-selectable-borderColor-selected: var(--salt-palette-interact-border-active);\n --salt-selectable-borderColor-selectedDisabled: var(--salt-palette-interact-border-activeDisabled);\n --salt-selectable-borderColor-disabled: var(--salt-palette-interact-border-disabled);\n --salt-selectable-borderColor-readonly: var(--salt-palette-interact-border-readonly);\n\n --salt-selectable-foreground: var(--salt-palette-interact-foreground);\n --salt-selectable-foreground-disabled: var(--salt-palette-interact-foreground-disabled);\n --salt-selectable-foreground-hover: var(--salt-palette-interact-foreground-hover);\n --salt-selectable-foreground-selected: var(--salt-palette-interact-foreground-active);\n --salt-selectable-foreground-selectedDisabled: var(--salt-palette-interact-foreground-activeDisabled);\n --salt-selectable-background: var(--salt-palette-interact-background);\n --salt-selectable-background-hover: var(--salt-palette-interact-background-hover);\n --salt-selectable-background-selected: var(--salt-palette-interact-background-active);\n --salt-selectable-background-blurSelected: var(--salt-palette-interact-background-blurSelected);\n --salt-selectable-background-disabled: var(--salt-palette-interact-background-disabled);\n --salt-selectable-background-selectedDisabled: var(--salt-palette-interact-background-activeDisabled);\n\n --salt-selectable-cta-foreground-hover: var(--salt-palette-interact-cta-foreground-hover);\n --salt-selectable-cta-foreground-selected: var(--salt-palette-interact-cta-foreground-active);\n --salt-selectable-cta-foreground-selectedDisabled: var(--salt-palette-interact-cta-foreground-activeDisabled);\n --salt-selectable-cta-background: var(--salt-palette-interact-background);\n --salt-selectable-cta-background-disabled: var(--salt-palette-interact-background-disabled);\n --salt-selectable-cta-background-hover: var(--salt-palette-interact-cta-background-hover);\n --salt-selectable-cta-background-selected: var(--salt-palette-interact-cta-background-active);\n --salt-selectable-cta-background-selectedDisabled: var(--salt-palette-interact-cta-background-activeDisabled);\n\n --salt-selectable-primary-foreground-hover: var(--salt-palette-interact-primary-foreground-hover);\n --salt-selectable-primary-foreground-selected: var(--salt-palette-interact-primary-foreground-active);\n --salt-selectable-primary-foreground-selectedDisabled: var(--salt-palette-interact-primary-foreground-activeDisabled);\n --salt-selectable-primary-background: var(--salt-palette-interact-background);\n --salt-selectable-primary-background-disabled: var(--salt-palette-interact-background-disabled);\n --salt-selectable-primary-background-hover: var(--salt-palette-interact-primary-background-hover);\n --salt-selectable-primary-background-selected: var(--salt-palette-interact-primary-background-active);\n --salt-selectable-primary-background-selectedDisabled: var(--salt-palette-interact-primary-background-activeDisabled);\n\n --salt-selectable-secondary-foreground-hover: var(--salt-palette-interact-secondary-foreground-hover);\n --salt-selectable-secondary-foreground-selected: var(--salt-palette-interact-secondary-foreground-active);\n --salt-selectable-secondary-foreground-selectedDisabled: var(--salt-palette-interact-secondary-foreground-activeDisabled);\n --salt-selectable-secondary-background: var(--salt-palette-interact-background);\n --salt-selectable-secondary-background-disabled: var(--salt-palette-interact-background-disabled);\n --salt-selectable-secondary-background-hover: var(--salt-palette-interact-secondary-background-hover);\n --salt-selectable-secondary-background-selected: var(--salt-palette-interact-secondary-background-active);\n --salt-selectable-secondary-background-selectedDisabled: var(--salt-palette-interact-secondary-background-activeDisabled);\n}\n", ".vuu-theme {\n --salt-separable-borderStyle: solid;\n\n --salt-separable-primary-borderColor: var(--salt-palette-neutral-primary-separator);\n --salt-separable-secondary-borderColor: var(--salt-palette-neutral-secondary-separator);\n --salt-separable-tertiary-borderColor: var(--salt-palette-neutral-tertiary-separator);\n}\n", ".vuu-theme {\n --salt-status-info-foreground: var(--salt-palette-info-foreground);\n --salt-status-success-foreground: var(--salt-palette-success-foreground);\n --salt-status-warning-foreground: var(--salt-palette-warning-foreground);\n --salt-status-error-foreground: var(--salt-palette-error-foreground);\n --salt-status-static-foreground: var(--salt-palette-neutral-secondary-foreground);\n --salt-status-negative-foreground: var(--salt-palette-negative-foreground);\n --salt-status-positive-foreground: var(--salt-palette-positive-foreground);\n\n --salt-status-info-borderColor: var(--salt-palette-info-border);\n --salt-status-success-borderColor: var(--salt-palette-success-border);\n --salt-status-warning-borderColor: var(--salt-palette-warning-border);\n --salt-status-error-borderColor: var(--salt-palette-error-border);\n\n --salt-status-info-background: var(--salt-palette-info-background);\n --salt-status-success-background: var(--salt-palette-success-background);\n --salt-status-warning-background: var(--salt-palette-warning-background);\n --salt-status-error-background: var(--salt-palette-error-background);\n\n --salt-status-success-background-selected: var(--salt-palette-success-background-selected);\n --salt-status-warning-background-selected: var(--salt-palette-warning-background-selected);\n --salt-status-error-background-selected: var(--salt-palette-error-background-selected);\n}\n", ".vuu-theme {\n --salt-taggable-cursor-hover: pointer;\n --salt-taggable-cursor-active: pointer;\n --salt-taggable-cursor-disabled: not-allowed;\n\n --salt-taggable-background: var(--salt-palette-interact-primary-background);\n --salt-taggable-background-hover: var(--salt-palette-interact-primary-background-hover);\n --salt-taggable-background-active: var(--salt-palette-interact-primary-background-active);\n --salt-taggable-background-disabled: var(--salt-palette-interact-primary-background-disabled);\n\n --salt-taggable-foreground: var(--salt-palette-interact-primary-foreground);\n --salt-taggable-foreground-hover: var(--salt-palette-interact-primary-foreground-hover);\n --salt-taggable-foreground-active: var(--salt-palette-interact-primary-foreground-active);\n --salt-taggable-foreground-disabled: var(--salt-palette-interact-primary-foreground-disabled);\n}\n", ".vuu-theme {\n /* Misc */\n --salt-text-letterSpacing: 0;\n --salt-text-textAlign: left;\n --salt-text-textAlign-embedded: center;\n --salt-text-textDecoration: none;\n --salt-text-textTransform: none;\n\n /* Body text (should be used as default) */\n --salt-text-fontFamily: var(--salt-typography-fontFamily);\n --salt-text-fontWeight: var(--salt-typography-fontWeight-regular);\n --salt-text-fontWeight-small: var(--salt-typography-fontWeight-light);\n --salt-text-fontWeight-strong: var(--salt-typography-fontWeight-semiBold);\n\n /* H1 */\n --salt-text-h1-fontFamily: var(--salt-typography-fontFamily);\n --salt-text-h1-fontWeight: var(--salt-typography-fontWeight-bold);\n --salt-text-h1-fontWeight-small: var(--salt-typography-fontWeight-medium);\n --salt-text-h1-fontWeight-strong: var(--salt-typography-fontWeight-extraBold);\n\n /* H2 */\n --salt-text-h2-fontFamily: var(--salt-typography-fontFamily);\n --salt-text-h2-fontWeight: var(--salt-typography-fontWeight-semiBold);\n --salt-text-h2-fontWeight-small: var(--salt-typography-fontWeight-regular);\n --salt-text-h2-fontWeight-strong: var(--salt-typography-fontWeight-bold);\n\n /* H3 */\n --salt-text-h3-fontFamily: var(--salt-typography-fontFamily);\n --salt-text-h3-fontWeight: var(--salt-typography-fontWeight-semiBold);\n --salt-text-h3-fontWeight-small: var(--salt-typography-fontWeight-regular);\n --salt-text-h3-fontWeight-strong: var(--salt-typography-fontWeight-bold);\n\n /* H4 */\n --salt-text-h4-fontFamily: var(--salt-typography-fontFamily);\n --salt-text-h4-fontWeight: var(--salt-typography-fontWeight-semiBold);\n --salt-text-h4-fontWeight-small: var(--salt-typography-fontWeight-regular);\n --salt-text-h4-fontWeight-strong: var(--salt-typography-fontWeight-bold);\n\n /* Label */\n --salt-text-label-fontFamily: var(--salt-typography-fontFamily);\n --salt-text-label-fontWeight: var(--salt-typography-fontWeight-regular);\n --salt-text-label-fontWeight-small: var(--salt-typography-fontWeight-light);\n --salt-text-label-fontWeight-strong: var(--salt-typography-fontWeight-semiBold);\n\n /* Display text */\n --salt-text-display1-fontFamily: var(--salt-typography-fontFamily);\n --salt-text-display1-fontWeight: var(--salt-typography-fontWeight-semiBold);\n --salt-text-display1-fontWeight-strong: var(--salt-typography-fontWeight-bold);\n --salt-text-display1-fontWeight-small: var(--salt-typography-fontWeight-regular);\n\n --salt-text-display2-fontFamily: var(--salt-typography-fontFamily);\n --salt-text-display2-fontWeight: var(--salt-typography-fontWeight-semiBold);\n --salt-text-display2-fontWeight-strong: var(--salt-typography-fontWeight-bold);\n --salt-text-display2-fontWeight-small: var(--salt-typography-fontWeight-regular);\n\n --salt-text-display3-fontFamily: var(--salt-typography-fontFamily);\n --salt-text-display3-fontWeight: var(--salt-typography-fontWeight-semiBold);\n --salt-text-display3-fontWeight-strong: var(--salt-typography-fontWeight-bold);\n --salt-text-display3-fontWeight-small: var(--salt-typography-fontWeight-regular);\n\n /* Colors */\n --salt-text-background-selected: var(--salt-palette-interact-background-active);\n\n --salt-text-primary-foreground: var(--salt-palette-neutral-primary-foreground);\n --salt-text-primary-foreground-disabled: var(--salt-palette-neutral-primary-foreground-disabled);\n --salt-text-secondary-foreground: var(--salt-palette-neutral-secondary-foreground);\n --salt-text-secondary-foreground-disabled: var(--salt-palette-neutral-secondary-foreground-disabled);\n\n /* Link */\n --salt-text-link-foreground-hover: var(--salt-palette-navigate-foreground-hover);\n --salt-text-link-foreground-active: var(--salt-palette-navigate-foreground-active);\n --salt-text-link-foreground-visited: var(--salt-palette-navigate-foreground-visited);\n --salt-text-link-textDecoration: underline;\n --salt-text-link-textDecoration-hover: none;\n --salt-text-link-textDecoration-selected: underline;\n\n /* Code */\n --salt-text-code-fontFamily: var(--salt-typography-fontFamily-code);\n}\n\n/* Sizes by density */\n.vuu-density-touch {\n --salt-text-h1-fontSize: 42px;\n --salt-text-h1-lineHeight: 54px;\n\n --salt-text-h2-fontSize: 32px;\n --salt-text-h2-lineHeight: 42px;\n\n --salt-text-h3-fontSize: 24px;\n --salt-text-h3-lineHeight: 32px;\n\n --salt-text-h4-fontSize: 16px;\n --salt-text-h4-lineHeight: 20px;\n\n --salt-text-label-fontSize: 14px;\n --salt-text-label-lineHeight: 18px;\n\n --salt-text-fontSize: 16px;\n --salt-text-lineHeight: 20px;\n --salt-text-minHeight: 20px;\n\n --salt-text-display1-fontSize: 84px;\n --salt-text-display1-lineHeight: 109px;\n\n --salt-text-display2-fontSize: 58px;\n --salt-text-display2-lineHeight: 76px;\n\n --salt-text-display3-fontSize: 42px;\n --salt-text-display3-lineHeight: 54px;\n}\n\n.vuu-density-low {\n --salt-text-h1-fontSize: 32px;\n --salt-text-h1-lineHeight: 42px;\n\n --salt-text-h2-fontSize: 24px;\n --salt-text-h2-lineHeight: 32px;\n\n --salt-text-h3-fontSize: 18px;\n --salt-text-h3-lineHeight: 24px;\n\n --salt-text-h4-fontSize: 14px;\n --salt-text-h4-lineHeight: 18px;\n\n --salt-text-label-fontSize: 12px;\n --salt-text-label-lineHeight: 16px;\n\n --salt-text-fontSize: 14px;\n --salt-text-lineHeight: 18px;\n --salt-text-minHeight: 18px;\n\n --salt-text-display1-fontSize: 68px;\n --salt-text-display1-lineHeight: 88px;\n\n --salt-text-display2-fontSize: 46px;\n --salt-text-display2-lineHeight: 60px;\n\n --salt-text-display3-fontSize: 32px;\n --salt-text-display3-lineHeight: 42px;\n}\n\n.vuu-density-medium {\n --salt-text-h1-fontSize: 24px;\n --salt-text-h1-lineHeight: 32px;\n\n --salt-text-h2-fontSize: 18px;\n --salt-text-h2-lineHeight: 24px;\n\n --salt-text-h3-fontSize: 14px;\n --salt-text-h3-lineHeight: 18px;\n\n --salt-text-h4-fontSize: 12px;\n --salt-text-h4-lineHeight: 16px;\n\n --salt-text-label-fontSize: 11px;\n --salt-text-label-lineHeight: 14px;\n\n --salt-text-fontSize: 12px;\n --salt-text-lineHeight: 16px;\n --salt-text-minHeight: 16px;\n\n --salt-text-display1-fontSize: 54px;\n --salt-text-display1-lineHeight: 70px;\n\n --salt-text-display2-fontSize: 36px;\n --salt-text-display2-lineHeight: 47px;\n\n --salt-text-display3-fontSize: 24px;\n --salt-text-display3-lineHeight: 32px;\n}\n\n.vuu-density-high {\n --salt-text-h1-fontSize: 18px;\n --salt-text-h1-lineHeight: 24px;\n\n --salt-text-h2-fontSize: 14px;\n --salt-text-h2-lineHeight: 18px;\n\n --salt-text-h3-fontSize: 12px;\n --salt-text-h3-lineHeight: 16px;\n\n --salt-text-h4-fontSize: 11px;\n --salt-text-h4-lineHeight: 14px;\n\n --salt-text-label-fontSize: 10px;\n --salt-text-label-lineHeight: 13px;\n\n --salt-text-fontSize: 12px;\n --salt-text-lineHeight: 14px;\n --salt-text-minHeight: 14px;\n\n --salt-text-display1-fontSize: 42px;\n --salt-text-display1-lineHeight: 54px;\n\n --salt-text-display2-fontSize: 28px;\n --salt-text-display2-lineHeight: 36px;\n\n --salt-text-display3-fontSize: 18px;\n --salt-text-display3-lineHeight: 24px;\n}\n", ".vuu-theme {\n --salt-track-borderStyle: solid;\n --salt-track-borderStyle-active: solid;\n --salt-track-borderStyle-complete: solid;\n --salt-track-borderStyle-incomplete: dotted;\n\n --salt-track-borderWidth: 2px;\n --salt-track-borderWidth-active: 2px;\n --salt-track-borderWidth-complete: 2px;\n --salt-track-borderWidth-incomplete: 2px;\n\n --salt-track-fontWeight: var(--salt-typography-fontWeight-semiBold);\n --salt-track-textAlign: center;\n\n --salt-track-background: var(--salt-palette-track-background);\n --salt-track-background-disabled: var(--salt-palette-track-background-disabled);\n --salt-track-borderColor: var(--salt-palette-track-border);\n --salt-track-borderColor-disabled: var(--salt-palette-track-border-disabled);\n}\n", ".vuu-theme {\n /* Differential */\n --salt-differential-positive-foreground: var(--salt-palette-positive-foreground);\n --salt-differential-negative-foreground: var(--salt-palette-negative-foreground);\n\n /* Editable */\n --salt-editable-tertiary-background: var(--salt-palette-neutral-tertiary-background);\n --salt-editable-tertiary-background-active: var(--salt-palette-neutral-tertiary-background);\n --salt-editable-tertiary-background-disabled: var(--salt-palette-neutral-tertiary-background-disabled);\n --salt-editable-tertiary-background-hover: var(--salt-palette-neutral-tertiary-background);\n --salt-editable-tertiary-background-readonly: var(--salt-palette-neutral-tertiary-background-readonly);\n\n /* Measured */\n --salt-measured-borderStyle: solid;\n --salt-measured-borderStyle-active: solid;\n --salt-measured-borderStyle-complete: solid;\n --salt-measured-borderStyle-incomplete: dotted;\n --salt-measured-borderWidth: 2px;\n --salt-measured-borderWidth-active: 2px;\n --salt-measured-borderWidth-complete: 2px;\n --salt-measured-borderWidth-incomplete: 2px;\n\n --salt-measured-fontWeight: var(--salt-typography-fontWeight-semiBold);\n --salt-measured-textAlign: center;\n\n --salt-measured-background: var(--salt-palette-measured-background);\n --salt-measured-background-disabled: var(--salt-palette-measured-background-disabled);\n --salt-measured-borderColor: var(--salt-palette-measured-border);\n --salt-measured-borderColor-disabled: var(--salt-palette-measured-border-disabled);\n --salt-measured-fill: var(--salt-palette-measured-fill);\n --salt-measured-fill-disabled: var(--salt-palette-measured-fill-disabled);\n --salt-measured-foreground: var(--salt-palette-measured-foreground);\n --salt-measured-foreground-hover: var(--salt-palette-measured-foreground-active);\n --salt-measured-foreground-active: var(--salt-palette-measured-foreground-active);\n --salt-measured-foreground-undo: var(--salt-palette-measured-foreground-active);\n --salt-measured-foreground-activeDisabled: var(--salt-palette-measured-foreground-activeDisabled);\n --salt-measured-foreground-disabled: var(--salt-palette-measured-foreground-disabled);\n\n /* Overlayable */\n --salt-overlayable-shadow-scroll-color: var(--salt-shadow-1-color);\n\n /* Selectable */\n --salt-selectable-foreground-partial: var(--salt-palette-interact-foreground-partial);\n --salt-selectable-foreground-partialDisabled: var(--salt-palette-interact-foreground-partialDisabled);\n\n --salt-selectable-cta-foreground: var(--salt-palette-interact-foreground);\n --salt-selectable-cta-foreground-disabled: var(--salt-palette-interact-foreground-disabled);\n --salt-selectable-primary-foreground: var(--salt-palette-interact-foreground);\n --salt-selectable-primary-foreground-disabled: var(--salt-palette-interact-foreground-disabled);\n --salt-selectable-secondary-foreground: var(--salt-palette-interact-foreground);\n --salt-selectable-secondary-foreground-disabled: var(--salt-palette-interact-foreground-disabled);\n\n /* Status */\n --salt-status-info-background-emphasize: var(--salt-status-info-background);\n --salt-status-success-background-emphasize: var(--salt-status-success-background);\n --salt-status-warning-background-emphasize: var(--salt-status-warning-background);\n --salt-status-error-background-emphasize: var(--salt-status-error-background);\n\n --salt-status-info-foreground-disabled: var(--salt-palette-info-foreground-disabled);\n --salt-status-success-foreground-disabled: var(--salt-palette-success-foreground-disabled);\n --salt-status-warning-foreground-disabled: var(--salt-palette-warning-foreground-disabled);\n --salt-status-error-foreground-disabled: var(--salt-palette-error-foreground-disabled);\n --salt-status-static-foreground-disabled: var(--salt-palette-neutral-secondary-foreground-disabled);\n --salt-status-negative-foreground-disabled: var(--salt-palette-negative-foreground-disabled);\n --salt-status-positive-foreground-disabled: var(--salt-palette-positive-foreground-disabled);\n\n --salt-status-info-borderColor-disabled: var(--salt-palette-info-border-disabled);\n --salt-status-success-borderColor-disabled: var(--salt-palette-success-border-disabled);\n --salt-status-warning-borderColor-disabled: var(--salt-palette-warning-border-disabled);\n --salt-status-error-borderColor-disabled: var(--salt-palette-error-border-disabled);\n}\n", ".vuu-theme {\n --salt-color-orange-500-fade-foreground: rgba(234, 115, 25, var(--salt-palette-opacity-foreground));\n --salt-color-orange-700-fade-foreground: rgba(214, 85, 19, var(--salt-palette-opacity-foreground));\n --salt-color-orange-400-fade-background: rgba(238, 133, 43, var(--salt-palette-opacity-background));\n --salt-color-orange-600-fade-background: rgba(224, 101, 25, var(--salt-palette-opacity-background));\n --salt-color-blue-300-fade-fill: rgba(51, 141, 205, var(--salt-palette-opacity-fill));\n --salt-color-blue-500-fade-fill: rgba(38, 112, 169, var(--salt-palette-opacity-fill));\n}\n", "/*\n* **Deprecated:** Use duration instead\n*/\n.vuu-theme {\n /* Delay */\n --salt-delay-instant: 100ms;\n --salt-delay-perceptible: 300ms;\n --salt-delay-notable: 1000ms;\n --salt-delay-cutoff: 10000ms;\n\n /* Icon */\n --salt-size-icon-base: var(--salt-icon-size-base);\n\n /* Opacity */\n --salt-opacity-1: 0.15;\n --salt-opacity-2: 0.25;\n --salt-opacity-3: 0.4;\n --salt-opacity-4: 0.7;\n}\n\n.vuu-density-touch,\n.vuu-density-low,\n.vuu-density-medium,\n.vuu-density-high {\n /* Size */\n --salt-size-selection: var(--salt-size-selectable);\n --salt-size-brandBar: 4px; /* Use --salt-size-accent */\n --salt-size-graphic-small: 12px;\n --salt-size-graphic-medium: 24px;\n --salt-size-graphic-large: 48px;\n --salt-size-divider-height: var(--salt-size-separator-height);\n --salt-size-divider-strokeWidth: var(--salt-size-separator-strokeWidth);\n\n --salt-size-detail: var(--salt-size-compact);\n}\n", "/*\n* **Deprecated:**\n* Delete below on breaking change\n*/\n\n.vuu-theme {\n --salt-palette-error-background-emphasize: var(--salt-palette-error-background);\n --salt-palette-warning-background-emphasize: var(--salt-palette-warning-background);\n --salt-palette-success-background-emphasize: var(--salt-palette-success-background);\n --salt-palette-info-background-emphasize: var(--salt-palette-info-background);\n\n --salt-palette-opacity-fill: var(--salt-palette-opacity-disabled);\n --salt-palette-opacity-stroke: var(--salt-palette-opacity-disabled);\n --salt-palette-opacity-background: var(--salt-palette-opacity-disabled);\n --salt-palette-opacity-border: var(--salt-palette-opacity-disabled);\n --salt-palette-opacity-foreground: var(--salt-palette-opacity-disabled);\n}\n\n.vuu-theme[data-mode=\"light\"] {\n /* Interact */\n --salt-palette-interact-foreground-partial: var(--salt-color-blue-600);\n --salt-palette-interact-foreground-partialDisabled: var(--salt-color-blue-600-fade-foreground);\n\n /* Measure */\n --salt-palette-measured-fill: var(--salt-color-blue-500);\n --salt-palette-measured-fill-disabled: var(--salt-color-blue-500-fade-fill);\n --salt-palette-measured-foreground: var(--salt-color-gray-90);\n --salt-palette-measured-foreground-active: var(--salt-color-blue-500);\n --salt-palette-measured-foreground-disabled: var(--salt-color-gray-90-fade-foreground);\n --salt-palette-measured-foreground-activeDisabled: var(--salt-color-blue-500-fade-fill);\n --salt-palette-measured-background: var(--salt-color-gray-60);\n --salt-palette-measured-background-disabled: var(--salt-color-gray-60-fade-background);\n --salt-palette-measured-border: var(--salt-color-gray-90);\n --salt-palette-measured-border-disabled: var(--salt-color-gray-90-fade-border);\n\n /* Neutral */\n --salt-palette-neutral-tertiary-background-readonly: transparent;\n\n /* Status */\n --salt-palette-error-foreground-disabled: var(--salt-color-red-500-fade-foreground);\n --salt-palette-error-border-disabled: var(--salt-color-red-500-fade-border);\n\n --salt-palette-info-border-disabled: var(--salt-color-blue-500-fade-border);\n --salt-palette-info-foreground-disabled: var(--salt-color-blue-500-fade-foreground);\n\n --salt-palette-negative-foreground-disabled: var(--salt-color-red-700-fade-foreground);\n\n --salt-palette-positive-foreground-disabled: var(--salt-color-green-700-fade-foreground);\n\n --salt-palette-success-border-disabled: var(--salt-color-green-500-fade-border);\n --salt-palette-success-foreground-disabled: var(--salt-color-green-500-fade-foreground);\n\n --salt-palette-warning-foreground-disabled: var(--salt-color-orange-700-fade-foreground);\n --salt-palette-warning-border-disabled: var(--salt-color-orange-700-fade-border);\n}\n\n.vuu-theme[data-mode=\"dark\"] {\n /* Interact */\n --salt-palette-interact-foreground-partial: var(--salt-color-blue-100);\n --salt-palette-interact-foreground-partialDisabled: var(--salt-color-blue-100-fade-foreground);\n\n /* Measure */\n --salt-palette-measured-fill: var(--salt-color-blue-300);\n --salt-palette-measured-fill-disabled: var(--salt-color-blue-300-fade-fill);\n --salt-palette-measured-foreground: var(--salt-color-gray-90);\n --salt-palette-measured-foreground-active: var(--salt-color-blue-300);\n --salt-palette-measured-foreground-disabled: var(--salt-color-gray-90-fade-foreground);\n --salt-palette-measured-foreground-activeDisabled: var(--salt-color-blue-300-fade-fill);\n --salt-palette-measured-background: var(--salt-color-gray-300);\n --salt-palette-measured-background-disabled: var(--salt-color-gray-300-fade-background);\n --salt-palette-measured-border: var(--salt-color-gray-90);\n --salt-palette-measured-border-disabled: var(--salt-color-gray-90-fade-border);\n\n /* Neutral */\n --salt-palette-neutral-tertiary-background-readonly: transparent;\n\n /* Status */\n --salt-palette-error-foreground-disabled: var(--salt-color-red-500-fade-foreground);\n --salt-palette-error-border-disabled: var(--salt-color-red-500-fade-border);\n\n --salt-palette-info-border-disabled: var(--salt-color-blue-500-fade-border);\n --salt-palette-info-foreground-disabled: var(--salt-color-blue-500-fade-foreground);\n\n --salt-palette-negative-foreground-disabled: var(--salt-color-red-300-fade-foreground);\n\n --salt-palette-positive-foreground-disabled: var(--salt-color-green-300-fade-foreground);\n\n --salt-palette-success-border-disabled: var(--salt-color-green-400-fade-border);\n --salt-palette-success-foreground-disabled: var(--salt-color-green-400-fade-foreground);\n\n --salt-palette-warning-foreground-disabled: var(--salt-color-orange-500-fade-foreground);\n --salt-palette-warning-border-disabled: var(--salt-color-orange-500-fade-border);\n}\n", ".saltButton {\n white-space: nowrap;;\n}\n\n.saltButton-primary {\n --saltButton-borderColor: var(--salt-actionable-primary-foreground);\n --saltButton-borderWidth: 1px;\n --saltButton-borderRadius: 6px;\n --saltButton-borderStyle: solid;\n --vuu-icon-color: var(--saltIcon-color);\n}\n\n.saltButton-primary:hover {\n --saltButton-borderColor: var(--salt-actionable-primary-background-hover)\n}", ".saltCheckbox {\n --vuu-icon-size: 12px;\n --vuu-icon-left: -1px;\n --vuu-icon-top: -1px;\n}\n\n.saltCheckboxIcon {\n border-radius: 3px;\n height: 12px;\n width: 12px;\n}\n\n.saltCheckboxIcon-checked {\n background-color: var(--vuuCheckboxIcon-background-checked, var(--salt-selectable-background-selected));\n}\n\n\n.saltCheckboxIcon-checked.saltCheckboxIcon-disabled, \n.saltCheckbox:hover .saltCheckboxIcon-checked.saltCheckboxIcon-disabled {\n background-color: var(--salt-selectable-background-disabled);\n border-color: transparent;;\n}\n\n\n.saltCheckboxIcon-checked:after {\n content: \"\";\n background-color: white;\n left: var(--vuu-icon-left, auto);\n height: var(--vuu-icon-height, var(--vuu-icon-size, 12px));\n -webkit-mask: var(--vuu-svg-tick) center center/var(--vuu-icon-size) var(--vuu-icon-size);\n mask: var(--vuu-icon-svg) center center/var(--vuu-icon-size) var(--vuu-icon-size);\n mask-repeat: no-repeat;\n -webkit-mask-repeat: no-repeat;\n position: absolute;\n top: var(--vuu-icon-top, auto);\n width: var(--vuu-icon-width, var(--vuu-icon-size, 12px));\n}", ".saltIcon {\n display: none;\n} ", ".saltInput-activationIndicator {\n display: none;\n}\n\n.saltInput-primary {\n --saltInput-height: 24px;\n border: solid 1px var(--input-borderColor, var(--salt-editable-borderColor));\n border-radius: 6px;\n}\n\n.saltInput-focused:hover, \n.saltInput-focused {\n --input-borderColor: var(--vuu-color-purple-10);\n}", ".vuu-theme .vuuSplitter {\n --splitter-background: var(--vuu-color-gray-05);\n --splitter-size: 9px;\n --splitter-borderColor: white;\n --splitter-borderStyle: none solid none solid;\n --splitter-borderWidth: 4px;\n}\n\n.vuu-theme .vuuSplitter-column {\n --splitter-borderStyle: solid none solid none;\n}", ".saltSwitch {\n --vuu-icon-left: -1px;\n\n}\n\n.saltSwitch-track,\n.saltSwitch-track:hover {\n background-color: var(--vuu-color-gray-45);\n border: none;\n border-radius: 4px;\n height: 14px;\n padding: 0 2px;\n width: 26px;\n}\n\n.saltSwitch-thumb {\n background-color: var(--vuu-color-white);\n border: none;\n border-radius: 3px;\n height: 10px;\n margin:0;\n width: 10px;\n}\n\n.saltSwitch-checked .saltSwitch-track {\n background-color: var(--salt-selectable-background-selected);\n}\n\n.saltSwitch-checked .saltSwitch-thumb,\n.saltSwitch-checked:hover .saltSwitch-thumb {\n background-color: white;\n transform: translateX(calc(100% + 2px));\n}\n\n\n.saltSwitch-checked .saltSwitch-thumb:after {\n background-color: var(--vuu-color-purple-10);\n content: \"\";\n left: var(--vuu-icon-left, auto);\n height: var(--vuu-icon-height, var(--vuu-icon-size, 12px));\n -webkit-mask: var(--vuu-svg-tick) center center/var(--vuu-icon-size) var(--vuu-icon-size);\n mask: var(--vuu-icon-svg) center center/var(--vuu-icon-size) var(--vuu-icon-size);\n mask-repeat: no-repeat;\n -webkit-mask-repeat: no-repeat;\n position: absolute;\n top: var(--vuu-icon-top, auto);\n width: var(--vuu-icon-width, var(--vuu-icon-size, 12px));\n\n}", ".saltToggleButtonGroup {\n border-radius: 6px;\n gap: 0;\n padding: 0;\n}\n\n.saltToggleButtonGroup-horizontal .saltToggleButton {\n height: 24px;\n}\n\n.vuuIconToggleButton {\n --vuu-icon-size: var(--vuuIconToggleButton-iconSize, 48px);\n width: 48px;\n}\n\n.vuuIconToggleButton:first-child {\n border-radius: 4px 0 0 4px;\n}\n.vuuIconToggleButton:last-child {\n border-radius: 0 4px 4px 0;\n}"], + "mappings": "AACA,WACE,wBACA,kBACA,gBACA,kBACA,kBACA,y45BACA,8KAEF,WACE,wBACA,kBACA,gBACA,kBACA,kBACA,y45BACA,8KAEF,WACE,wBACA,kBACA,gBACA,kBACA,kBACA,y45BACA,8KAGF,WACE,wBACA,kBACA,gBACA,kBACA,kBACA,y45BACA,8KAGA,WACE,wBACA,kBACA,gBACA,kBACA,kBACA,y45BACA,8KAGF,WACE,wBACA,kBACA,gBACA,kBACA,kBACA,y45BACA,8KCvDH,WACC,0CACA,8CACA,oCACA,8CACA,wCAGF,YACE,gDACA,+CAGF,4BACE,mBAGF,2BACE,kBAKF,mBAGE,sBAGF,qBACE,kBACA,WACA,UAjCF,sBAoCE,gBACA,mBACA,mBACA,eCvCF,0EAIE,kCACA,gCACA,gCACA,8BACA,uCACA,kCACA,+BACA,0CAGA,iHACA,mHACA,qHACA,uHAEA,wHACA,0HACA,4HACA,8HAGA,iHACA,uHACA,qHACA,2FAIF,2BAEI,4CACA,+DAGA,0CACA,2DAGJ,4BAEI,0CACA,6DAGA,4CACA,6DAGJ,4BAEI,4CACA,yEAGA,0CACA,0DAGJ,6BAEI,0CACA,4DAGA,4CACA,uEAGJ,6BAEI,4CACA,8DAGA,0CACA,0DAGJ,8BAEI,0CACA,4DAGA,4CACA,4DAGJ,8BAEI,4CACA,0EAGA,0CACA,2DAGJ,+BAEI,0CACA,6DAGA,4CACA,wEAIJ,2BAEI,kCACA,4CACA,sDAIA,0CACA,kDAGJ,8BAEI,iCACA,4CACA,sDAIA,0CACA,kDAGJ,6BAEI,+CAIA,2CAIJ,4BAEI,6CAGA,6CCxJJ,WAEE,sBAEA,qCACA,yBACA,yBAGA,wCAGA,uCACA,0EAEA,wCAGA,wCACA,wCACA,wCACA,yCACA,wCACA,wCACA,wCACA,wCACA,wCACA,wCACA,uCACA,qCAEF,wCACA,uCACA,oDAEA,qCAEE,yCAKA,uCACA,iCAEA,wCACA,wCACA,wCACA,wCACA,wCACA,yCACA,wCACA,uCACA,uCACA,uCACA,uCACA,uCACA,sCACA,sCAEA,2CACA,2CACA,2CACA,2CACA,0CACA,2CACA,2CACA,2CACA,2CACA,2CACA,2CACA,0CACA,0CACA,yCAEA,0CACA,0CACA,0CACA,0CACA,0CACA,0CACA,0CACA,yCACA,yCACA,yCACA,yCACA,wCACA,uCACA,wCAEA,yCACA,yCACA,yCACA,yCACA,yCACA,0CACA,yCACA,yCACA,yCACA,wCACA,yCACA,uCACA,sCACA,sCAEA,yCACA,yCACA,yCACA,yCACA,yCACA,0CACA,yCACA,yCACA,yCACA,yCACA,wCACA,uCACA,uCACA,uCAEA,2CACA,2CACA,2CACA,2CACA,2CACA,4CACA,4CACA,4CACA,2CACA,2CACA,2CACA,2CACA,0CACA,yCAEA,yCACA,yCACA,yCACA,yCACA,yCACA,yCACA,yCACA,yCACA,yCACA,0CACA,yCACA,uCACA,uCACA,uCACA,uCACA,uCACA,uCACA,uCCxJF,WACE,6BACA,iCACA,4BACA,4BCJF,WACE,iGACA,gGACA,+FACA,gGACA,gGACA,gGACA,8FACA,gGACA,gGACA,gGACA,+FACA,8FACA,8FACA,8FACA,8FAEA,4FACA,4FACA,4FACA,4FACA,0FACA,4FACA,4FACA,8FACA,8FACA,8FACA,6FACA,0FAEA,4GACA,4GAEA,gGACA,gGACA,+FACA,8FACA,gGACA,gGACA,gGACA,gGACA,8FACA,8FACA,8FACA,8FAEA,kHACA,oHACA,kHACA,kHAEA,yFAEA,2FACA,yFAEA,kHACA,sHACA,oHACA,4GACA,gHACA,8GC7DF,mBACE,4BACA,wCAGF,iBACE,4BACA,wCAGF,oBACE,4BACA,uCAGF,kBACE,4BACA,uCCjBF,WACE,oBACA,sBACA,uBACA,uBACA,sBACA,sBCNF,4BACE,yCACA,yCACA,0CACA,yCACA,yCAGF,2BACE,yCACA,yCACA,0CACA,0CACA,0CAGF,WACE,sBACA,wDACA,wDACA,wDACA,yDACA,0DCrBF,0EAIE,4BAEA,4DACA,+DACA,uCACA,yHACA,iGACA,mCACA,mCACA,2EAGF,kBACE,wDACA,6DACA,2DAGA,2BACA,qBACA,uBACA,wBACA,6BACA,uBAGF,oBACE,wDACA,2DACA,0DAGA,2BACA,qBACA,uBACA,wBACA,6BACA,uBAGF,iBACE,wDACA,6DACA,4DAGA,4BACA,qBACA,uBACA,wBACA,6BACA,uBAGF,mBACE,wDACA,2DACA,0DAGA,4BACA,qBACA,uBACA,wBACA,6BACA,uBCtEF,mBACE,yBAGF,iBACE,yBAGF,oBACE,wBAGF,kBACE,wBAGF,0EAIE,uDACA,sDACA,uDAEA,wDACA,sDACA,wDACA,sDACA,wDACA,sDC7BF,WACE,4CACA,6CAEA,wCACA,0CACA,yCACA,2CACA,uCACA,4CCTF,0EAIE,yBACA,2BACA,2BACA,8BACA,2BACA,0BACA,iCACA,+BACA,gCACA,4BCbF,uDACE,6DACA,sFACA,yDACA,8EACA,0DACA,mFCNF,4BACE,0DACA,mEACA,uDACA,2DAGF,2BACE,2DACA,oEACA,uDACA,2DCXF,4BACE,0DACA,uDACA,2DAGF,2BACE,2DACA,uDACA,2DCTF,4BACE,gDACA,2EACA,mEACA,oEACA,sEACA,6FACA,yDACA,kEACA,oFACA,gFACA,+DACA,yFACA,+DACA,sEACA,8FACA,wFACA,qEACA,4DAEA,mEACA,0EACA,kGACA,4FACA,uEACA,gEACA,uEACA,+FACA,yFACA,uEACA,mEACA,4EACA,sGACA,+FACA,2EACA,qEACA,2EACA,mGACA,gGACA,2EACA,0DACA,gFACA,wGACA,mEACA,8EACA,yEACA,6EACA,qGACA,kGACA,+EAGF,2BACE,gDACA,sEACA,4EACA,qEACA,yDACA,8FACA,0DACA,kEACA,oFACA,+EACA,iEACA,wFACA,8DACA,sEACA,8FACA,uFACA,qEACA,0DAEA,mEACA,0EACA,kGACA,4FACA,yEACA,gEACA,uEACA,+FACA,yFACA,sEACA,uEACA,6EACA,qGACA,gGACA,6EACA,oEACA,8EACA,sGACA,6FACA,0EACA,0DACA,+EACA,uGACA,mEACA,+EACA,sEACA,gFACA,wGACA,+FACA,4ECrGF,4BACE,wDACA,+DACA,4EACA,0DACA,iEACA,8EACA,yDACA,gEACA,6EACA,qEACA,sEACA,yEACA,mEACA,qEACA,2FAGF,2BACE,wDACA,+DACA,6EACA,0DACA,iEACA,+EACA,yDACA,gEACA,8EACA,qEACA,sEACA,yEACA,mEACA,mEACA,2FCjCF,4BACE,8DAGF,2BACE,8DCLF,4BACE,mEACA,4FACA,qGACA,oEACA,+FACA,gGACA,kEACA,sFACA,sEACA,gGACA,yGACA,mEACA,wFACA,wEACA,iGACA,uEACA,oGACA,wDACA,iEACA,oDACA,6DACA,oEAGF,2BACE,sEACA,+FACA,wGACA,kEACA,uFACA,mEACA,4FACA,gGACA,wEACA,iGACA,0GACA,mEACA,wFACA,uEACA,gGACA,uEACA,oGACA,wDACA,iEACA,oDACA,6DACA,kGC/CF,WACE,wDACA,wDACA,kEACA,+DACA,8DACA,gEACA,+DCPF,4BACE,gEAGF,2BACE,gECLF,4BACE,8DACA,uEACA,2DACA,+DAGF,2BACE,+DACA,wEACA,2DACA,+DCXF,4BACE,2DACA,oFACA,uDACA,4EAGF,2BACE,4DACA,qFACA,uDACA,4ECXF,4BACE,+DACA,wEACA,4DACA,gEAGF,2BACE,gEACA,yEACA,4DACA,gECXF,kBACE,4BACA,+BAEF,oBACE,6BACA,+BAEF,iBACE,6BACA,+BAEF,mBACE,6BACA,+BAGF,WACE,gEACA,kFACA,6DACA,+EACA,gEACA,kFACA,qECxBF,WACE,wCACA,yCACA,+CAEA,sCACA,oCACA,2CAGA,sFACA,kGACA,oGACA,wGACA,sFACA,kGACA,oGACA,wGACA,6EAGA,8EACA,0FACA,4FACA,gGACA,8EACA,0FACA,4FACA,gGACA,yEAGA,0FACA,sGACA,wGACA,4GACA,0FACA,sGACA,wGACA,4GACA,mFCxCF,WACE,oCAEA,oFACA,sGACA,iFACA,mGAEA,wFACA,0GACA,qFACA,uGAEA,sFACA,wGACA,mFACA,qGChBF,WACE,qDACA,sDAEA,mDACA,oDAEA,yCACA,8CCRF,WACE,8EAEA,2EACA,kCACA,uCACA,2CAEA,2CCRF,WACE,mCACA,oCACA,6CACA,sCAEA,mCACA,yCACA,0CACA,4CACA,4CACA,wCAEA,iEACA,+EACA,mFACA,6EACA,mFAEA,mFACA,0FACA,qGACA,yFACA,qGAEA,uFACA,8FACA,yGACA,6FACA,yGAEA,uCC/BF,WACE,0EAGF,mBACE,8DCLF,WACE,wCACA,uCACA,8CACA,mCAEA,uEACA,6EACA,+EACA,4EAEA,+EACA,iFACA,iGAEA,qFACA,iGACA,mGAEA,yFACA,qGACA,uGAEA,uFACA,mGACA,qGCzBF,WACE,uDACA,6DACA,gDACA,sDACA,uDACA,qDACA,sDAEA,oECTF,WACE,wCACA,2CACA,+CACA,+CACA,+CAEA,qCACA,2CACA,8CACA,kDAEA,mEACA,+EACA,mFACA,mGACA,qFACA,qFAEA,sEACA,wFACA,kFACA,sFACA,sGACA,sEACA,kFACA,sFACA,gGACA,wFACA,sGAEA,0FACA,8FACA,8GACA,0EACA,4FACA,0FACA,8FACA,8GAEA,kGACA,sGACA,sHACA,8EACA,gGACA,kGACA,sGACA,sHAEA,sGACA,0GACA,0HACA,gFACA,kGACA,sGACA,0GACA,0HCxDF,WACE,oCAEA,oFACA,wFACA,sFCLF,WACE,mEACA,yEACA,yEACA,qEACA,kFACA,2EACA,2EAEA,gEACA,sEACA,sEACA,kEAEA,mEACA,yEACA,yEACA,qEAEA,2FACA,2FACA,uFCrBF,WACE,sCACA,uCACA,6CAEA,4EACA,wFACA,0FACA,8FAEA,4EACA,wFACA,0FACA,8FCbF,WAEE,6BACA,4BACA,uCACA,iCACA,gCAGA,0DACA,kEACA,sEACA,0EAGA,6DACA,kEACA,0EACA,8EAGA,6DACA,sEACA,2EACA,yEAGA,6DACA,sEACA,2EACA,yEAGA,6DACA,sEACA,2EACA,yEAGA,gEACA,wEACA,4EACA,gFAGA,mEACA,4EACA,+EACA,iFAEA,mEACA,4EACA,+EACA,iFAEA,mEACA,4EACA,+EACA,iFAGA,gFAEA,+EACA,iGACA,mFACA,qGAGA,iFACA,mFACA,qFACA,2CACA,4CACA,oDAGA,oEAIF,mBACE,8BACA,gCAEA,8BACA,gCAEA,8BACA,gCAEA,8BACA,gCAEA,iCACA,mCAEA,2BACA,6BACA,4BAEA,oCACA,uCAEA,oCACA,sCAEA,oCACA,sCAGF,iBACE,8BACA,gCAEA,8BACA,gCAEA,8BACA,gCAEA,8BACA,gCAEA,iCACA,mCAEA,2BACA,6BACA,4BAEA,oCACA,sCAEA,oCACA,sCAEA,oCACA,sCAGF,oBACE,8BACA,gCAEA,8BACA,gCAEA,8BACA,gCAEA,8BACA,gCAEA,iCACA,mCAEA,2BACA,6BACA,4BAEA,oCACA,sCAEA,oCACA,sCAEA,oCACA,sCAGF,kBACE,8BACA,gCAEA,8BACA,gCAEA,8BACA,gCAEA,8BACA,gCAEA,iCACA,mCAEA,2BACA,6BACA,4BAEA,oCACA,sCAEA,oCACA,sCAEA,oCACA,sCCtMF,WACE,gCACA,uCACA,yCACA,4CAEA,8BACA,qCACA,uCACA,yCAEA,oEACA,+BAEA,8DACA,gFACA,2DACA,6ECjBF,WAEE,iFACA,iFAGA,qFACA,4FACA,uGACA,2FACA,uGAGA,mCACA,0CACA,4CACA,+CACA,iCACA,wCACA,0CACA,4CAEA,uEACA,kCAEA,oEACA,sFACA,iEACA,mFACA,wDACA,0EACA,oEACA,iFACA,kFACA,gFACA,kGACA,sFAGA,mEAGA,sFACA,sGAEA,0EACA,4FACA,8EACA,gGACA,gFACA,kGAGA,4EACA,kFACA,kFACA,8EAEA,qFACA,2FACA,2FACA,uFACA,oGACA,6FACA,6FAEA,kFACA,wFACA,wFACA,oFCrEF,WACE,oGACA,mGACA,oGACA,oGACA,sFACA,sFCHF,WAEE,0BACA,8BACA,yBACA,yBAGA,kDAGA,sBACA,sBACA,qBACA,qBAGF,0EAKE,mDACA,0BACA,gCACA,iCACA,gCACA,8DACA,wEAEA,6CC5BF,WACE,gFACA,oFACA,oFACA,8EAEA,kEACA,oEACA,wEACA,oEACA,wEAGF,4BAEE,uEACA,+FAGA,yDACA,4EACA,8DACA,sEACA,uFACA,wFACA,8DACA,uFACA,0DACA,+EAGA,iEAGA,oFACA,4EAEA,4EACA,oFAEA,uFAEA,yFAEA,gFACA,wFAEA,yFACA,iFAGF,2BAEE,uEACA,+FAGA,yDACA,4EACA,8DACA,sEACA,uFACA,wFACA,+DACA,wFACA,0DACA,+EAGA,iEAGA,oFACA,4EAEA,4EACA,oFAEA,uFAEA,yFAEA,gFACA,wFAEA,yFACA,iFC3FF,YACI,mBAGJ,oBACI,oEACA,8BACA,+BACA,gCACA,wCAGJ,0BACI,2ECbJ,cACI,sBACA,sBACA,qBAGJ,kBANA,kBAQI,YACA,WAGJ,0BACI,uGAIJ,4HAEI,4DACA,yBAIJ,gCACI,WACA,sBACA,gCACA,0DACA,yFACA,iFACA,sBACA,8BACA,kBACA,8BACA,wDCnCJ,UACI,aCDJ,+BACI,aAGJ,mBACI,yBACA,4EANJ,kBAUA,4CAEI,gDCZJ,wBACI,gDACA,qBACA,8BACA,8CACA,4BAGJ,+BACI,8CCTJ,YACI,sBAIJ,0CAEI,0CACA,YARJ,kBAUI,YAVJ,cAYI,WAGJ,kBACI,wCACA,YAjBJ,kBAmBI,YAnBJ,SAqBI,WAGJ,sCACI,4DAGJ,kFAEI,sBACA,sCAIJ,4CACI,4CACA,WACA,gCACA,0DACA,yFACA,iFACA,sBACA,8BACA,kBACA,8BACA,wDC9CJ,yCAEI,MAFJ,UAMA,oDACI,YAGJ,qBACI,2DACA,WAGJ,iCAfA,0BAkBA,gCAlBA", + "names": [] +} diff --git a/vuu-ui/global.d.ts b/vuu-ui/global.d.ts new file mode 100644 index 000000000..a19d27bfe --- /dev/null +++ b/vuu-ui/global.d.ts @@ -0,0 +1,3 @@ +declare module "@thomaschaplin/isin-generator" { + export const isinGenerator = () => undefined; +} diff --git a/vuu-ui/package-lock.json b/vuu-ui/package-lock.json index 1ba83619b..a5edb95de 100644 --- a/vuu-ui/package-lock.json +++ b/vuu-ui/package-lock.json @@ -57,9 +57,9 @@ "stylelint": "^15.0.0", "tinycolor2": "1.4.2", "typescript": "4.9.5", - "vite": "4.2.0", + "vite": "4.5.0", "vite-tsconfig-paths": "^4.0.3", - "vitest": "0.33.0" + "vitest": "0.34.6" }, "engines": { "node": ">=16.0.0" @@ -1236,6 +1236,10 @@ "resolved": "packages/vuu-data-react", "link": true }, + "node_modules/@finos/vuu-data-test": { + "resolved": "packages/vuu-data-test", + "link": true + }, "node_modules/@finos/vuu-data-types": { "resolved": "packages/vuu-data-types", "link": true @@ -2717,26 +2721,26 @@ } }, "node_modules/@vitest/expect": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.33.0.tgz", - "integrity": "sha512-sVNf+Gla3mhTCxNJx+wJLDPp/WcstOe0Ksqz4Vec51MmgMth/ia0MGFEkIZmVGeTL5HtjYR4Wl/ZxBxBXZJTzQ==", + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.34.6.tgz", + "integrity": "sha512-QUzKpUQRc1qC7qdGo7rMK3AkETI7w18gTCUrsNnyjjJKYiuUB9+TQK3QnR1unhCnWRC0AbKv2omLGQDF/mIjOw==", "dev": true, "dependencies": { - "@vitest/spy": "0.33.0", - "@vitest/utils": "0.33.0", - "chai": "^4.3.7" + "@vitest/spy": "0.34.6", + "@vitest/utils": "0.34.6", + "chai": "^4.3.10" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/runner": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.33.0.tgz", - "integrity": "sha512-UPfACnmCB6HKRHTlcgCoBh6ppl6fDn+J/xR8dTufWiKt/74Y9bHci5CKB8tESSV82zKYtkBJo9whU3mNvfaisg==", + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.34.6.tgz", + "integrity": "sha512-1CUQgtJSLF47NnhN+F9X2ycxUP0kLHQ/JWvNHbeBfwW8CzEGgeskzNnHDyv1ieKTltuR6sdIHV+nmR6kPxQqzQ==", "dev": true, "dependencies": { - "@vitest/utils": "0.33.0", + "@vitest/utils": "0.34.6", "p-limit": "^4.0.0", "pathe": "^1.1.1" }, @@ -2772,9 +2776,9 @@ } }, "node_modules/@vitest/snapshot": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.33.0.tgz", - "integrity": "sha512-tJjrl//qAHbyHajpFvr8Wsk8DIOODEebTu7pgBrP07iOepR5jYkLFiqLq2Ltxv+r0uptUb4izv1J8XBOwKkVYA==", + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.34.6.tgz", + "integrity": "sha512-B3OZqYn6k4VaN011D+ve+AA4whM4QkcwcrwaKwAbyyvS/NB1hCWjFIBQxAQQSQir9/RtyAAGuq+4RJmbn2dH4w==", "dev": true, "dependencies": { "magic-string": "^0.30.1", @@ -2786,12 +2790,12 @@ } }, "node_modules/@vitest/snapshot/node_modules/pretty-format": { - "version": "29.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.2.tgz", - "integrity": "sha512-1q0oC8eRveTg5nnBEWMXAU2qpv65Gnuf2eCQzSjxpWFkPaPARwqZZDGuNE0zPAZfTCHzIk3A8dIjwlQKKLphyg==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "dependencies": { - "@jest/schemas": "^29.6.0", + "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" }, @@ -2806,9 +2810,9 @@ "dev": true }, "node_modules/@vitest/spy": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.33.0.tgz", - "integrity": "sha512-Kv+yZ4hnH1WdiAkPUQTpRxW8kGtH8VRTnus7ZTGovFYM1ZezJpvGtb9nPIjPnptHbsyIAxYZsEpVPYgtpjGnrg==", + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.34.6.tgz", + "integrity": "sha512-xaCvneSaeBw/cz8ySmF7ZwGvL0lBjfvqc1LpQ/vcdHEvpLn3Ff1vAvjw+CoGn0802l++5L/pxb7whwcWAw+DUQ==", "dev": true, "dependencies": { "tinyspy": "^2.1.1" @@ -2818,9 +2822,9 @@ } }, "node_modules/@vitest/utils": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.33.0.tgz", - "integrity": "sha512-pF1w22ic965sv+EN6uoePkAOTkAPWM03Ri/jXNyMIKBb/XHLDPfhLvf/Fa9g0YECevAIz56oVYXhodLvLQ/awA==", + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.34.6.tgz", + "integrity": "sha512-IG5aDD8S6zlvloDsnzHw0Ut5xczlF+kv2BOTo+iXfPr54Yhi5qbVOgGB1hZaVq4iJ4C/MZ2J0y15IlsV/ZcI0A==", "dev": true, "dependencies": { "diff-sequences": "^29.4.3", @@ -2832,21 +2836,21 @@ } }, "node_modules/@vitest/utils/node_modules/diff-sequences": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", - "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", "dev": true, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@vitest/utils/node_modules/pretty-format": { - "version": "29.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.2.tgz", - "integrity": "sha512-1q0oC8eRveTg5nnBEWMXAU2qpv65Gnuf2eCQzSjxpWFkPaPARwqZZDGuNE0zPAZfTCHzIk3A8dIjwlQKKLphyg==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "dependencies": { - "@jest/schemas": "^29.6.0", + "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" }, @@ -3523,18 +3527,18 @@ } }, "node_modules/chai": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", - "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", + "version": "4.3.10", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz", + "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==", "dev": true, "dependencies": { "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^4.1.2", - "get-func-name": "^2.0.0", - "loupe": "^2.3.1", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", "pathval": "^1.1.1", - "type-detect": "^4.0.5" + "type-detect": "^4.0.8" }, "engines": { "node": ">=4" @@ -3593,10 +3597,13 @@ } }, "node_modules/check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", "dev": true, + "dependencies": { + "get-func-name": "^2.0.2" + }, "engines": { "node": "*" } @@ -5480,9 +5487,9 @@ } }, "node_modules/get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", "dev": true, "engines": { "node": "*" @@ -7205,12 +7212,12 @@ } }, "node_modules/loupe": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", - "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", "dev": true, "dependencies": { - "get-func-name": "^2.0.0" + "get-func-name": "^2.0.1" } }, "node_modules/lru-cache": { @@ -7232,9 +7239,9 @@ } }, "node_modules/magic-string": { - "version": "0.30.2", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.2.tgz", - "integrity": "sha512-lNZdu7pewtq/ZvWUp9Wpf/x7WzMTsR26TWV03BRZrXFsv+BI6dy8RAiKgm1uM/kyR0rCfUcqvOlXKG66KhIGug==", + "version": "0.30.5", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", + "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", "dev": true, "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" @@ -8223,15 +8230,15 @@ } }, "node_modules/mlly": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.0.tgz", - "integrity": "sha512-ua8PAThnTwpprIaU47EPeZ/bPUVp2QYBbWMphUQpVdBI3Lgqzm5KZQ45Agm3YJedHXaIHl6pBGabaLSUPPSptg==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.2.tgz", + "integrity": "sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==", "dev": true, "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.10.0", "pathe": "^1.1.1", "pkg-types": "^1.0.3", - "ufo": "^1.1.2" + "ufo": "^1.3.0" } }, "node_modules/mri": { @@ -8770,9 +8777,9 @@ } }, "node_modules/postcss": { - "version": "8.4.27", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz", - "integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==", + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "dev": true, "funding": [ { @@ -10228,18 +10235,18 @@ } }, "node_modules/tinypool": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.6.0.tgz", - "integrity": "sha512-FdswUUo5SxRizcBc6b1GSuLpLjisa8N8qMyYoP3rl+bym+QauhtJP5bvZY1ytt8krKGmMLYIRl36HBZfeAoqhQ==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.7.0.tgz", + "integrity": "sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww==", "dev": true, "engines": { "node": ">=14.0.0" } }, "node_modules/tinyspy": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.1.1.tgz", - "integrity": "sha512-XPJL2uSzcOyBMky6OFrusqWlzfFrXtE0hPuMgW8A2HmaqrPo4ZQHRN/V0QXN3FSjKxpsbRrFc5LI7KOwBsT1/w==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.0.tgz", + "integrity": "sha512-d2eda04AN/cPOR89F7Xv5bK/jrQEhmcLFe6HFldoeO9AJtps+fqEnh486vnT/8y4bw38pSyxDcTCAq+Ks2aJTg==", "dev": true, "engines": { "node": ">=14.0.0" @@ -10519,9 +10526,9 @@ } }, "node_modules/ufo": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.2.0.tgz", - "integrity": "sha512-RsPyTbqORDNDxqAdQPQBpgqhWle1VcTSou/FraClYlHf6TZnQcGslpLcAphNR+sQW4q5lLWLbOsRlh9j24baQg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.3.1.tgz", + "integrity": "sha512-uY/99gMLIOlJPwATcMVYfqDSxUR9//AUcgZMzwfSTJPDKzA1S8mX4VLqa+fiAtveraQUBCz4FFcwVZBGbwBXIw==", "dev": true }, "node_modules/unbox-primitive": { @@ -10817,15 +10824,14 @@ } }, "node_modules/vite": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.2.0.tgz", - "integrity": "sha512-AbDTyzzwuKoRtMIRLGNxhLRuv1FpRgdIw+1y6AQG73Q5+vtecmvzKo/yk8X/vrHDpETRTx01ABijqUHIzBXi0g==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz", + "integrity": "sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==", "dev": true, "dependencies": { - "esbuild": "^0.17.5", - "postcss": "^8.4.21", - "resolve": "^1.22.1", - "rollup": "^3.18.0" + "esbuild": "^0.18.10", + "postcss": "^8.4.27", + "rollup": "^3.27.1" }, "bin": { "vite": "bin/vite.js" @@ -10833,12 +10839,16 @@ "engines": { "node": "^14.18.0 || >=16.0.0" }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@types/node": ">= 14", "less": "*", + "lightningcss": "^1.21.0", "sass": "*", "stylus": "*", "sugarss": "*", @@ -10851,6 +10861,9 @@ "less": { "optional": true }, + "lightningcss": { + "optional": true + }, "sass": { "optional": true }, @@ -10866,9 +10879,9 @@ } }, "node_modules/vite-node": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.33.0.tgz", - "integrity": "sha512-19FpHYbwWWxDr73ruNahC+vtEdza52kA90Qb3La98yZ0xULqV8A5JLNPUff0f5zID4984tW7l3DH2przTJUZSw==", + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.34.6.tgz", + "integrity": "sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==", "dev": true, "dependencies": { "cac": "^6.7.14", @@ -10876,7 +10889,7 @@ "mlly": "^1.4.0", "pathe": "^1.1.1", "picocolors": "^1.0.0", - "vite": "^3.0.0 || ^4.0.0" + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0-0" }, "bin": { "vite-node": "vite-node.mjs" @@ -10907,41 +10920,413 @@ } } }, - "node_modules/vite/node_modules/resolve": { - "version": "1.22.4", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", - "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==", + "node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "cpu": [ + "arm" + ], "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/esbuild": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "dev": true, + "hasInstallScript": true, "bin": { - "resolve": "bin/resolve" + "esbuild": "bin/esbuild" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" } }, "node_modules/vitest": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.33.0.tgz", - "integrity": "sha512-1CxaugJ50xskkQ0e969R/hW47za4YXDUfWJDxip1hwbnhUjYolpfUn2AMOulqG/Dtd9WYAtkHmM/m3yKVrEejQ==", + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.34.6.tgz", + "integrity": "sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==", "dev": true, "dependencies": { "@types/chai": "^4.3.5", "@types/chai-subset": "^1.3.3", "@types/node": "*", - "@vitest/expect": "0.33.0", - "@vitest/runner": "0.33.0", - "@vitest/snapshot": "0.33.0", - "@vitest/spy": "0.33.0", - "@vitest/utils": "0.33.0", + "@vitest/expect": "0.34.6", + "@vitest/runner": "0.34.6", + "@vitest/snapshot": "0.34.6", + "@vitest/spy": "0.34.6", + "@vitest/utils": "0.34.6", "acorn": "^8.9.0", "acorn-walk": "^8.2.0", "cac": "^6.7.14", - "chai": "^4.3.7", + "chai": "^4.3.10", "debug": "^4.3.4", "local-pkg": "^0.4.3", "magic-string": "^0.30.1", @@ -10950,9 +11335,9 @@ "std-env": "^3.3.3", "strip-literal": "^1.0.1", "tinybench": "^2.5.0", - "tinypool": "^0.6.0", - "vite": "^3.0.0 || ^4.0.0", - "vite-node": "0.33.0", + "tinypool": "^0.7.0", + "vite": "^3.1.0 || ^4.0.0 || ^5.0.0-0", + "vite-node": "0.34.6", "why-is-node-running": "^2.2.2" }, "bin": { @@ -11415,6 +11800,15 @@ "react": "^17.0.2" } }, + "packages/vuu-data-test": { + "name": "@finos/vuu-data-test", + "version": "0.0.26", + "license": "Apache-2.0", + "devDependencies": { + "@finos/vuu-data": "0.0.26", + "@finos/vuu-datagrid-types": "0.0.26" + } + }, "packages/vuu-data-types": { "name": "@finos/vuu-data-types", "version": "0.0.26", @@ -11581,6 +11975,7 @@ "dependencies": { "@finos/vuu-data": "0.0.26", "@finos/vuu-filters": "0.0.26", + "@finos/vuu-icons": "0.0.26", "@finos/vuu-layout": "0.0.26", "@finos/vuu-table": "0.0.26", "@finos/vuu-table-extras": "0.0.26", @@ -11929,6 +12324,7 @@ "dependencies": { "@faker-js/faker": "^8.0.2", "@finos/vuu-data-ag-grid": "0.0.26", + "@finos/vuu-data-test": "0.0.26", "@finos/vuu-datagrid": "0.0.26", "@finos/vuu-filters": "0.0.26", "@finos/vuu-layout": "0.0.26", @@ -12673,6 +13069,7 @@ "requires": { "@faker-js/faker": "^8.0.2", "@finos/vuu-data-ag-grid": "0.0.26", + "@finos/vuu-data-test": "0.0.26", "@finos/vuu-datagrid": "0.0.26", "@finos/vuu-filters": "0.0.26", "@finos/vuu-layout": "0.0.26", @@ -12738,6 +13135,13 @@ "@finos/vuu-utils": "0.0.26" } }, + "@finos/vuu-data-test": { + "version": "file:packages/vuu-data-test", + "requires": { + "@finos/vuu-data": "0.0.26", + "@finos/vuu-datagrid-types": "0.0.26" + } + }, "@finos/vuu-data-types": { "version": "file:packages/vuu-data-types", "requires": { @@ -12845,6 +13249,7 @@ "requires": { "@finos/vuu-data": "0.0.26", "@finos/vuu-filters": "0.0.26", + "@finos/vuu-icons": "0.0.26", "@finos/vuu-layout": "0.0.26", "@finos/vuu-table": "0.0.26", "@finos/vuu-table-extras": "0.0.26", @@ -14004,23 +14409,23 @@ } }, "@vitest/expect": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.33.0.tgz", - "integrity": "sha512-sVNf+Gla3mhTCxNJx+wJLDPp/WcstOe0Ksqz4Vec51MmgMth/ia0MGFEkIZmVGeTL5HtjYR4Wl/ZxBxBXZJTzQ==", + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.34.6.tgz", + "integrity": "sha512-QUzKpUQRc1qC7qdGo7rMK3AkETI7w18gTCUrsNnyjjJKYiuUB9+TQK3QnR1unhCnWRC0AbKv2omLGQDF/mIjOw==", "dev": true, "requires": { - "@vitest/spy": "0.33.0", - "@vitest/utils": "0.33.0", - "chai": "^4.3.7" + "@vitest/spy": "0.34.6", + "@vitest/utils": "0.34.6", + "chai": "^4.3.10" } }, "@vitest/runner": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.33.0.tgz", - "integrity": "sha512-UPfACnmCB6HKRHTlcgCoBh6ppl6fDn+J/xR8dTufWiKt/74Y9bHci5CKB8tESSV82zKYtkBJo9whU3mNvfaisg==", + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.34.6.tgz", + "integrity": "sha512-1CUQgtJSLF47NnhN+F9X2ycxUP0kLHQ/JWvNHbeBfwW8CzEGgeskzNnHDyv1ieKTltuR6sdIHV+nmR6kPxQqzQ==", "dev": true, "requires": { - "@vitest/utils": "0.33.0", + "@vitest/utils": "0.34.6", "p-limit": "^4.0.0", "pathe": "^1.1.1" }, @@ -14043,9 +14448,9 @@ } }, "@vitest/snapshot": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.33.0.tgz", - "integrity": "sha512-tJjrl//qAHbyHajpFvr8Wsk8DIOODEebTu7pgBrP07iOepR5jYkLFiqLq2Ltxv+r0uptUb4izv1J8XBOwKkVYA==", + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.34.6.tgz", + "integrity": "sha512-B3OZqYn6k4VaN011D+ve+AA4whM4QkcwcrwaKwAbyyvS/NB1hCWjFIBQxAQQSQir9/RtyAAGuq+4RJmbn2dH4w==", "dev": true, "requires": { "magic-string": "^0.30.1", @@ -14054,12 +14459,12 @@ }, "dependencies": { "pretty-format": { - "version": "29.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.2.tgz", - "integrity": "sha512-1q0oC8eRveTg5nnBEWMXAU2qpv65Gnuf2eCQzSjxpWFkPaPARwqZZDGuNE0zPAZfTCHzIk3A8dIjwlQKKLphyg==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "requires": { - "@jest/schemas": "^29.6.0", + "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" } @@ -14073,18 +14478,18 @@ } }, "@vitest/spy": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.33.0.tgz", - "integrity": "sha512-Kv+yZ4hnH1WdiAkPUQTpRxW8kGtH8VRTnus7ZTGovFYM1ZezJpvGtb9nPIjPnptHbsyIAxYZsEpVPYgtpjGnrg==", + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.34.6.tgz", + "integrity": "sha512-xaCvneSaeBw/cz8ySmF7ZwGvL0lBjfvqc1LpQ/vcdHEvpLn3Ff1vAvjw+CoGn0802l++5L/pxb7whwcWAw+DUQ==", "dev": true, "requires": { "tinyspy": "^2.1.1" } }, "@vitest/utils": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.33.0.tgz", - "integrity": "sha512-pF1w22ic965sv+EN6uoePkAOTkAPWM03Ri/jXNyMIKBb/XHLDPfhLvf/Fa9g0YECevAIz56oVYXhodLvLQ/awA==", + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.34.6.tgz", + "integrity": "sha512-IG5aDD8S6zlvloDsnzHw0Ut5xczlF+kv2BOTo+iXfPr54Yhi5qbVOgGB1hZaVq4iJ4C/MZ2J0y15IlsV/ZcI0A==", "dev": true, "requires": { "diff-sequences": "^29.4.3", @@ -14093,18 +14498,18 @@ }, "dependencies": { "diff-sequences": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", - "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", "dev": true }, "pretty-format": { - "version": "29.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.2.tgz", - "integrity": "sha512-1q0oC8eRveTg5nnBEWMXAU2qpv65Gnuf2eCQzSjxpWFkPaPARwqZZDGuNE0zPAZfTCHzIk3A8dIjwlQKKLphyg==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "requires": { - "@jest/schemas": "^29.6.0", + "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" } @@ -14587,18 +14992,18 @@ "dev": true }, "chai": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", - "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", + "version": "4.3.10", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz", + "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==", "dev": true, "requires": { "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^4.1.2", - "get-func-name": "^2.0.0", - "loupe": "^2.3.1", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", "pathval": "^1.1.1", - "type-detect": "^4.0.5" + "type-detect": "^4.0.8" } }, "chalk": { @@ -14632,10 +15037,13 @@ "dev": true }, "check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", - "dev": true + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "requires": { + "get-func-name": "^2.0.2" + } }, "check-more-types": { "version": "2.24.0", @@ -16116,9 +16524,9 @@ "dev": true }, "get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", "dev": true }, "get-intrinsic": { @@ -17349,12 +17757,12 @@ } }, "loupe": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", - "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", "dev": true, "requires": { - "get-func-name": "^2.0.0" + "get-func-name": "^2.0.1" } }, "lru-cache": { @@ -17373,9 +17781,9 @@ "dev": true }, "magic-string": { - "version": "0.30.2", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.2.tgz", - "integrity": "sha512-lNZdu7pewtq/ZvWUp9Wpf/x7WzMTsR26TWV03BRZrXFsv+BI6dy8RAiKgm1uM/kyR0rCfUcqvOlXKG66KhIGug==", + "version": "0.30.5", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", + "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", "dev": true, "requires": { "@jridgewell/sourcemap-codec": "^1.4.15" @@ -18011,15 +18419,15 @@ } }, "mlly": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.0.tgz", - "integrity": "sha512-ua8PAThnTwpprIaU47EPeZ/bPUVp2QYBbWMphUQpVdBI3Lgqzm5KZQ45Agm3YJedHXaIHl6pBGabaLSUPPSptg==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.2.tgz", + "integrity": "sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==", "dev": true, "requires": { - "acorn": "^8.9.0", + "acorn": "^8.10.0", "pathe": "^1.1.1", "pkg-types": "^1.0.3", - "ufo": "^1.1.2" + "ufo": "^1.3.0" } }, "mri": { @@ -18402,9 +18810,9 @@ } }, "postcss": { - "version": "8.4.27", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz", - "integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==", + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "dev": true, "requires": { "nanoid": "^3.3.6", @@ -19463,15 +19871,15 @@ "integrity": "sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA==" }, "tinypool": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.6.0.tgz", - "integrity": "sha512-FdswUUo5SxRizcBc6b1GSuLpLjisa8N8qMyYoP3rl+bym+QauhtJP5bvZY1ytt8krKGmMLYIRl36HBZfeAoqhQ==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.7.0.tgz", + "integrity": "sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww==", "dev": true }, "tinyspy": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.1.1.tgz", - "integrity": "sha512-XPJL2uSzcOyBMky6OFrusqWlzfFrXtE0hPuMgW8A2HmaqrPo4ZQHRN/V0QXN3FSjKxpsbRrFc5LI7KOwBsT1/w==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.0.tgz", + "integrity": "sha512-d2eda04AN/cPOR89F7Xv5bK/jrQEhmcLFe6HFldoeO9AJtps+fqEnh486vnT/8y4bw38pSyxDcTCAq+Ks2aJTg==", "dev": true }, "tmp": { @@ -19661,9 +20069,9 @@ "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==" }, "ufo": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.2.0.tgz", - "integrity": "sha512-RsPyTbqORDNDxqAdQPQBpgqhWle1VcTSou/FraClYlHf6TZnQcGslpLcAphNR+sQW4q5lLWLbOsRlh9j24baQg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.3.1.tgz", + "integrity": "sha512-uY/99gMLIOlJPwATcMVYfqDSxUR9//AUcgZMzwfSTJPDKzA1S8mX4VLqa+fiAtveraQUBCz4FFcwVZBGbwBXIw==", "dev": true }, "unbox-primitive": { @@ -19874,35 +20282,207 @@ } }, "vite": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.2.0.tgz", - "integrity": "sha512-AbDTyzzwuKoRtMIRLGNxhLRuv1FpRgdIw+1y6AQG73Q5+vtecmvzKo/yk8X/vrHDpETRTx01ABijqUHIzBXi0g==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz", + "integrity": "sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==", "dev": true, "requires": { - "esbuild": "^0.17.5", + "esbuild": "^0.18.10", "fsevents": "~2.3.2", - "postcss": "^8.4.21", - "resolve": "^1.22.1", - "rollup": "^3.18.0" + "postcss": "^8.4.27", + "rollup": "^3.27.1" }, "dependencies": { - "resolve": { - "version": "1.22.4", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", - "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==", + "@esbuild/android-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "dev": true, + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "dev": true, + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "dev": true, + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "dev": true, + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "dev": true, + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "dev": true, + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "dev": true, + "optional": true + }, + "esbuild": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", "dev": true, "requires": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" } } } }, "vite-node": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.33.0.tgz", - "integrity": "sha512-19FpHYbwWWxDr73ruNahC+vtEdza52kA90Qb3La98yZ0xULqV8A5JLNPUff0f5zID4984tW7l3DH2przTJUZSw==", + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.34.6.tgz", + "integrity": "sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==", "dev": true, "requires": { "cac": "^6.7.14", @@ -19910,7 +20490,7 @@ "mlly": "^1.4.0", "pathe": "^1.1.1", "picocolors": "^1.0.0", - "vite": "^3.0.0 || ^4.0.0" + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0-0" } }, "vite-tsconfig-paths": { @@ -19925,23 +20505,23 @@ } }, "vitest": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.33.0.tgz", - "integrity": "sha512-1CxaugJ50xskkQ0e969R/hW47za4YXDUfWJDxip1hwbnhUjYolpfUn2AMOulqG/Dtd9WYAtkHmM/m3yKVrEejQ==", + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.34.6.tgz", + "integrity": "sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==", "dev": true, "requires": { "@types/chai": "^4.3.5", "@types/chai-subset": "^1.3.3", "@types/node": "*", - "@vitest/expect": "0.33.0", - "@vitest/runner": "0.33.0", - "@vitest/snapshot": "0.33.0", - "@vitest/spy": "0.33.0", - "@vitest/utils": "0.33.0", + "@vitest/expect": "0.34.6", + "@vitest/runner": "0.34.6", + "@vitest/snapshot": "0.34.6", + "@vitest/spy": "0.34.6", + "@vitest/utils": "0.34.6", "acorn": "^8.9.0", "acorn-walk": "^8.2.0", "cac": "^6.7.14", - "chai": "^4.3.7", + "chai": "^4.3.10", "debug": "^4.3.4", "local-pkg": "^0.4.3", "magic-string": "^0.30.1", @@ -19950,9 +20530,9 @@ "std-env": "^3.3.3", "strip-literal": "^1.0.1", "tinybench": "^2.5.0", - "tinypool": "^0.6.0", - "vite": "^3.0.0 || ^4.0.0", - "vite-node": "0.33.0", + "tinypool": "^0.7.0", + "vite": "^3.1.0 || ^4.0.0 || ^5.0.0-0", + "vite-node": "0.34.6", "why-is-node-running": "^2.2.2" } }, diff --git a/vuu-ui/package.json b/vuu-ui/package.json index 952d788e6..c471237d9 100644 --- a/vuu-ui/package.json +++ b/vuu-ui/package.json @@ -35,11 +35,12 @@ "showcase:build": " cd showcase && node scripts/build.mjs", "test:cypress": "cypress run --component --browser chrome --headless", "test:cypress:local": "cypress open --component --browser chrome", + "test:cypress:e2e": "cypress run --browser chrome", "test:vite": "vitest run", "bump": "node ./scripts/version.mjs", "pub": "node ./scripts/publish.mjs", "pub:debug": "node ./scripts/publish.mjs --debug", - "typecheck": "tsc --noEmit" + "typecheck": "tsc --noEmit --project tsconfig-typecheck.json" }, "dependencies": { "@types/jest": "^26.0.20", @@ -82,9 +83,9 @@ "stylelint": "^15.0.0", "tinycolor2": "1.4.2", "typescript": "4.9.5", - "vite": "4.2.0", + "vite": "4.5.0", "vite-tsconfig-paths": "^4.0.3", - "vitest": "0.33.0" + "vitest": "0.34.6" }, "engines": { "node": ">=16.0.0" diff --git a/vuu-ui/packages/vuu-codemirror/src/codemirror-basic-setup.ts b/vuu-ui/packages/vuu-codemirror/src/codemirror-basic-setup.ts index 0b8f7413c..5c2352232 100644 --- a/vuu-ui/packages/vuu-codemirror/src/codemirror-basic-setup.ts +++ b/vuu-ui/packages/vuu-codemirror/src/codemirror-basic-setup.ts @@ -1,16 +1,16 @@ -import { KeyBinding } from "@codemirror/view"; +import { closeBrackets } from "@codemirror/autocomplete"; +import { defaultKeymap, history, historyKeymap } from "@codemirror/commands"; import { - closeBrackets, defaultHighlightStyle, - defaultKeymap, + syntaxHighlighting, +} from "@codemirror/language"; +import { Extension } from "@codemirror/state"; +import { drawSelection, - Extension, highlightSpecialChars, - history, - historyKeymap, + KeyBinding, keymap, - syntaxHighlighting, -} from "./index"; +} from "@codemirror/view"; const keyBindings = [ ...defaultKeymap, diff --git a/vuu-ui/packages/vuu-codemirror/tsconfig.json b/vuu-ui/packages/vuu-codemirror/tsconfig.json new file mode 100644 index 000000000..db9582a16 --- /dev/null +++ b/vuu-ui/packages/vuu-codemirror/tsconfig.json @@ -0,0 +1,6 @@ +{ +"extends": "../../tsconfig.json", +"compilerOptions":{ + "composite": true +}, +} diff --git a/vuu-ui/packages/vuu-data-ag-grid/tsconfig.json b/vuu-ui/packages/vuu-data-ag-grid/tsconfig.json new file mode 100644 index 000000000..db9582a16 --- /dev/null +++ b/vuu-ui/packages/vuu-data-ag-grid/tsconfig.json @@ -0,0 +1,6 @@ +{ +"extends": "../../tsconfig.json", +"compilerOptions":{ + "composite": true +}, +} diff --git a/vuu-ui/packages/vuu-data-react/src/hooks/useTypeaheadSuggestions.ts b/vuu-ui/packages/vuu-data-react/src/hooks/useTypeaheadSuggestions.ts index add3835c9..42cb853f8 100644 --- a/vuu-ui/packages/vuu-data-react/src/hooks/useTypeaheadSuggestions.ts +++ b/vuu-ui/packages/vuu-data-react/src/hooks/useTypeaheadSuggestions.ts @@ -30,32 +30,20 @@ export const getTypeaheadParams = ( // const containSpace = (text: string) => text.indexOf(" ") !== -1; // const replaceSpace = (text: string) => text.replace(/\s/g, SPECIAL_SPACE); -export const useTypeaheadSuggestions = () => { - const getTypeaheadSuggestions: SuggestionFetcher = useCallback( - async (params: TypeaheadParams) => { - const rpcMessage = - params.length === 2 - ? ({ - method: "getUniqueFieldValues", - params, - ...TYPEAHEAD_MESSAGE_CONSTANTS, - } as ClientToServerGetUniqueValues) - : ({ - method: "getUniqueFieldValuesStartingWith", - params, - ...TYPEAHEAD_MESSAGE_CONSTANTS, - } as ClientToServerGetUniqueValuesStartingWith); - - const suggestions = await makeRpcCall(rpcMessage); - - // TODO replacing space with underscores like this is not being correctly handled elsewhere - return suggestions; - // return suggestions.some(containSpace) - // ? suggestions.map(replaceSpace) - // : suggestions; - }, - [] - ); - - return getTypeaheadSuggestions; -}; +export const useTypeaheadSuggestions = () => + useCallback(async (params: TypeaheadParams) => { + const rpcMessage = + params.length === 2 + ? ({ + method: "getUniqueFieldValues", + params, + ...TYPEAHEAD_MESSAGE_CONSTANTS, + } as ClientToServerGetUniqueValues) + : ({ + method: "getUniqueFieldValuesStartingWith", + params, + ...TYPEAHEAD_MESSAGE_CONSTANTS, + } as ClientToServerGetUniqueValuesStartingWith); + + return makeRpcCall(rpcMessage); + }, []); diff --git a/vuu-ui/packages/vuu-data-react/src/hooks/useVuuMenuActions.ts b/vuu-ui/packages/vuu-data-react/src/hooks/useVuuMenuActions.ts index 3d1afb08d..3780574a6 100644 --- a/vuu-ui/packages/vuu-data-react/src/hooks/useVuuMenuActions.ts +++ b/vuu-ui/packages/vuu-data-react/src/hooks/useVuuMenuActions.ts @@ -213,7 +213,7 @@ export type VuuServerMenuOptions = { columnMap: ColumnMap; columnName: string; row: DataSourceRow; - selectedRows: DataSourceRow[]; + selectedRowsCount: number; viewport: string; }; @@ -373,6 +373,7 @@ export const useVuuMenuActions = ({ `useViewServer handleMenuAction, can't handle action type ${menuId}` ); } + return false; }, [clientSideMenuActionHandler, dataSource, onRpcResponse] diff --git a/vuu-ui/packages/vuu-data-react/tsconfig.json b/vuu-ui/packages/vuu-data-react/tsconfig.json new file mode 100644 index 000000000..db9582a16 --- /dev/null +++ b/vuu-ui/packages/vuu-data-react/tsconfig.json @@ -0,0 +1,6 @@ +{ +"extends": "../../tsconfig.json", +"compilerOptions":{ + "composite": true +}, +} diff --git a/vuu-ui/packages/vuu-data-test/package.json b/vuu-ui/packages/vuu-data-test/package.json new file mode 100644 index 000000000..9204184cf --- /dev/null +++ b/vuu-ui/packages/vuu-data-test/package.json @@ -0,0 +1,15 @@ +{ + "name": "@finos/vuu-data-test", + "version": "0.0.26", + "main": "src/index.ts", + "author": "heswell", + "license": "Apache-2.0", + "scripts": { + "build": "node ../../scripts/run-build.mjs", + "type-defs": "node ../../scripts/build-type-defs.mjs" + }, + "devDependencies": { + "@finos/vuu-data": "0.0.26", + "@finos/vuu-datagrid-types": "0.0.26" + } +} diff --git a/vuu-ui/showcase/src/examples/utils/UpdateGenerator.ts b/vuu-ui/packages/vuu-data-test/src/UpdateGenerator.ts similarity index 93% rename from vuu-ui/showcase/src/examples/utils/UpdateGenerator.ts rename to vuu-ui/packages/vuu-data-test/src/UpdateGenerator.ts index 97a95e9c8..f76e03023 100644 --- a/vuu-ui/showcase/src/examples/utils/UpdateGenerator.ts +++ b/vuu-ui/packages/vuu-data-test/src/UpdateGenerator.ts @@ -1,7 +1,7 @@ -import { VuuRange } from "packages/vuu-protocol-types"; +import { ArrayDataSource } from "@finos/vuu-data"; +import { VuuRange } from "@finos/vuu-protocol-types"; +import { random } from "./simul/reference-data"; import { RowUpdates, UpdateGenerator, UpdateHandler } from "./rowUpdates"; -import { random } from "./reference-data"; -import { ArrayDataSource, DataSource } from "@finos/vuu-data"; const getNewValue = (value: number) => { const multiplier = random(0, 100) / 1000; diff --git a/vuu-ui/packages/vuu-data-test/src/basket/basket-schemas.ts b/vuu-ui/packages/vuu-data-test/src/basket/basket-schemas.ts new file mode 100644 index 000000000..aa1edde74 --- /dev/null +++ b/vuu-ui/packages/vuu-data-test/src/basket/basket-schemas.ts @@ -0,0 +1,125 @@ +import { TableSchema } from "@finos/vuu-data"; + +export type BasketsTableName = + | "algoType" + | "basket" + | "basketConstituent" + | "basketTrading" + | "basketTradingConstituent" + | "basketTrdConsPrices" + | "priceStrategyType"; + +export const schemas: Readonly< + Record> +> = { + algoType: { + columns: [ + { name: "algoType", serverDataType: "string" }, + { name: "id", serverDataType: "int" }, + ], + key: "id", + table: { module: "BASKET", table: "algoType" }, + }, + basket: { + columns: [ + { name: "id", serverDataType: "string" }, + { name: "name", serverDataType: "string" }, + { name: "notionalValue", serverDataType: "double" }, + { name: "notionalValueUsd", serverDataType: "double" }, + ], + key: "id", + table: { module: "BASKET", table: "basket" }, + }, + basketConstituent: { + columns: [ + { name: "basketId", serverDataType: "string" }, + { name: "change", serverDataType: "string" }, + { name: "lastTrade", serverDataType: "string" }, + { name: "ric", serverDataType: "string" }, + { name: "ricBasketId", serverDataType: "string" }, + { name: "side", serverDataType: "string" }, + { name: "volume", serverDataType: "string" }, + { name: "weighting", serverDataType: "double" }, + ], + key: "ricBasketId", + table: { module: "BASKET", table: "basketConstituent" }, + }, + basketTrading: { + columns: [ + { name: "basketId", serverDataType: "string" }, + { name: "basketName", serverDataType: "string" }, + { name: "filledPct", serverDataType: "double" }, + { name: "fxRateToUsd", serverDataType: "double" }, + { name: "instanceId", serverDataType: "string" }, + { name: "status", serverDataType: "string" }, + { name: "totalNotional", serverDataType: "double" }, + { name: "totalNotionalUsd", serverDataType: "double" }, + { name: "units", serverDataType: "int" }, + ], + key: "instanceId", + table: { module: "BASKET", table: "basketTrading" }, + }, + basketTradingConstituent: { + columns: [ + { name: "algo", serverDataType: "string" }, + { name: "algoParams", serverDataType: "string" }, + { name: "basketId", serverDataType: "string" }, + { name: "bid", serverDataType: "double" }, + { name: "description", serverDataType: "string" }, + { name: "instanceId", serverDataType: "string" }, + { name: "instanceIdRic", serverDataType: "string" }, + { name: "limitPrice", serverDataType: "double" }, + { name: "notionalLocal", serverDataType: "double" }, + { name: "notionalUsd", serverDataType: "double" }, + { name: "pctFilled", serverDataType: "double" }, + { name: "priceSpread", serverDataType: "int" }, + { name: "priceStrategyId", serverDataType: "int" }, + { name: "quantity", serverDataType: "long" }, + { name: "ric", serverDataType: "string" }, + { name: "side", serverDataType: "string" }, + { name: "venue", serverDataType: "string" }, + { name: "weighting", serverDataType: "double" }, + ], + key: "instanceIdRic", + table: { module: "BASKET", table: "basketTradingConstituent" }, + }, + basketTrdConsPrices: { + columns: [ + { name: "algo", serverDataType: "string" }, + { name: "algoParams", serverDataType: "string" }, + { name: "ask", serverDataType: "double" }, + { name: "askSize", serverDataType: "double" }, + { name: "basketId", serverDataType: "string" }, + { name: "bid", serverDataType: "double" }, + { name: "bidSize", serverDataType: "double" }, + { name: "close", serverDataType: "double" }, + { name: "description", serverDataType: "string" }, + { name: "instanceId", serverDataType: "string" }, + { name: "instanceIdRic", serverDataType: "string" }, + { name: "last", serverDataType: "double" }, + { name: "limitPrice", serverDataType: "double" }, + { name: "notionalLocal", serverDataType: "double" }, + { name: "notionalUsd", serverDataType: "double" }, + { name: "open", serverDataType: "double" }, + { name: "pctFilled", serverDataType: "double" }, + { name: "phase", serverDataType: "string" }, + { name: "priceSpread", serverDataType: "int" }, + { name: "priceStrategyId", serverDataType: "int" }, + { name: "quantity", serverDataType: "long" }, + { name: "ric", serverDataType: "string" }, + { name: "side", serverDataType: "string" }, + { name: "venue", serverDataType: "string" }, + { name: "weighting", serverDataType: "double" }, + ], + key: "instanceIdRic", + table: { module: "BASKET", table: "basketTradingConstituent" }, + }, + priceStrategyType: { + columns: [ + { name: "priceStrategy", serverDataType: "string" }, + { name: "id", serverDataType: "int" }, + ], + key: "", + table: { module: "BASKET", table: "priceStrategyType" }, + }, +}; diff --git a/vuu-ui/packages/vuu-data-test/src/basket/data-generators/basket-generator.ts b/vuu-ui/packages/vuu-data-test/src/basket/data-generators/basket-generator.ts new file mode 100644 index 000000000..7de4feae6 --- /dev/null +++ b/vuu-ui/packages/vuu-data-test/src/basket/data-generators/basket-generator.ts @@ -0,0 +1,10 @@ +import { BasketColumnMap, BasketReferenceData } from "../reference-data"; +import { getGenerators } from "../../generatorTemplate"; + +const [RowGenerator, ColumnGenerator] = getGenerators( + "basket", + BasketColumnMap, + BasketReferenceData +); + +export { RowGenerator, ColumnGenerator }; diff --git a/vuu-ui/packages/vuu-data-test/src/basket/data-generators/basketConstituent-generator.ts b/vuu-ui/packages/vuu-data-test/src/basket/data-generators/basketConstituent-generator.ts new file mode 100644 index 000000000..9db313bcf --- /dev/null +++ b/vuu-ui/packages/vuu-data-test/src/basket/data-generators/basketConstituent-generator.ts @@ -0,0 +1,13 @@ +import { + BasketConstituentColumnMap, + BasketConstituentReferenceData, +} from "../reference-data"; +import { getGenerators } from "../../generatorTemplate"; + +const [RowGenerator, ColumnGenerator] = getGenerators( + "basketConstituent", + BasketConstituentColumnMap, + BasketConstituentReferenceData +); + +export { RowGenerator, ColumnGenerator }; diff --git a/vuu-ui/packages/vuu-data-test/src/basket/data-generators/basketTrading-generator.ts b/vuu-ui/packages/vuu-data-test/src/basket/data-generators/basketTrading-generator.ts new file mode 100644 index 000000000..2fe2e2ed8 --- /dev/null +++ b/vuu-ui/packages/vuu-data-test/src/basket/data-generators/basketTrading-generator.ts @@ -0,0 +1,13 @@ +import { + BasketTradingColumnMap, + BasketTradingReferenceData, +} from "../reference-data"; +import { getGenerators } from "../../generatorTemplate"; + +const [RowGenerator, ColumnGenerator] = getGenerators( + "basketTrading", + BasketTradingColumnMap, + BasketTradingReferenceData +); + +export { RowGenerator, ColumnGenerator }; diff --git a/vuu-ui/packages/vuu-data-test/src/basket/data-generators/basketTradingConstituent-generator.ts b/vuu-ui/packages/vuu-data-test/src/basket/data-generators/basketTradingConstituent-generator.ts new file mode 100644 index 000000000..90fd547c2 --- /dev/null +++ b/vuu-ui/packages/vuu-data-test/src/basket/data-generators/basketTradingConstituent-generator.ts @@ -0,0 +1,13 @@ +import { + BasketTradingConstituentColumnMap, + BasketTradingConstituentReferenceData, +} from "../reference-data"; +import { getGenerators } from "../../generatorTemplate"; + +const [RowGenerator, ColumnGenerator] = getGenerators( + "basketTradingConstituent", + BasketTradingConstituentColumnMap, + BasketTradingConstituentReferenceData +); + +export { RowGenerator, ColumnGenerator }; diff --git a/vuu-ui/packages/vuu-data-test/src/basket/data-generators/index.ts b/vuu-ui/packages/vuu-data-test/src/basket/data-generators/index.ts new file mode 100644 index 000000000..7c1a90d42 --- /dev/null +++ b/vuu-ui/packages/vuu-data-test/src/basket/data-generators/index.ts @@ -0,0 +1,4 @@ +export * as basket from "./basket-generator"; +export * as basketConstituent from "./basketConstituent-generator"; +export * as basketTrading from "./basketTrading-generator"; +export * as basketTradingConstituent from "./basketTradingConstituent-generator"; diff --git a/vuu-ui/packages/vuu-data-test/src/basket/reference-data/basket.ts b/vuu-ui/packages/vuu-data-test/src/basket/reference-data/basket.ts new file mode 100644 index 000000000..5dbf416cc --- /dev/null +++ b/vuu-ui/packages/vuu-data-test/src/basket/reference-data/basket.ts @@ -0,0 +1,22 @@ +import { VuuDataRow } from "@finos/vuu-protocol-types"; +import { ColumnMap } from "@finos/vuu-utils"; +import { getSchema } from "../../schemas"; + +const schema = getSchema("basket"); + +export const BasketColumnMap = Object.values(schema.columns).reduce( + (map, col, index) => { + map[col.name] = index; + return map; + }, + {} +); + +const data: VuuDataRow[] = [ + [".NASDAQ100", ".NASDAQ100", 0, 0], + [".HSI", ".HSI", 0, 0], + [".FTSE100", ".FTSE100", 0, 0], + [".SP500", ".SP500", 0, 0], +]; + +export default data; diff --git a/vuu-ui/packages/vuu-data-test/src/basket/reference-data/basketConstituent.ts b/vuu-ui/packages/vuu-data-test/src/basket/reference-data/basketConstituent.ts new file mode 100644 index 000000000..933435dd6 --- /dev/null +++ b/vuu-ui/packages/vuu-data-test/src/basket/reference-data/basketConstituent.ts @@ -0,0 +1,43 @@ +import { VuuDataRow } from "@finos/vuu-protocol-types"; +import { getSchema } from "../../schemas"; +import { ColumnMap } from "@finos/vuu-utils"; +import ftse from "./ftse100"; + +const schema = getSchema("basketConstituent"); + +export const BasketConstituentColumnMap = Object.values( + schema.columns +).reduce((map, col, index) => { + map[col.name] = index; + return map; +}, {}); + +const data: VuuDataRow[] = []; + +// const start = performance.now(); +// Create 100_000 Instruments + +for (const row of ftse) { + // prettier-ignore + const [ric, name, lastTrade, change, volume] = row; + + const basketId = ".FTSE100"; + const side = "BUY"; + const weighting = 1; + + data.push([ + basketId, + change, + lastTrade, + ric, + `${ric}-${basketId}`, + side, + volume, + weighting, + ]); +} + +// const end = performance.now(); +// console.log(`generating 100,000 instrumentPrices took ${end - start} ms`); + +export default data; diff --git a/vuu-ui/packages/vuu-data-test/src/basket/reference-data/basketTrading.ts b/vuu-ui/packages/vuu-data-test/src/basket/reference-data/basketTrading.ts new file mode 100644 index 000000000..165531d04 --- /dev/null +++ b/vuu-ui/packages/vuu-data-test/src/basket/reference-data/basketTrading.ts @@ -0,0 +1,45 @@ +import { VuuDataRow } from "@finos/vuu-protocol-types"; +import { ColumnMap } from "@finos/vuu-utils"; +import { getSchema } from "../../schemas"; + +import baskets, { BasketColumnMap } from "./basket"; +import basketConstituents from "./basketConstituent"; + +const schema = getSchema("basketTrading"); + +export const BasketTradingColumnMap = Object.values( + schema.columns +).reduce((map, col, index) => { + map[col.name] = index; + return map; +}, {}); + +let instance = 1; + +const data: VuuDataRow[] = []; + +const createBasket = (basketId: string, basketName: string) => { + const key = BasketColumnMap.basketId; + const basketRow = baskets.find((basket) => basket[key] === basketId); + const basketTradingRow = [ + basketId, + basketName, + 0, + 0, + `steve-${instance++}`, + "OFF-MARKET", + 0, + 0, + 0, + ]; + data.push(basketTradingRow); +}; + +createBasket(".FTSE", "Steve FTSE 1"); +createBasket(".FTSE", "Steve FTSE 2"); +createBasket(".FTSE", "Steve FTSE 3"); +createBasket(".FTSE", "Steve FTSE 4"); +createBasket(".FTSE", "Steve FTSE 5"); +createBasket(".FTSE", "Steve FTSE 6"); + +export default data; diff --git a/vuu-ui/packages/vuu-data-test/src/basket/reference-data/basketTradingConstituent.ts b/vuu-ui/packages/vuu-data-test/src/basket/reference-data/basketTradingConstituent.ts new file mode 100644 index 000000000..01e3471ba --- /dev/null +++ b/vuu-ui/packages/vuu-data-test/src/basket/reference-data/basketTradingConstituent.ts @@ -0,0 +1,16 @@ +import { VuuDataRow } from "@finos/vuu-protocol-types"; +import { ColumnMap } from "@finos/vuu-utils"; +import { getSchema } from "../../schemas"; + +const schema = getSchema("basketTradingConstituent"); + +export const BasketTradingConstituentColumnMap = Object.values( + schema.columns +).reduce((map, col, index) => { + map[col.name] = index; + return map; +}, {}); + +const data: VuuDataRow[] = []; + +export default data; diff --git a/vuu-ui/packages/vuu-data-test/src/basket/reference-data/ftse100.ts b/vuu-ui/packages/vuu-data-test/src/basket/reference-data/ftse100.ts new file mode 100644 index 000000000..3adb247c5 --- /dev/null +++ b/vuu-ui/packages/vuu-data-test/src/basket/reference-data/ftse100.ts @@ -0,0 +1,102 @@ +// Symbol,Name,Last Trade,Change,Volume +// prettier-ignore +export default [ + ["AAL.L","Anglo American PLC","436.35 13:13","5.35 (1.24%)","5,799,089"], + ["ABF.L","Associated British Foods PLC","3,435.60 13:12","7.40 (0.21%)","86,808"], + ["ADM.L","Admiral Group PLC","1,627.00 13:13",""], + ["ADN.L","Aberdeen Asset Management PLC","334.00 13:13","2.50 (0.75%)","806,880"], + ["AHT.L","Ashtead Group PLC","1,027.00 13:13","6.00 (0.59%)","331,255"], + ["ANTO.L","Antofagasta PLC","484.10 13:13","11.70 (2.48%)","1,753,976"], + ["ARM.L","ARM Holdings PLC","1,058.00 13:13","3.00 (0.28%)","475,927"], + ["AV.L","Aviva PLC","493.97 13:13","2.23 (0.45%)","2,226,835"], + ["AZN.L","AstraZeneca PLC","4,399.50 13:13","2.50 (0.06%)","815,133"], + ["BA.L","BAE Systems PLC","478.10 13:13","4.30 (0.91%)","2,039,934"], + ["BAB.L","Babcock International Group PLC","988.00 13:13","9.50 (0.97%)","209,614"], + ["BARC.L","Barclays PLC","226.30 13:13", "1.15 (0.51%)","6,575,664"], + ["BATS.L","British American Tobacco PLC","3,803.50 13:13", "8.50 (0.22%)","465,110"], + ["BDEV.L","Barratt Developments PLC","576.00 13:13", "0.50 (0.09%)","1,044,365"], + ["BG.L","BG Group PLC","1,013.50 13:13", "5.50 (0.55%)","1,507,332"], + ["BKG.L","Berkeley Group Holdings (The) PLC","3,126.00 13:13", "15.00 (0.48%)","95,071"], + ["BLND.L","British Land Co PLC","828.06 13:12", "10.44 (1.25%)","1,802,548"], + ["BLT.L","BHP Billiton PLC","881.40 13:13", "4.30 (0.49%)","4,947,287"], + ["BNZL.L","Bunzl PLC","1,875.40 13:05", "4.60 (0.24%)","104,541"], + ["BP.L","BP PLC","381.50 13:13", "2.95 (0.78%)","10,493,561"], + ["BRBY.L","Burberry Group PLC","1,269.00 13:13", "7.00 (0.55%)","295,647"], + ["BT-A","L,BT Group PLC","489.20 13:13", "3.70 (0.75%)","3,914,982"], + ["CCL.L","Carnival PLC","3,426.00 13:12", "22.00 (0.64%)","86,257"], + ["CNA.L","Centrica PLC","212.80 13:13", "0.60 (0.28%)","2,144,540"], + ["CPG.L","Compass Group PLC","1,054.00 13:08", "5.00 (0.48%)","1,001,167"], + ["CPI.L","Capita PLC","1,235.00 13:11", "1.00 (0.08%)","244,591"], + ["CRH.L","CRH PLC","1,783.20 13:12", "17.80 (0.99%)","897,325"], + ["DC.L","DIXONS CARPHONE","462.10 13:11",""], + ["DGE.L","Diageo PLC","1,881.50 13:13", "6.50 (0.34%)","756,906"], + ["DLG.L","Direct Line Insurance Group PLC","403.80 13:13", "0.40 (0.10%)","1,095,340"], + ["EXPN.L","Experian PLC","1,191.00 13:12", "2.00 (0.17%)","467,283"], + ["EZJ.L","easyJet PLC","1,682.00 13:12", "28.00 (1.64%)","1,191,230"], + ["FRES.L","Fresnillo PLC","678.50 13:12", "6.50 (0.97%)","381,871"], + ["GFS.L","G4S PLC","232.30 13:03", "2.00 (0.85%)","1,096,551"], + ["GKN.L","GKN PLC","294.80 13:12", "2.50 (0.86%)","792,247"], + ["GLEN.L","Glencore PLC","90.48 13:13", "1.65 (1.86%)","41,631,528"], + ["GSK.L","GlaxoSmithKline PLC","1,345.00 13:13", "0.50 (0.04%)","1,767,356"], + ["HIK.L","Hikma Pharmaceuticals PLC","2,010.00 13:04", "57.00 (2.92%)","261,511"], + ["HL.L","Hargreaves Lansdown PLC","1,488.03 13:12", "9.97 (0.67%)","372,261"], + ["HMSO.L","Hammerson PLC","597.50 13:11", "3.50 (0.58%)","478,301"], + ["HSBA.L","HSBC Holdings PLC","519.70 13:13", "0.50 (0.10%)","7,415,629"], + ["IAG.L","International Consolidated Airlines Group SA","575.40 13:12", "16.10 (2.72%)","4,311,514"], + ["IHG.L","InterContinental Hotels Group PLC","2,481.00 13:12", "19.00 (0.76%)","219,918"], + ["III.L","3i Group PLC","487.30 13:11", "4.50 (0.92%)","189,987"], + ["IMT.L","Imperial Tobacco Group PLC","3,571.00 13:13", "29.00 (0.81%)","926,816"], + ["INTU.L","intu properties PLC","319.90 13:09", "4.60 (1.42%)","514,821"], + ["ISAT.L","Inmarsat PLC","1,054.44 13:13", "3.44 (0.33%)","988,089"], + ["ITRK.L","Intertek Group PLC","2,643.00 13:14", "3.00 (0.11%)","45,868"], + ["ITV.L","ITV PLC","267.30 13:14", "2.60 (0.96%)","3,453,208"], + ["JMAT.L","Johnson Matthey PLC","2,445.00 13:14", "29.00 (1.20%)","276,397"], + ["KGF.L","Kingfisher PLC","346.20 13:14", "4.30 (1.23%)","1,021,408"], + ["LAND.L","Land Securities Group PLC","1,239.00 13:13", "7.00 (0.56%)","384,973"], + ["LGEN.L","Legal & General Group PLC","266.00 13:14", "1.60 (0.60%)","1,998,399"], + ["LLOY.L","Lloyds Banking Group PLC","73.86 13:14", "0.02 (0.03%)","18,907,878"], + ["LSE.L","London Stock Exchange Group PLC","2,544.00 13:11", "6.00 (0.24%)","129,657"], + ["MGGT.L","Meggitt PLC","386.00 13:15", "3.20 (0.84%)","611,044"], + ["MKS.L","Marks & Spencer Group PLC","514.75 13:12", "3.25 (0.63%)","920,128"], + ["MNDI.L","Mondi PLC","1,463.00 13:14", "7.00 (0.48%)","383,546"], + ["MRW.L","Morrison (Wm) Supermarkets PLC","155.20 13:14",""], + ["NG.L","National Grid PLC","926.40 13:14", "1.10 (0.12%)","1,659,592"], + ["NXT.L","Next PLC","7,765.00 13:11", "95.00 (1.21%)","114,062"], + ["OML.L","Old Mutual PLC","198.50 13:14", "0.40 (0.20%)","2,040,849"], + ["PRU.L","Prudential PLC","1,499.50 13:15", "14.00 (0.93%)","580,870"], + ["PSON.L","Pearson PLC","794.00 13:09", "5.00 (0.63%)","1,177,953"], + ["RB.L","Reckitt Benckiser Group PLC","6,293.00 13:14", "34.00 (0.54%)","281,172"], + ["RBS.L","Royal Bank of Scotland Group PLC","313.40 13:14", "2.40 (0.77%)","2,100,058"], + ["RDSA.L","Royal Dutch Shell PLC","1,636.00 13:14", "18.00 (1.11%)","2,467,461"], + ["RDSB.L","Royal Dutch Shell PLC","1,652.00 13:15", "14.50 (0.89%)","1,457,434"], + ["REL.L","Reed Elsevier PLC","1,170.00 13:14","0.00 (0.00%)","908,802"], + ["RIO.L","Rio Tinto PLC","2,235.00 13:15", "21.00 (0.95%)","2,190,722"], + ["RMG.L","Royal Mail PLC","453.50 13:14", "1.20 (0.26%)","995,316"], + ["RR.L","Rolls-Royce Group PLC","546.63 13:14", "8.38 (1.51%)","2,792,915"], + ["RRS.L","Randgold Resources Ltd","3,929.00 13:14","0.00 (0.00%)","135,524"], + ["RSA.L","RSA Insurance Group PLC","437.10 13:14", "0.10 (0.02%)","395,477"], + ["SAB.L","SABMiller PLC","4,011.00 13:15", "1.00 (0.02%)","892,451"], + ["SBRY.L","Sainsbury (J) PLC","255.80 13:14", "7.40 (2.98%)","2,395,670"], + ["SDR.L","Schroders PLC","2,930.00 13:09", "12.00 (0.41%)","44,674"], + ["SGE.L","Sage Group (The) PLC","545.50 13:13", "0.50 (0.09%)","539,717"], + ["SHP.L","Shire PLC","4,685.00 13:14", "22.00 (0.47%)","221,318"], + ["SKY.L","SKY","1,095.00 13:12", "4.00 (0.37%)","925,016"], + ["SL.L","Standard Life PLC","399.90 13:14", "3.20 (0.79%)","861,636"], + ["SMIN.L","Smiths Group PLC","992.50 13:14", "27.50 (2.70%)","640,309"], + ["SN.L","Smith & Nephew PLC","1,110.00 13:14", "9.00 (0.82%)","480,018"], + ["SPD.L","Sports Direct International PLC","694.50 13:11", "1.50 (0.22%)","157,981"], + ["SSE.L","SSE PLC","1,463.00 13:13", "2.00 (0.14%)","562,454"], + ["STAN.L","Standard Chartered PLC","583.00 13:14", "0.60 (0.10%)","2,018,697"], + ["STJ.L","St James's Place PLC","964.00 13:14", "11.00 (1.13%)","418,480"], + ["SVT.L","Severn Trent PLC","2,199.00 13:12", "1.00 (0.05%)","95,342"], + ["TPK.L","Travis Perkins PLC","1,945.00 13:13", "4.00 (0.21%)","92,916"], + ["TSCO.L","Tesco PLC","171.54 13:14", "2.54 (1.50%)","9,831,136"], + ["TUI.L","TUI AG","1,115.00 13:10", "5.00 (0.45%)","458,970"], + ["TW.L","Taylor Wimpey PLC","183.90 13:15", "1.10 (0.59%)","3,180,729"], + ["ULVR.L","Unilever PLC","2,791.00 13:14", "29.00 (1.03%)","824,827"], + ["UU.L","United Utilities Group PLC","959.00 13:10", "2.50 (0.26%)","436,911"], + ["VOD.L","Vodafone Group PLC","224.25 13:15", "1.30 (0.58%)","17,572,036"], + ["WOS.L","Wolseley PLC","3,657.00 13:14", "4.00 (0.11%)","179,536"], + ["WPP.L","WPP PLC","1,502.00 13:15", "12.00 (0.79%)","857,887"], + ["WTB.L","Whitbread PLC","4,484.00 13:16", "60.00 (1.32%)","141,036"] +] diff --git a/vuu-ui/packages/vuu-data-test/src/basket/reference-data/index.ts b/vuu-ui/packages/vuu-data-test/src/basket/reference-data/index.ts new file mode 100644 index 000000000..4ece82ad2 --- /dev/null +++ b/vuu-ui/packages/vuu-data-test/src/basket/reference-data/index.ts @@ -0,0 +1,13 @@ +export { default as BasketReferenceData, BasketColumnMap } from "./basket"; +export { + default as BasketConstituentReferenceData, + BasketConstituentColumnMap, +} from "./basketConstituent"; +export { + default as BasketTradingReferenceData, + BasketTradingColumnMap, +} from "./basketTrading"; +export { + default as BasketTradingConstituentReferenceData, + BasketTradingConstituentColumnMap, +} from "./basketTradingConstituent"; diff --git a/vuu-ui/packages/vuu-data-test/src/generatorTemplate.ts b/vuu-ui/packages/vuu-data-test/src/generatorTemplate.ts new file mode 100644 index 000000000..01c76e1a7 --- /dev/null +++ b/vuu-ui/packages/vuu-data-test/src/generatorTemplate.ts @@ -0,0 +1,44 @@ +import { ColumnDescriptor } from "@finos/vuu-datagrid-types"; +import { ColumnMap } from "@finos/vuu-utils"; +import { VuuDataRow } from "@finos/vuu-protocol-types"; +import { ColumnGeneratorFn, RowGeneratorFactory } from "./vuu-row-generator"; +import { getSchema, VuuTableName } from "./schemas"; + +export const getGenerators = ( + tableName: VuuTableName, + columnMap: ColumnMap, + data: VuuDataRow[] +): [RowGeneratorFactory, ColumnGeneratorFn] => [ + (columnNames?: string[]) => (index: number) => { + if (index >= data.length) { + return undefined; + } + if (columnNames) { + return columnNames.map((name) => data[index][columnMap[name]]); + } else { + return data[index].slice(0, 7); + } + }, + + ( + columns = [] + //columnConfig: ExtendedColumnConfig = {} + ) => { + const schema = getSchema(tableName); + const result: ColumnDescriptor[] = schema.columns; + if (typeof columns === "number") { + throw Error(`${tableName}Generator must be passed columns (strings)`); + } else if (columns.length === 0) { + return result; + } else { + return columns.map((name) => { + const column = result.find((col) => col.name === name); + if (column) { + return column; + } else { + throw Error(`${tableName}Generator no column ${name}`); + } + }); + } + }, +]; diff --git a/vuu-ui/packages/vuu-data-test/src/index.ts b/vuu-ui/packages/vuu-data-test/src/index.ts new file mode 100644 index 000000000..da4cd3769 --- /dev/null +++ b/vuu-ui/packages/vuu-data-test/src/index.ts @@ -0,0 +1,2 @@ +export * from "./schemas"; +export * from "./vuu-row-generator"; diff --git a/vuu-ui/showcase/src/examples/utils/rowUpdates.ts b/vuu-ui/packages/vuu-data-test/src/rowUpdates.ts similarity index 94% rename from vuu-ui/showcase/src/examples/utils/rowUpdates.ts rename to vuu-ui/packages/vuu-data-test/src/rowUpdates.ts index 836ca9c23..d430b0e86 100644 --- a/vuu-ui/showcase/src/examples/utils/rowUpdates.ts +++ b/vuu-ui/packages/vuu-data-test/src/rowUpdates.ts @@ -1,5 +1,5 @@ import { VuuRange, VuuRowDataItemType } from "@finos/vuu-protocol-types"; -import { ArrayDataSource } from "packages/vuu-data/src"; +import { ArrayDataSource } from "@finos/vuu-data"; export interface UpdateGenerator { setDataSource: (dataSource: ArrayDataSource) => void; diff --git a/vuu-ui/packages/vuu-data-test/src/schemas.ts b/vuu-ui/packages/vuu-data-test/src/schemas.ts new file mode 100644 index 000000000..79adf5250 --- /dev/null +++ b/vuu-ui/packages/vuu-data-test/src/schemas.ts @@ -0,0 +1,29 @@ +import { TableSchema } from "@finos/vuu-data"; +import { + type BasketsTableName, + schemas as basketSchemas, +} from "./basket/basket-schemas"; +import { + type SimulTableName, + schemas as simulSchemas, +} from "./simul/simul-schemas"; + +export type VuuTableName = BasketsTableName | SimulTableName; +export const schemas: Record = { + ...basketSchemas, + ...simulSchemas, +}; + +const allSchemas: Readonly>> = { + ...basketSchemas, + ...simulSchemas, +}; + +export const getAllSchemas = () => schemas; + +export const getSchema = (tableName: VuuTableName) => { + if (allSchemas[tableName]) { + return allSchemas[tableName]; + } + throw Error(`getSchema no schema for table ${tableName}`); +}; diff --git a/vuu-ui/showcase/src/examples/utils/data-generators/child-order-generator.ts b/vuu-ui/packages/vuu-data-test/src/simul/data-generators/child-order-generator.ts similarity index 82% rename from vuu-ui/showcase/src/examples/utils/data-generators/child-order-generator.ts rename to vuu-ui/packages/vuu-data-test/src/simul/data-generators/child-order-generator.ts index daa712cab..d1af767b5 100644 --- a/vuu-ui/showcase/src/examples/utils/data-generators/child-order-generator.ts +++ b/vuu-ui/packages/vuu-data-test/src/simul/data-generators/child-order-generator.ts @@ -1,7 +1,9 @@ import { ColumnDescriptor } from "@finos/vuu-datagrid-types"; -import { ExtendedColumnConfig } from "../useTableConfig"; -import { ColumnGeneratorFn, RowGeneratorFactory } from "./vuu-row-generator"; -import { schemas } from "../useSchemas"; +import { + ColumnGeneratorFn, + RowGeneratorFactory, +} from "../../vuu-row-generator"; +import { getSchema } from "../../index"; import { currencies, locations, suffixes } from "./generatedData"; function random(min: number, max: number) { @@ -75,12 +77,9 @@ export const RowGenerator: RowGeneratorFactory = () => (index: number) => { ]; }; -export const ColumnGenerator: ColumnGeneratorFn = ( - columns = [], - columnConfig: ExtendedColumnConfig = {} -) => { - console.log({ columnConfig }); - const schemaColumns: ColumnDescriptor[] = schemas.childOrders.columns; +export const ColumnGenerator: ColumnGeneratorFn = (columns = []) => { + const schema = getSchema("childOrders"); + const schemaColumns: ColumnDescriptor[] = schema.columns; if (typeof columns === "number") { throw Error("ChildOrderColumnGenerator must be passed columns (strings)"); } else if (columns.length === 0) { diff --git a/vuu-ui/packages/vuu-data-test/src/simul/data-generators/generate-data-utils.ts b/vuu-ui/packages/vuu-data-test/src/simul/data-generators/generate-data-utils.ts new file mode 100644 index 000000000..0cf067d08 --- /dev/null +++ b/vuu-ui/packages/vuu-data-test/src/simul/data-generators/generate-data-utils.ts @@ -0,0 +1,60 @@ +import { faker } from "@faker-js/faker"; +import { VuuRowDataItemType } from "@finos/vuu-protocol-types"; + +export function createArray(numofrows: number): VuuRowDataItemType[][] { + const result = []; + + for (let i = 0; i < numofrows; i++) { + const FakerDataGenerator = [ + faker.company.name(), + faker.finance.currencyCode(), + Number(faker.finance.amount({ min: 5, max: 10, dec: 2 })), + faker.finance.amount({ min: 100, max: 2000, dec: 0 }), + faker.finance.transactionType(), + faker.finance.transactionDescription(), + faker.date.anytime().getMilliseconds(), + faker.finance.accountName(), + faker.finance.accountNumber(), + faker.commerce.department(), + faker.commerce.product(), + faker.finance.amount({ min: 5, max: 10, dec: 2 }), + faker.finance.amount({ min: 5, max: 10, dec: 2 }), + faker.finance.amount({ min: 5, max: 10, dec: 2 }), + faker.finance.amount({ min: 5, max: 10, dec: 2 }), + faker.finance.amount({ min: 5, max: 10, dec: 2 }), + faker.finance.amount({ min: 5, max: 10, dec: 2 }), + faker.finance.amount({ min: 5, max: 10, dec: 2 }), + faker.finance.amount({ min: 5, max: 10, dec: 2 }), + faker.finance.amount({ min: 5, max: 10, dec: 2 }), + ]; + result.push([ + i + 1, + FakerDataGenerator[0], + FakerDataGenerator[1], + Number(FakerDataGenerator[2]), + FakerDataGenerator[3] as number, + Number( + Math.floor( + Number(FakerDataGenerator[2]) * Number(FakerDataGenerator[3]) + ) + ), + FakerDataGenerator[4], + FakerDataGenerator[5], + FakerDataGenerator[6], + FakerDataGenerator[7], + FakerDataGenerator[8], + FakerDataGenerator[9], + FakerDataGenerator[10], + FakerDataGenerator[11], + FakerDataGenerator[12], + FakerDataGenerator[13], + FakerDataGenerator[14], + FakerDataGenerator[15], + FakerDataGenerator[16], + FakerDataGenerator[17], + Number(FakerDataGenerator[18]), + ]); + } + + return result; +} diff --git a/vuu-ui/showcase/src/examples/utils/data-generators/generatedData.ts b/vuu-ui/packages/vuu-data-test/src/simul/data-generators/generatedData.ts similarity index 100% rename from vuu-ui/showcase/src/examples/utils/data-generators/generatedData.ts rename to vuu-ui/packages/vuu-data-test/src/simul/data-generators/generatedData.ts diff --git a/vuu-ui/showcase/src/examples/utils/data-generators/index.ts b/vuu-ui/packages/vuu-data-test/src/simul/data-generators/index.ts similarity index 58% rename from vuu-ui/showcase/src/examples/utils/data-generators/index.ts rename to vuu-ui/packages/vuu-data-test/src/simul/data-generators/index.ts index 771b51673..b378012d4 100644 --- a/vuu-ui/showcase/src/examples/utils/data-generators/index.ts +++ b/vuu-ui/packages/vuu-data-test/src/simul/data-generators/index.ts @@ -1,7 +1,3 @@ -export * as basket from "./basket-generator"; -export * as basketDefinitions from "./basket-definitions-generator"; -export * as basketDesign from "./basket-design-generator"; -export * as basketOrders from "./basket-orders-generator"; export * as childOrders from "./child-order-generator"; export * as instruments from "./instrument-generator"; export * as instrumentPrices from "./instrument-prices-generator"; diff --git a/vuu-ui/showcase/src/examples/utils/data-generators/instrument-generator.ts b/vuu-ui/packages/vuu-data-test/src/simul/data-generators/instrument-generator.ts similarity index 83% rename from vuu-ui/showcase/src/examples/utils/data-generators/instrument-generator.ts rename to vuu-ui/packages/vuu-data-test/src/simul/data-generators/instrument-generator.ts index 20b080047..609c7eda5 100644 --- a/vuu-ui/showcase/src/examples/utils/data-generators/instrument-generator.ts +++ b/vuu-ui/packages/vuu-data-test/src/simul/data-generators/instrument-generator.ts @@ -1,12 +1,16 @@ import { ColumnDescriptor } from "@finos/vuu-datagrid-types"; -import { ColumnGeneratorFn, RowGeneratorFactory } from "./vuu-row-generator"; -import { schemas } from "../useSchemas"; +import { + ColumnGeneratorFn, + RowGeneratorFactory, +} from "../../vuu-row-generator"; +import { getSchema } from "../../index"; import { InstrumentReferenceData, InstrumentColumnMap, } from "../reference-data"; import { getCalculatedColumnType, isCalculatedColumn } from "@finos/vuu-utils"; -import { ExtendedColumnConfig } from "../useTableConfig"; + +export type ExtendedColumnConfig = { [key: string]: Partial }; export const RowGenerator: RowGeneratorFactory = (columnNames?: string[]) => (index: number) => { @@ -28,7 +32,8 @@ export const ColumnGenerator: ColumnGeneratorFn = ( columns = [], columnConfig: ExtendedColumnConfig = {} ) => { - const instrumentColumns: ColumnDescriptor[] = schemas.instruments.columns; + const schema = getSchema("instruments"); + const instrumentColumns: ColumnDescriptor[] = schema.columns; if (typeof columns === "number") { throw Error("InstrumentColumnGenerator must be passed columns (strings)"); } else if (columns.length === 0) { diff --git a/vuu-ui/showcase/src/examples/utils/data-generators/instrument-prices-generator.ts b/vuu-ui/packages/vuu-data-test/src/simul/data-generators/instrument-prices-generator.ts similarity index 85% rename from vuu-ui/showcase/src/examples/utils/data-generators/instrument-prices-generator.ts rename to vuu-ui/packages/vuu-data-test/src/simul/data-generators/instrument-prices-generator.ts index 33d23d8e6..3059b73cc 100644 --- a/vuu-ui/showcase/src/examples/utils/data-generators/instrument-prices-generator.ts +++ b/vuu-ui/packages/vuu-data-test/src/simul/data-generators/instrument-prices-generator.ts @@ -4,11 +4,14 @@ import { InstrumentPricesColumnMap, InstrumentPricesReferenceData, } from "../reference-data"; -import { BaseUpdateGenerator } from "../UpdateGenerator"; -import { schemas } from "../useSchemas"; -import { ColumnGeneratorFn, RowGeneratorFactory } from "./vuu-row-generator"; +import { BaseUpdateGenerator } from "../../UpdateGenerator"; +import { getSchema } from "../../index"; +import { + ColumnGeneratorFn, + RowGeneratorFactory, +} from "../../vuu-row-generator"; -const { instrumentPrices: instrumentPriceSchema } = schemas; +const instrumentPriceSchema = getSchema("instrumentPrices"); export const RowGenerator: RowGeneratorFactory = (columnNames?: string[]) => (index: number) => { @@ -39,7 +42,7 @@ export const ColumnGenerator: ColumnGeneratorFn = ( //columnConfig: ExtendedColumnConfig = {} ) => { const instrumentPriceColumns: ColumnDescriptor[] = - schemas.instrumentPrices.columns; + instrumentPriceSchema.columns; if (typeof columns === "number") { throw Error( "InstrumentPricesColumnGenerator must be passed columns (strings)" diff --git a/vuu-ui/showcase/src/examples/utils/data-generators/order-generator.ts b/vuu-ui/packages/vuu-data-test/src/simul/data-generators/order-generator.ts similarity index 88% rename from vuu-ui/showcase/src/examples/utils/data-generators/order-generator.ts rename to vuu-ui/packages/vuu-data-test/src/simul/data-generators/order-generator.ts index dad8fbf32..df7389829 100644 --- a/vuu-ui/showcase/src/examples/utils/data-generators/order-generator.ts +++ b/vuu-ui/packages/vuu-data-test/src/simul/data-generators/order-generator.ts @@ -1,7 +1,11 @@ import { ColumnDescriptor } from "@finos/vuu-datagrid-types"; -import { ExtendedColumnConfig } from "../useTableConfig"; -import { ColumnGeneratorFn, RowGeneratorFactory } from "./vuu-row-generator"; -import { schemas } from "../useSchemas"; +import { + ColumnGeneratorFn, + RowGeneratorFactory, +} from "../../vuu-row-generator"; +import { getSchema } from "../../index"; + +export type ExtendedColumnConfig = { [key: string]: Partial }; function random(min: number, max: number) { min = Math.ceil(min); @@ -75,7 +79,8 @@ export const ColumnGenerator: ColumnGeneratorFn = ( columnConfig: ExtendedColumnConfig = {} ) => { console.log({ columnConfig }); - const instrumentColumns: ColumnDescriptor[] = schemas.orders.columns; + const schema = getSchema("orders"); + const instrumentColumns: ColumnDescriptor[] = schema.columns; if (typeof columns === "number") { throw Error("OrderColumnGenerator must be passed columns (strings)"); } else if (columns.length === 0) { diff --git a/vuu-ui/showcase/src/examples/utils/data-generators/parent-order-generator.ts b/vuu-ui/packages/vuu-data-test/src/simul/data-generators/parent-order-generator.ts similarity index 80% rename from vuu-ui/showcase/src/examples/utils/data-generators/parent-order-generator.ts rename to vuu-ui/packages/vuu-data-test/src/simul/data-generators/parent-order-generator.ts index 274ddf143..78c773c1c 100644 --- a/vuu-ui/showcase/src/examples/utils/data-generators/parent-order-generator.ts +++ b/vuu-ui/packages/vuu-data-test/src/simul/data-generators/parent-order-generator.ts @@ -1,7 +1,9 @@ import { ColumnDescriptor } from "@finos/vuu-datagrid-types"; -import { ExtendedColumnConfig } from "../useTableConfig"; -import { ColumnGeneratorFn, RowGeneratorFactory } from "./vuu-row-generator"; -import { schemas } from "../useSchemas"; +import { + ColumnGeneratorFn, + RowGeneratorFactory, +} from "../../vuu-row-generator"; +import { getSchema } from "../../index"; import { currencies, locations, suffixes } from "./generatedData"; function random(min: number, max: number) { @@ -67,12 +69,9 @@ export const RowGenerator: RowGeneratorFactory = () => (index: number) => { ]; }; -export const ColumnGenerator: ColumnGeneratorFn = ( - columns = [], - columnConfig: ExtendedColumnConfig = {} -) => { - console.log({ columnConfig }); - const schemaColumns: ColumnDescriptor[] = schemas.parentOrders.columns; +export const ColumnGenerator: ColumnGeneratorFn = (columns = []) => { + const schema = getSchema("parentOrders"); + const schemaColumns: ColumnDescriptor[] = schema.columns; if (typeof columns === "number") { throw Error("ParentOrderColumnGenerator must be passed columns (strings)"); } else if (columns.length === 0) { diff --git a/vuu-ui/showcase/src/examples/utils/data-generators/prices-generator.ts b/vuu-ui/packages/vuu-data-test/src/simul/data-generators/prices-generator.ts similarity index 72% rename from vuu-ui/showcase/src/examples/utils/data-generators/prices-generator.ts rename to vuu-ui/packages/vuu-data-test/src/simul/data-generators/prices-generator.ts index 11eecc290..223cbf01e 100644 --- a/vuu-ui/showcase/src/examples/utils/data-generators/prices-generator.ts +++ b/vuu-ui/packages/vuu-data-test/src/simul/data-generators/prices-generator.ts @@ -1,10 +1,12 @@ import { ColumnDescriptor } from "@finos/vuu-datagrid-types"; import { buildColumnMap } from "@finos/vuu-utils"; import { PriceReferenceData } from "../reference-data"; -import { schemas } from "../useSchemas"; -import { ExtendedColumnConfig } from "../useTableConfig"; -import { ColumnGeneratorFn, RowGeneratorFactory } from "./vuu-row-generator"; -import { BaseUpdateGenerator } from "../UpdateGenerator"; +import { + ColumnGeneratorFn, + RowGeneratorFactory, +} from "../../vuu-row-generator"; +import { BaseUpdateGenerator } from "../../UpdateGenerator"; +import { getAllSchemas } from "../../index"; export const RowGenerator: RowGeneratorFactory = () => (index: number) => { if (index >= PriceReferenceData.length) { @@ -14,17 +16,14 @@ export const RowGenerator: RowGeneratorFactory = () => (index: number) => { return PriceReferenceData[index]; }; +const schemas = getAllSchemas(); const { prices: pricesSchema } = schemas; const { bid, bidSize, ask, askSize } = buildColumnMap(pricesSchema.columns); const tickingColumns = [bid, bidSize, ask, askSize]; export const createUpdateGenerator = () => new BaseUpdateGenerator(tickingColumns); -export const ColumnGenerator: ColumnGeneratorFn = ( - columns = [], - columnConfig: ExtendedColumnConfig = {} -) => { - console.log({ columnConfig }); +export const ColumnGenerator: ColumnGeneratorFn = (columns = []) => { const schemaColumns: ColumnDescriptor[] = pricesSchema.columns; if (typeof columns === "number") { throw Error("PricesColumnGenerator must be passed columns (strings)"); diff --git a/vuu-ui/packages/vuu-data-test/src/simul/index.ts b/vuu-ui/packages/vuu-data-test/src/simul/index.ts new file mode 100644 index 000000000..e69de29bb diff --git a/vuu-ui/showcase/src/examples/utils/reference-data/currencies.ts b/vuu-ui/packages/vuu-data-test/src/simul/reference-data/currencies.ts similarity index 100% rename from vuu-ui/showcase/src/examples/utils/reference-data/currencies.ts rename to vuu-ui/packages/vuu-data-test/src/simul/reference-data/currencies.ts diff --git a/vuu-ui/packages/vuu-data-test/src/simul/reference-data/index.ts b/vuu-ui/packages/vuu-data-test/src/simul/reference-data/index.ts new file mode 100644 index 000000000..35f607a34 --- /dev/null +++ b/vuu-ui/packages/vuu-data-test/src/simul/reference-data/index.ts @@ -0,0 +1,12 @@ +export * from "./currencies"; +export { + default as InstrumentReferenceData, + InstrumentColumnMap, +} from "./instruments"; +export { + default as InstrumentPricesReferenceData, + InstrumentPricesColumnMap, +} from "./instrument-prices"; +export { default as PriceReferenceData } from "./prices"; +export * from "./locations"; +export * from "./utils"; diff --git a/vuu-ui/showcase/src/examples/utils/reference-data/instrument-prices.ts b/vuu-ui/packages/vuu-data-test/src/simul/reference-data/instrument-prices.ts similarity index 100% rename from vuu-ui/showcase/src/examples/utils/reference-data/instrument-prices.ts rename to vuu-ui/packages/vuu-data-test/src/simul/reference-data/instrument-prices.ts diff --git a/vuu-ui/showcase/src/examples/utils/reference-data/instruments.ts b/vuu-ui/packages/vuu-data-test/src/simul/reference-data/instruments.ts similarity index 100% rename from vuu-ui/showcase/src/examples/utils/reference-data/instruments.ts rename to vuu-ui/packages/vuu-data-test/src/simul/reference-data/instruments.ts diff --git a/vuu-ui/showcase/src/examples/utils/reference-data/locations.ts b/vuu-ui/packages/vuu-data-test/src/simul/reference-data/locations.ts similarity index 100% rename from vuu-ui/showcase/src/examples/utils/reference-data/locations.ts rename to vuu-ui/packages/vuu-data-test/src/simul/reference-data/locations.ts diff --git a/vuu-ui/showcase/src/examples/utils/reference-data/lotsizes.ts b/vuu-ui/packages/vuu-data-test/src/simul/reference-data/lotsizes.ts similarity index 100% rename from vuu-ui/showcase/src/examples/utils/reference-data/lotsizes.ts rename to vuu-ui/packages/vuu-data-test/src/simul/reference-data/lotsizes.ts diff --git a/vuu-ui/showcase/src/examples/utils/reference-data/priceStrategies.ts b/vuu-ui/packages/vuu-data-test/src/simul/reference-data/priceStrategies.ts similarity index 100% rename from vuu-ui/showcase/src/examples/utils/reference-data/priceStrategies.ts rename to vuu-ui/packages/vuu-data-test/src/simul/reference-data/priceStrategies.ts diff --git a/vuu-ui/showcase/src/examples/utils/reference-data/prices.ts b/vuu-ui/packages/vuu-data-test/src/simul/reference-data/prices.ts similarity index 100% rename from vuu-ui/showcase/src/examples/utils/reference-data/prices.ts rename to vuu-ui/packages/vuu-data-test/src/simul/reference-data/prices.ts diff --git a/vuu-ui/showcase/src/examples/utils/reference-data/utils.ts b/vuu-ui/packages/vuu-data-test/src/simul/reference-data/utils.ts similarity index 100% rename from vuu-ui/showcase/src/examples/utils/reference-data/utils.ts rename to vuu-ui/packages/vuu-data-test/src/simul/reference-data/utils.ts diff --git a/vuu-ui/packages/vuu-data-test/src/simul/simul-schemas.ts b/vuu-ui/packages/vuu-data-test/src/simul/simul-schemas.ts new file mode 100644 index 000000000..b15bab971 --- /dev/null +++ b/vuu-ui/packages/vuu-data-test/src/simul/simul-schemas.ts @@ -0,0 +1,137 @@ +import type { TableSchema } from "@finos/vuu-data"; +import type { ColumnDescriptor } from "@finos/vuu-datagrid-types"; + +export type SimulTableName = + | "instruments" + | "instrumentPrices" + | "orders" + | "childOrders" + | "parentOrders" + | "prices"; + +// These Schemas take the form of the schemas that we create +// with TABLE_META returned by Vuu. +export const schemas: Readonly>> = + { + instruments: { + columns: [ + { name: "bbg", serverDataType: "string" }, + { name: "currency", serverDataType: "string" }, + { name: "description", serverDataType: "string" }, + { name: "exchange", serverDataType: "string" }, + { name: "isin", serverDataType: "string" }, + { name: "lotSize", serverDataType: "int" }, + { name: "ric", serverDataType: "string" }, + ], + key: "ric", + table: { module: "SIMUL", table: "instruments" }, + }, + instrumentPrices: { + columns: [ + { name: "ask", serverDataType: "double" }, + { name: "askSize", serverDataType: "double" }, // type: "int" + { name: "bbg", serverDataType: "string" }, + { name: "bid", serverDataType: "double" }, + { name: "bidSize", serverDataType: "double" }, + { name: "close", serverDataType: "double" }, + { name: "currency", serverDataType: "string" }, + { name: "description", serverDataType: "string" }, + { name: "exchange", serverDataType: "string" }, + { name: "isin", serverDataType: "string" }, + { name: "last", serverDataType: "double" }, + { name: "lotSize", serverDataType: "int" }, + { name: "open", serverDataType: "double" }, + { name: "phase", serverDataType: "string" }, + { name: "ric", serverDataType: "string" }, + { name: "scenario", serverDataType: "string" }, + ], + key: "ric", + table: { module: "SIMUL", table: "instrumentPrices" }, + }, + orders: { + columns: [ + { name: "ccy", serverDataType: "string" }, + { name: "created", serverDataType: "long" }, + { name: "filledQuantity", serverDataType: "double" }, + { name: "lastUpdate", serverDataType: "long" }, + { name: "orderId", serverDataType: "string" }, + { name: "quantity", serverDataType: "double" }, + { name: "ric", serverDataType: "string" }, + { name: "side", serverDataType: "string" }, + { name: "trader", serverDataType: "string" }, + ], + key: "orderId", + table: { module: "SIMUL", table: "orders" }, + }, + childOrders: { + columns: [ + { name: "account", serverDataType: "string" }, + { name: "averagePrice", serverDataType: "double" }, + { name: "ccy", serverDataType: "string" }, + { name: "exchange", serverDataType: "string" }, + { name: "filledQty", serverDataType: "double" }, + { name: "id", serverDataType: "string" }, + { name: "idAsInt", serverDataType: "int" }, + { name: "lastUpdate", serverDataType: "long" }, + { name: "openQty", serverDataType: "double" }, + { name: "parentOrderId", serverDataType: "string" }, + { name: "price", serverDataType: "double" }, + { name: "quantity", serverDataType: "double" }, + { name: "ric", serverDataType: "string" }, + { name: "side", serverDataType: "string" }, + { name: "status", serverDataType: "string" }, + { name: "strategy", serverDataType: "string" }, + { name: "volLimit", serverDataType: "int" }, + ], + key: "id", + table: { module: "SIMUL", table: "childOrders" }, + }, + parentOrders: { + columns: [ + { name: "account", serverDataType: "string" }, + { name: "algo", serverDataType: "string" }, + { name: "averagePrice", serverDataType: "double" }, + { name: "ccy", serverDataType: "string" }, + { name: "childCount", serverDataType: "int" }, + { name: "exchange", serverDataType: "string" }, + { name: "filledQty", serverDataType: "double" }, + { name: "id", serverDataType: "string" }, + { name: "idAsInt", serverDataType: "int" }, + { name: "lastUpdate", serverDataType: "long" }, + { name: "openQty", serverDataType: "double" }, + { name: "price", serverDataType: "double" }, + { name: "quantity", serverDataType: "double" }, + { name: "ric", serverDataType: "string" }, + { name: "side", serverDataType: "string" }, + { name: "status", serverDataType: "string" }, + { name: "volLimit", serverDataType: "int" }, + ], + key: "id", + table: { module: "SIMUL", table: "parentOrders" }, + }, + prices: { + columns: [ + { name: "ask", serverDataType: "double" }, + { name: "askSize", serverDataType: "double" }, // type: "int" + { name: "bid", serverDataType: "double" }, + { name: "bidSize", serverDataType: "double" }, + { name: "close", serverDataType: "double" }, + { name: "last", serverDataType: "double" }, + { name: "open", serverDataType: "double" }, + { name: "phase", serverDataType: "string" }, + { name: "ric", serverDataType: "string" }, + { name: "scenario", serverDataType: "string" }, + ], + key: "ric", + table: { module: "SIMUL", table: "prices" }, + }, + }; + +export type ColumnState = { [key: string]: TableSchema }; + +export interface ColumnActionUpdate { + type: "updateColumn"; + column: ColumnDescriptor; +} + +export type ColumnAction = ColumnActionUpdate; diff --git a/vuu-ui/showcase/src/examples/utils/data-generators/vuu-row-generator.ts b/vuu-ui/packages/vuu-data-test/src/vuu-row-generator.ts similarity index 60% rename from vuu-ui/showcase/src/examples/utils/data-generators/vuu-row-generator.ts rename to vuu-ui/packages/vuu-data-test/src/vuu-row-generator.ts index 1c8f0c0eb..3468f64c1 100644 --- a/vuu-ui/showcase/src/examples/utils/data-generators/vuu-row-generator.ts +++ b/vuu-ui/packages/vuu-data-test/src/vuu-row-generator.ts @@ -1,8 +1,10 @@ import { ColumnDescriptor } from "@finos/vuu-datagrid-types"; import { VuuRowDataItemType, VuuTable } from "@finos/vuu-protocol-types"; -import { RowAtIndexFunc } from "../ArrayProxy"; -import * as dataGenerators from "."; -import { UpdateGenerator } from "../rowUpdates"; +import * as simulDataGenerators from "./simul/data-generators"; +import * as basketDataGenerators from "./basket/data-generators"; +import { UpdateGenerator } from "./rowUpdates"; + +type RowAtIndexFunc = (index: number) => T | undefined; export const VuuColumnGenerator = (columnCount: number): string[] => ["Row No"].concat( @@ -49,7 +51,7 @@ export const DefaultColumnGenerator: ColumnGeneratorFn = ( const defaultGenerators = { ColumnGenerator: DefaultColumnGenerator, - RowGeneratorFactory: DefaultRowGenerator, + RowGenerator: DefaultRowGenerator, }; export const getColumnAndRowGenerator = ( @@ -60,16 +62,31 @@ export const getColumnAndRowGenerator = ( const tableName = table?.table ?? ""; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - if (table?.table && dataGenerators[table?.table] === undefined) { - throw Error( - `vuu-row-gererator table ${table.table} was requested but no generator is registered` - ); + switch (table?.module) { + case "SIMUL": { + const { ColumnGenerator, RowGenerator, createUpdateGenerator } = + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + simulDataGenerators[tableName] ?? defaultGenerators; + return [ColumnGenerator, RowGenerator, createUpdateGenerator]; + } + + case "BASKET": { + const { ColumnGenerator, RowGenerator, createUpdateGenerator } = + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + basketDataGenerators[tableName] ?? defaultGenerators; + return [ColumnGenerator, RowGenerator, createUpdateGenerator]; + } + case undefined: { + const { ColumnGenerator, RowGenerator } = defaultGenerators; + return [ColumnGenerator, RowGenerator]; + } + default: + throw Error( + `vuu-row-gererator table ${table?.table} was requested but no generator is registered` + ); } - const { ColumnGenerator, RowGenerator, createUpdateGenerator } = - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - dataGenerators[tableName] ?? defaultGenerators; - return [ColumnGenerator, RowGenerator, createUpdateGenerator]; }; export const populateArray = ( @@ -82,7 +99,12 @@ export const populateArray = ( const generateRow = rowGen(columnDescriptors.map((col) => col.name)); const data: Array = []; for (let i = 0; i < count; i++) { - data[i] = generateRow(i) as VuuRowDataItemType[]; + const row = generateRow(i); + if (row) { + data[i] = row; + } else { + break; + } } return data; }; diff --git a/vuu-ui/packages/vuu-data-test/tsconfig.json b/vuu-ui/packages/vuu-data-test/tsconfig.json new file mode 100644 index 000000000..db9582a16 --- /dev/null +++ b/vuu-ui/packages/vuu-data-test/tsconfig.json @@ -0,0 +1,6 @@ +{ +"extends": "../../tsconfig.json", +"compilerOptions":{ + "composite": true +}, +} diff --git a/vuu-ui/packages/vuu-data-types/tsconfig.json b/vuu-ui/packages/vuu-data-types/tsconfig.json new file mode 100644 index 000000000..db9582a16 --- /dev/null +++ b/vuu-ui/packages/vuu-data-types/tsconfig.json @@ -0,0 +1,6 @@ +{ +"extends": "../../tsconfig.json", +"compilerOptions":{ + "composite": true +}, +} diff --git a/vuu-ui/packages/vuu-data/src/array-data-source/array-data-source.ts b/vuu-ui/packages/vuu-data/src/array-data-source/array-data-source.ts index 000079217..82262beec 100644 --- a/vuu-ui/packages/vuu-data/src/array-data-source/array-data-source.ts +++ b/vuu-ui/packages/vuu-data/src/array-data-source/array-data-source.ts @@ -16,6 +16,8 @@ import { buildColumnMap, ColumnMap, EventEmitter, + getAddedItems, + getMissingItems, getSelectionStatus, KeySet, logger, @@ -57,7 +59,6 @@ export interface ArrayDataSourceConstructorProps data: Array; rangeChangeRowset?: "delta" | "full"; } - const { debug } = logger("ArrayDataSource"); const { RENDER_IDX, SELECTED } = metadataKeys; @@ -148,6 +149,10 @@ export class ArrayDataSource }: ArrayDataSourceConstructorProps) { super(); + console.log(`ArrayDataSource`, { + columnDescriptors, + }); + if (!data || !columnDescriptors) { throw Error( "ArrayDataSource constructor called without data or without columnDescriptors" @@ -196,34 +201,41 @@ export class ArrayDataSource this.status = "subscribed"; this.lastRangeServed = { from: 0, to: 0 }; - if (aggregations || columns || filter || groupBy || sort) { + let config = this.#config; + + const hasConfigProps = aggregations || columns || filter || groupBy || sort; + if (hasConfigProps) { if (range) { this.#range = range; } - this.config = { - ...this.#config, + config = { + ...config, aggregations: aggregations || this.#config.aggregations, columns: columns || this.#config.columns, filter: filter || this.#config.filter, groupBy: groupBy || this.#config.groupBy, sort: sort || this.#config.sort, }; - } else { - this.clientCallback?.({ - ...this.#config, - type: "subscribed", - clientViewportId: this.viewport, - range: this.#range, - tableSchema: this.tableSchema, - }); + } + this.clientCallback?.({ + ...config, + type: "subscribed", + clientViewportId: this.viewport, + range: this.#range, + tableSchema: this.tableSchema, + }); + + if (hasConfigProps) { + // invoke setter to action config + this.config = config; + } else { this.clientCallback({ clientViewportId: this.viewport, mode: "size-only", type: "viewport-update", size: this.#data.length, }); - if (range) { // set range and trigger dispatch of initial rows this.range = range; @@ -293,6 +305,10 @@ export class ArrayDataSource return this.processedData ?? this.#data; } + get table() { + return this.tableSchema.table; + } + get config() { return this.#config; } @@ -434,6 +450,17 @@ export class ArrayDataSource } set columns(columns: string[]) { + const addedColumns = getAddedItems(this.config.columns, columns); + if (addedColumns.length > 0) { + const columnsWithoutDescriptors = getMissingItems( + this.columnDescriptors, + addedColumns, + (col) => col.name + ); + console.log(`columnsWithoutDescriptors`, { + columnsWithoutDescriptors, + }); + } this.config = { ...this.#config, columns, @@ -550,8 +577,8 @@ export class ArrayDataSource console.log({ row, colName, value }); } - applyEdit(rowIndex: number, columnName: string, value: VuuColumnDataType) { - console.log(`ArrayDataSource applyEdit ${rowIndex} ${columnName} ${value}`); + applyEdit(row: DataSourceRow, columnName: string, value: VuuColumnDataType) { + console.log(`ArrayDataSource applyEdit ${row[0]} ${columnName} ${value}`); return true; } diff --git a/vuu-ui/packages/vuu-data/src/connection-manager.ts b/vuu-ui/packages/vuu-data/src/connection-manager.ts index ce9d3b15b..086cc3763 100644 --- a/vuu-ui/packages/vuu-data/src/connection-manager.ts +++ b/vuu-ui/packages/vuu-data/src/connection-manager.ts @@ -164,6 +164,7 @@ function handleMessageFromWorker({ } else if (isConnectionStatusMessage(message)) { ConnectionManager.emit("connection-status", message); } else if (isConnectionQualityMetrics(message)) { + console.log({ message }); ConnectionManager.emit("connection-metrics", message); } else { const requestId = (message as VuuUIMessageInRPC).requestId; diff --git a/vuu-ui/packages/vuu-data/src/data-source.ts b/vuu-ui/packages/vuu-data/src/data-source.ts index ca8ac416b..6e5b083d4 100644 --- a/vuu-ui/packages/vuu-data/src/data-source.ts +++ b/vuu-ui/packages/vuu-data/src/data-source.ts @@ -212,7 +212,7 @@ const equivalentColumns: DataConfigPredicate = ( (cols1 === undefined && cols2?.length === 0) || (cols2 === undefined && cols1?.length === 0); -const columnsChanged: DataConfigPredicate = (config, newConfig) => { +export const columnsChanged: DataConfigPredicate = (config, newConfig) => { const { columns: cols1 } = config; const { columns: cols2 } = newConfig; @@ -475,11 +475,18 @@ export type DataSourceEvents = { }; export type DataSourceEditHandler = ( - rowIndex: number, + row: DataSourceRow, columnName: string, value: VuuColumnDataType ) => boolean; +export type RpcResponse = + | MenuRpcResponse + | VuuUIMessageInRPCEditReject + | VuuUIMessageInRPCEditResponse; + +export type RpcResponseHandler = (response: RpcResponse) => boolean; + export interface DataSource extends EventEmitter { aggregations: VuuAggregation[]; applyEdit: DataSourceEditHandler; @@ -494,12 +501,7 @@ export interface DataSource extends EventEmitter { groupBy: VuuGroupBy; menuRpcCall: ( rpcRequest: Omit | ClientToServerEditRpc - ) => Promise< - | MenuRpcResponse - | VuuUIMessageInRPCEditReject - | VuuUIMessageInRPCEditResponse - | undefined - >; + ) => Promise; openTreeNode: (key: string) => void; range: VuuRange; select: SelectionChangeHandler; @@ -510,6 +512,7 @@ export interface DataSource extends EventEmitter { props: SubscribeProps, callback: SubscribeCallback ) => Promise; + table?: VuuTable; title?: string; unsubscribe: () => void; viewport?: string; diff --git a/vuu-ui/packages/vuu-data/src/inlined-worker.js b/vuu-ui/packages/vuu-data/src/inlined-worker.js new file mode 100644 index 000000000..c9900c37e --- /dev/null +++ b/vuu-ui/packages/vuu-data/src/inlined-worker.js @@ -0,0 +1,8 @@ +export const workerSourceCode = ` +var fe=(s,e,t)=>{if(!e.has(s))throw TypeError("Cannot "+t)};var p=(s,e,t)=>(fe(s,e,"read from private field"),t?t.call(s):e.get(s)),U=(s,e,t)=>{if(e.has(s))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(s):e.set(s,t)},me=(s,e,t,n)=>(fe(s,e,"write to private field"),n?n.call(s,t):e.set(s,t),t);function he(s,e,t=[],n=[]){for(let r=0,o=s.length;r{var e,t;if(((e=globalThis.document)==null?void 0:e.cookie)!==void 0)return(t=globalThis.document.cookie.split("; ").find(n=>n.startsWith(\`\${s}=\`)))==null?void 0:t.split("=")[1]};function Y({from:s,to:e},t=0,n=Number.MAX_SAFE_INTEGER){if(t===0)return ns>=e&&s=this.to||ttypeof s=="string"&&ct.includes(s),dt="error",F=()=>{},gt="error",{loggingLevel:N=gt}=ft(),w=s=>{let e=N==="debug",t=e||N==="info",n=t||N==="warn",r=n||N==="error",o=t?g=>console.info(\`[\${s}] \${g}\`):F,a=n?g=>console.warn(\`[\${s}] \${g}\`):F,u=e?g=>console.debug(\`[\${s}] \${g}\`):F;return{errorEnabled:r,error:r?g=>console.error(\`[\${s}] \${g}\`):F}};function ft(){return typeof loggingSettings<"u"?loggingSettings:{loggingLevel:mt()}}function mt(){let s=be("vuu-logging-level");return pt(s)?s:dt}var{debug:ht,debugEnabled:bt}=w("range-monitor"),W=class{constructor(e){this.source=e;this.range={from:0,to:0};this.timestamp=0}isSet(){return this.timestamp!==0}set({from:e,to:t}){let{timestamp:n}=this;if(this.range.from=e,this.range.to=t,this.timestamp=performance.now(),n)bt&&ht(\`<\${this.source}> [\${e}-\${t}], \${(this.timestamp-n).toFixed(0)} ms elapsed\`);else return 0}};function Ce(s){return Array.isArray(s)}function Ct(s){return!Array.isArray(s)}var y,ye=class{constructor(){U(this,y,new Map)}addListener(e,t){let n=p(this,y).get(e);n?Ce(n)?n.push(t):Ct(n)&&p(this,y).set(e,[n,t]):p(this,y).set(e,t)}removeListener(e,t){if(!p(this,y).has(e))return;let n=p(this,y).get(e),r=-1;if(n===t)p(this,y).delete(e);else if(Array.isArray(n)){for(let o=length;o-- >0;)if(n[o]===t){r=o;break}if(r<0)return;n.length===1?(n.length=0,p(this,y).delete(e)):n.splice(r,1)}}removeAllListeners(e){e&&p(this,y).has(e)?p(this,y).delete(e):e===void 0&&p(this,y).clear()}emit(e,...t){if(p(this,y)){let n=p(this,y).get(e);n&&this.invokeHandler(n,t)}}once(e,t){let n=(...r)=>{this.removeListener(e,n),t(...r)};this.on(e,n)}on(e,t){this.addListener(e,t)}hasListener(e,t){let n=p(this,y).get(e);return Array.isArray(n)?n.includes(t):n===t}invokeHandler(e,t){if(Ce(e))e.slice().forEach(n=>this.invokeHandler(n,t));else switch(t.length){case 0:e();break;case 1:e(t[0]);break;case 2:e(t[0],t[1]);break;default:e.call(null,...t)}}};y=new WeakMap;var \$=String.fromCharCode(8200),m=String.fromCharCode(8199);var wn={DIGIT:m,TWO_DIGITS:m+m,THREE_DIGITS:m+m+m,FULL_PADDING:[null,\$+m,\$+m+m,\$+m+m+m,\$+m+m+m+m]};var En=m+m+m+m+m+m+m+m+m;var{COUNT:Bn}=x;var q=class{constructor(e){this.keys=new Map,this.free=[],this.nextKeyValue=0,this.reset(e)}next(){return this.free.length>0?this.free.pop():this.nextKeyValue++}reset({from:e,to:t}){this.keys.forEach((r,o)=>{(o=t)&&(this.free.push(r),this.keys.delete(o))});let n=t-e;this.keys.size+this.free.length>n&&(this.free.length=Math.max(0,n-this.keys.size));for(let r=e;rthis.keys.size&&(this.nextKeyValue=this.keys.size)}keyFor(e){let t=this.keys.get(e);if(t===void 0)throw console.log(\`key not found + keys: \${this.toDebugString()} + free : \${this.free.join(",")} + \`),Error(\`KeySet, no key found for rowIndex \${e}\`);return t}toDebugString(){return Array.from(this.keys.entries()).map((e,t)=>\`\${e}=>\${t}\`).join(",")}};var{IDX:Zn}=x;var{SELECTED:er}=x,I={False:0,True:1,First:2,Last:4};var yt=(s,e)=>e>=s[0]&&e<=s[1],St=I.True+I.First+I.Last,Tt=I.True+I.First,Rt=I.True+I.Last,Z=(s,e)=>{for(let t of s)if(typeof t=="number"){if(t===e)return St}else if(yt(t,e))return e===t[0]?Tt:e===t[1]?Rt:I.True;return I.False};var Se=s=>{if(s.every(t=>typeof t=="number"))return s;let e=[];for(let t of s)if(typeof t=="number")e.push(t);else for(let n=t[0];n<=t[1];n++)e.push(n);return e};var wt=(()=>{let s=0,e=()=>\`0000\${(Math.random()*36**4<<0).toString(36)}\`.slice(-4);return()=>(s+=1,\`u\${e()}\${s}\`)})();var{debug:ks,debugEnabled:As,error:we,info:V,infoEnabled:It,warn:_}=w("websocket-connection"),Ee="ws",vt=s=>s.startsWith(Ee+"://")||s.startsWith(Ee+"s://"),xe={},ee=Symbol("setWebsocket"),B=Symbol("connectionCallback");async function Ie(s,e,t,n=10,r=5){return xe[s]={status:"connecting",connect:{allowed:r,remaining:r},reconnect:{allowed:n,remaining:n}},ve(s,e,t)}async function Q(s){throw Error("connection broken")}async function ve(s,e,t,n){let{status:r,connect:o,reconnect:a}=xe[s],u=r==="connecting"?o:a;try{t({type:"connection-status",status:"connecting"});let c=typeof n<"u",g=await _t(s,e);console.info("%c\u26A1 %cconnected","font-size: 24px;color: green;font-weight: bold;","color:green; font-size: 14px;"),n!==void 0&&n[ee](g);let i=n!=null?n:new te(g,s,e,t),l=c?"reconnected":"connection-open-awaiting-session";return t({type:"connection-status",status:l}),i.status=l,u.remaining=u.allowed,i}catch{let g=--u.remaining>0;if(t({type:"connection-status",status:"disconnected",reason:"failed to connect",retry:g}),g)return Dt(s,e,t,n,2e3);throw Error("Failed to establish connection")}}var Dt=(s,e,t,n,r)=>new Promise(o=>{setTimeout(()=>{o(ve(s,e,t,n))},r)}),_t=(s,e)=>new Promise((t,n)=>{let r=vt(s)?s:\`wss://\${s}\`;It&&e!==void 0&&V(\`WebSocket Protocol \${e==null?void 0:e.toString()}\`);let o=new WebSocket(r,e);o.onopen=()=>t(o),o.onerror=a=>n(a)}),Ve=()=>{_==null||_("Connection cannot be closed, socket not yet opened")},Me=s=>{_==null||_(\`Message cannot be sent, socket closed \${s.body.type}\`)},Pt=s=>{try{return JSON.parse(s)}catch{throw Error(\`Error parsing JSON response from server \${s}\`)}},te=class{constructor(e,t,n,r){this.close=Ve;this.requiresLogin=!0;this.send=Me;this.status="ready";this.messagesCount=0;this.connectionMetricsInterval=null;this.handleWebsocketMessage=e=>{let t=Pt(e.data);this.messagesCount+=1,this[B](t)};this.url=t,this.protocol=n,this[B]=r,this[ee](e)}reconnect(){Q(this)}[(B,ee)](e){let t=this[B];e.onmessage=o=>{this.status="connected",e.onmessage=this.handleWebsocketMessage,this.handleWebsocketMessage(o)},this.connectionMetricsInterval=setInterval(()=>{t({type:"connection-metrics",messagesLength:this.messagesCount}),this.messagesCount=0},2e3),e.onerror=()=>{we("\u26A1 connection error"),t({type:"connection-status",status:"disconnected",reason:"error"}),this.connectionMetricsInterval&&(clearInterval(this.connectionMetricsInterval),this.connectionMetricsInterval=null),this.status==="connection-open-awaiting-session"?we("Websocket connection lost before Vuu session established, check websocket configuration"):this.status!=="closed"&&(Q(this),this.send=r)},e.onclose=()=>{V==null||V("\u26A1 connection close"),t({type:"connection-status",status:"disconnected",reason:"close"}),this.connectionMetricsInterval&&(clearInterval(this.connectionMetricsInterval),this.connectionMetricsInterval=null),this.status!=="closed"&&(Q(this),this.send=r)};let n=o=>{e.send(JSON.stringify(o))},r=o=>{V==null||V(\`TODO queue message until websocket reconnected \${o.body.type}\`)};this.send=n,this.close=()=>{this.status="closed",e.close(),this.close=Ve,this.send=Me,V==null||V("close websocket")}}};var Lt=["VIEW_PORT_MENUS_SELECT_RPC","VIEW_PORT_MENU_TABLE_RPC","VIEW_PORT_MENU_ROW_RPC","VIEW_PORT_MENU_CELL_RPC","VP_EDIT_CELL_RPC","VP_EDIT_ROW_RPC","VP_EDIT_ADD_ROW_RPC","VP_EDIT_DELETE_CELL_RPC","VP_EDIT_DELETE_ROW_RPC","VP_EDIT_SUBMIT_FORM_RPC"],De=s=>Lt.includes(s.type),ne=({requestId:s,...e})=>[s,e],_e=s=>{let e=s.at(0);if(e.updateType==="SIZE"){if(s.length===1)return s;e=s.at(1)}let t=s.at(-1);return[e,t]},Pe=s=>{let e={};for(let t of s)(e[t.viewPortId]||(e[t.viewPortId]=[])).push(t);return e};var re=({columns:s,dataTypes:e,key:t,table:n})=>({table:n,columns:s.map((r,o)=>({name:r,serverDataType:e[o]})),key:t});var Le=s=>s.type==="connection-status",Oe=s=>s.type==="connection-metrics";var ke=s=>"viewport"in s,Ae=s=>s.type==="VIEW_PORT_MENU_RESP"&&s.action!==null&&G(s.action.table),G=s=>s!==null&&typeof s=="object"&&"table"in s&&"module"in s?s.table.startsWith("session"):!1;var Ue="CHANGE_VP_SUCCESS",Fe="CHANGE_VP_RANGE_SUCCESS",Ne="CLOSE_TREE_NODE",We="CLOSE_TREE_SUCCESS";var \$e="CREATE_VP",qe="CREATE_VP_SUCCESS",Be="DISABLE_VP",Ge="DISABLE_VP_SUCCESS";var Ke="ENABLE_VP",He="ENABLE_VP_SUCCESS";var se="GET_VP_VISUAL_LINKS",je="GET_VIEW_PORT_MENUS";var ze="HB",Je="HB_RESP",Ye="LOGIN",Ze="LOGIN_SUCCESS",Xe="OPEN_TREE_NODE",Qe="OPEN_TREE_SUCCESS";var et="REMOVE_VP";var oe="RPC_RESP";var tt="SET_SELECTION_SUCCESS",ie="TABLE_META_RESP",ae="TABLE_LIST_RESP",nt="TABLE_ROW";var st=s=>{switch(s){case"TypeAheadRpcHandler":return"TYPEAHEAD";default:return"SIMUL"}};var ot=[],T=w("array-backed-moving-window");function Ot(s,e){if(!e||e.data.length!==s.data.length||e.sel!==s.sel)return!1;for(let t=0;t{var t;if((t=T.info)==null||t.call(T,\`setRowCount \${e}\`),e{let n=this.bufferSize*.25;return p(this,h).to-t0&&e-p(this,h).from0&&this.clientRange.from+this.rowsWithinRange===this.rowCount}outOfRange(e,t){let{from:n,to:r}=this.range;if(t=r)return!0}setAtIndex(e){let{rowIndex:t}=e,n=t-p(this,h).from;if(Ot(e,this.internalData[n]))return!1;let r=this.isWithinClientRange(t);return(r||this.isWithinRange(t))&&(!this.internalData[n]&&r&&(this.rowsWithinRange+=1),this.internalData[n]=e),r}getAtIndex(e){return p(this,h).isWithin(e)&&this.internalData[e-p(this,h).from]!=null?this.internalData[e-p(this,h).from]:void 0}isWithinRange(e){return p(this,h).isWithin(e)}isWithinClientRange(e){return this.clientRange.isWithin(e)}setClientRange(e,t){var g;(g=T.debug)==null||g.call(T,\`setClientRange \${e} - \${t}\`);let n=this.clientRange.from,r=Math.min(this.clientRange.to,this.rowCount);if(e===n&&t===r)return[!1,ot];let o=this.clientRange.copy();this.clientRange.from=e,this.clientRange.to=t,this.rowsWithinRange=0;for(let i=e;io.to){let i=Math.max(e,o.to);a=this.internalData.slice(i-u,t-u)}else{let i=Math.min(o.from,t);a=this.internalData.slice(e-u,i-u)}return[this.bufferBreakout(e,t),a]}setRange(e,t){var n,r;if(e!==p(this,h).from||t!==p(this,h).to){(n=T.debug)==null||n.call(T,\`setRange \${e} - \${t}\`);let[o,a]=p(this,h).overlap(e,t),u=new Array(t-e);this.rowsWithinRange=0;for(let c=o;c=0;o--)if(e[o]!==void 0){r=e[o];break}return n&&r?[n.rowIndex,r.rowIndex]:[-1,-1]}};h=new WeakMap;var kt=[],{debug:b,debugEnabled:H,error:At,info:d,infoEnabled:Ut,warn:P}=w("viewport"),Ft=({rowKey:s,updateType:e})=>e==="U"&&!s.startsWith("\$root"),j=[void 0,void 0],Nt={count:0,mode:void 0,size:0,ts:0},z=class{constructor({aggregations:e,bufferSize:t=50,columns:n,filter:r,groupBy:o=[],table:a,range:u,sort:c,title:g,viewport:i,visualLink:l},f){this.batchMode=!0;this.hasUpdates=!1;this.pendingUpdates=[];this.pendingOperations=new Map;this.pendingRangeRequests=[];this.rowCountChanged=!1;this.selectedRows=[];this.tableSchema=null;this.useBatchMode=!0;this.lastUpdateStatus=Nt;this.updateThrottleTimer=void 0;this.rangeMonitor=new W("ViewPort");this.disabled=!1;this.isTree=!1;this.status="";this.suspended=!1;this.suspendTimer=null;this.setLastSizeOnlyUpdateSize=e=>{this.lastUpdateStatus.size=e};this.setLastUpdate=e=>{let{ts:t,mode:n}=this.lastUpdateStatus,r=0;if(n===e){let o=Date.now();this.lastUpdateStatus.count+=1,this.lastUpdateStatus.ts=o,r=t===0?0:o-t}else this.lastUpdateStatus.count=1,this.lastUpdateStatus.ts=0,r=0;return this.lastUpdateStatus.mode=e,r};this.rangeRequestAlreadyPending=e=>{let{bufferSize:t}=this,n=t*.25,{from:r}=e;for(let{from:o,to:a}of this.pendingRangeRequests)if(r>=o&&r{this.updateThrottleTimer=void 0,this.lastUpdateStatus.count=3,this.postMessageToClient({clientViewportId:this.clientViewportId,mode:"size-only",size:this.lastUpdateStatus.size,type:"viewport-update"})};this.shouldThrottleMessage=e=>{let t=this.setLastUpdate(e);return e==="size-only"&&t>0&&t<500&&this.lastUpdateStatus.count>3};this.throttleMessage=e=>this.shouldThrottleMessage(e)?(d==null||d("throttling updates setTimeout to 2000"),this.updateThrottleTimer===void 0&&(this.updateThrottleTimer=setTimeout(this.sendThrottledSizeMessage,2e3)),!0):(this.updateThrottleTimer!==void 0&&(clearTimeout(this.updateThrottleTimer),this.updateThrottleTimer=void 0),!1);this.getNewRowCount=()=>{if(this.rowCountChanged&&this.dataWindow)return this.rowCountChanged=!1,this.dataWindow.rowCount};this.aggregations=e,this.bufferSize=t,this.clientRange=u,this.clientViewportId=i,this.columns=n,this.filter=r,this.groupBy=o,this.keys=new q(u),this.pendingLinkedParent=l,this.table=a,this.sort=c,this.title=g,Ut&&(d==null||d(\`constructor #\${i} \${a.table} bufferSize=\${t}\`)),this.dataWindow=new K(this.clientRange,u,this.bufferSize),this.postMessageToClient=f}get hasUpdatesToProcess(){return this.suspended?!1:this.rowCountChanged||this.hasUpdates}get size(){var e;return(e=this.dataWindow.rowCount)!=null?e:0}subscribe(){let{filter:e}=this.filter;return this.status=this.status==="subscribed"?"resubscribing":"subscribing",{type:\$e,table:this.table,range:Y(this.clientRange,this.bufferSize),aggregations:this.aggregations,columns:this.columns,sort:this.sort,groupBy:this.groupBy,filterSpec:{filter:e}}}handleSubscribed({viewPortId:e,aggregations:t,columns:n,filterSpec:r,range:o,sort:a,groupBy:u}){return this.serverViewportId=e,this.status="subscribed",this.aggregations=t,this.columns=n,this.groupBy=u,this.isTree=u&&u.length>0,this.dataWindow.setRange(o.from,o.to),{aggregations:t,type:"subscribed",clientViewportId:this.clientViewportId,columns:n,filter:r,groupBy:u,range:o,sort:a,tableSchema:this.tableSchema}}awaitOperation(e,t){this.pendingOperations.set(e,t)}completeOperation(e,...t){var u;let{clientViewportId:n,pendingOperations:r}=this,o=r.get(e);if(!o){At("no matching operation found to complete");return}let{type:a}=o;if(d==null||d(\`completeOperation \${a}\`),r.delete(e),a==="CHANGE_VP_RANGE"){let[c,g]=t;(u=this.dataWindow)==null||u.setRange(c,g);for(let i=this.pendingRangeRequests.length-1;i>=0;i--){let l=this.pendingRangeRequests[i];if(l.requestId===e){l.acked=!0;break}else P==null||P("range requests sent faster than they are being ACKed")}}else if(a==="config"){let{aggregations:c,columns:g,filter:i,groupBy:l,sort:f}=o.data;return this.aggregations=c,this.columns=g,this.filter=i,this.groupBy=l,this.sort=f,l.length>0?this.isTree=!0:this.isTree&&(this.isTree=!1),b==null||b(\`config change confirmed, isTree : \${this.isTree}\`),{clientViewportId:n,type:a,config:o.data}}else{if(a==="groupBy")return this.isTree=o.data.length>0,this.groupBy=o.data,b==null||b(\`groupBy change confirmed, isTree : \${this.isTree}\`),{clientViewportId:n,type:a,groupBy:o.data};if(a==="columns")return this.columns=o.data,{clientViewportId:n,type:a,columns:o.data};if(a==="filter")return this.filter=o.data,{clientViewportId:n,type:a,filter:o.data};if(a==="aggregate")return this.aggregations=o.data,{clientViewportId:n,type:"aggregate",aggregations:this.aggregations};if(a==="sort")return this.sort=o.data,{clientViewportId:n,type:a,sort:this.sort};if(a!=="selection"){if(a==="disable")return this.disabled=!0,{type:"disabled",clientViewportId:n};if(a==="enable")return this.disabled=!1,{type:"enabled",clientViewportId:n};if(a==="CREATE_VISUAL_LINK"){let[c,g,i]=t;return this.linkedParent={colName:c,parentViewportId:g,parentColName:i},this.pendingLinkedParent=void 0,{type:"vuu-link-created",clientViewportId:n,colName:c,parentViewportId:g,parentColName:i}}else if(a==="REMOVE_VISUAL_LINK")return this.linkedParent=void 0,{type:"vuu-link-removed",clientViewportId:n}}}}rangeRequest(e,t){H&&this.rangeMonitor.set(t);let n="CHANGE_VP_RANGE";if(this.dataWindow){let[r,o]=this.dataWindow.setClientRange(t.from,t.to),a,u=this.dataWindow.rowCount||void 0,c=r&&!this.rangeRequestAlreadyPending(t)?{type:n,viewPortId:this.serverViewportId,...Y(t,this.bufferSize,u)}:null;if(c){H&&(b==null||b(\`create CHANGE_VP_RANGE: [\${c.from} - \${c.to}]\`)),this.awaitOperation(e,{type:n});let i=this.pendingRangeRequests.at(-1);if(i)if(i.acked)console.warn("Range Request before previous request is filled");else{let{from:l,to:f}=i;this.dataWindow.outOfRange(l,f)?a={clientViewportId:this.clientViewportId,type:"debounce-begin"}:P==null||P("Range Request before previous request is acked")}this.pendingRangeRequests.push({...c,requestId:e}),this.useBatchMode&&(this.batchMode=!0)}else o.length>0&&(this.batchMode=!1);this.keys.reset(this.dataWindow.clientRange);let g=this.isTree?le:ue;return o.length?[c,o.map(i=>g(i,this.keys,this.selectedRows))]:a?[c,void 0,a]:[c]}else return[null]}setLinks(e){return this.links=e,[{type:"vuu-links",links:e,clientViewportId:this.clientViewportId},this.pendingLinkedParent]}setMenu(e){return{type:"vuu-menu",menu:e,clientViewportId:this.clientViewportId}}setTableSchema(e){this.tableSchema=e}openTreeNode(e,t){return this.useBatchMode&&(this.batchMode=!0),{type:Xe,vpId:this.serverViewportId,treeKey:t.key}}closeTreeNode(e,t){return this.useBatchMode&&(this.batchMode=!0),{type:Ne,vpId:this.serverViewportId,treeKey:t.key}}createLink(e,t,n,r){let o={type:"CREATE_VISUAL_LINK",parentVpId:n,childVpId:this.serverViewportId,parentColumnName:r,childColumnName:t};return this.awaitOperation(e,o),this.useBatchMode&&(this.batchMode=!0),o}removeLink(e){let t={type:"REMOVE_VISUAL_LINK",childVpId:this.serverViewportId};return this.awaitOperation(e,t),t}suspend(){this.suspended=!0,d==null||d("suspend")}resume(){return this.suspended=!1,H&&(b==null||b(\`resume: \${this.currentData()}\`)),this.currentData()}currentData(){let e=[];if(this.dataWindow){let t=this.dataWindow.getData(),{keys:n}=this,r=this.isTree?le:ue;for(let o of t)o&&e.push(r(o,n,this.selectedRows))}return e}enable(e){return this.awaitOperation(e,{type:"enable"}),d==null||d(\`enable: \${this.serverViewportId}\`),{type:Ke,viewPortId:this.serverViewportId}}disable(e){return this.awaitOperation(e,{type:"disable"}),d==null||d(\`disable: \${this.serverViewportId}\`),this.suspended=!1,{type:Be,viewPortId:this.serverViewportId}}columnRequest(e,t){return this.awaitOperation(e,{type:"columns",data:t}),b==null||b(\`columnRequest: \${t}\`),this.createRequest({columns:t})}filterRequest(e,t){this.awaitOperation(e,{type:"filter",data:t}),this.useBatchMode&&(this.batchMode=!0);let{filter:n}=t;return d==null||d(\`filterRequest: \${n}\`),this.createRequest({filterSpec:{filter:n}})}setConfig(e,t){this.awaitOperation(e,{type:"config",data:t});let{filter:n,...r}=t;return this.useBatchMode&&(this.batchMode=!0),H?b==null||b(\`setConfig \${JSON.stringify(t)}\`):d==null||d("setConfig"),this.createRequest({...r,filterSpec:typeof(n==null?void 0:n.filter)=="string"?{filter:n.filter}:{filter:""}},!0)}aggregateRequest(e,t){return this.awaitOperation(e,{type:"aggregate",data:t}),d==null||d(\`aggregateRequest: \${t}\`),this.createRequest({aggregations:t})}sortRequest(e,t){return this.awaitOperation(e,{type:"sort",data:t}),d==null||d(\`sortRequest: \${JSON.stringify(t.sortDefs)}\`),this.createRequest({sort:t})}groupByRequest(e,t=kt){var n;return this.awaitOperation(e,{type:"groupBy",data:t}),this.useBatchMode&&(this.batchMode=!0),this.isTree||(n=this.dataWindow)==null||n.clear(),this.createRequest({groupBy:t})}selectRequest(e,t){return this.selectedRows=t,this.awaitOperation(e,{type:"selection",data:t}),d==null||d(\`selectRequest: \${t}\`),{type:"SET_SELECTION",vpId:this.serverViewportId,selection:Se(t)}}removePendingRangeRequest(e,t){for(let n=this.pendingRangeRequests.length-1;n>=0;n--){let{from:r,to:o}=this.pendingRangeRequests[n],a=!0;if(e>=r&&er&&t0){e=[],t="update";for(let a of this.pendingUpdates)e.push(o(a,n,r));this.pendingUpdates.length=0}else{let a=this.dataWindow.getData();if(this.dataWindow.hasAllRowsWithinRange){e=[],t="batch";for(let u of a)e.push(o(u,n,r));this.batchMode=!1}}this.hasUpdates=!1}return this.throttleMessage(t)?j:[e,t]}createRequest(e,t=!1){return t?{type:"CHANGE_VP",viewPortId:this.serverViewportId,...e}:{type:"CHANGE_VP",viewPortId:this.serverViewportId,aggregations:this.aggregations,columns:this.columns,sort:this.sort,groupBy:this.groupBy,filterSpec:{filter:this.filter.filter},...e}}},ue=({rowIndex:s,rowKey:e,sel:t,data:n},r,o)=>[s,r.keyFor(s),!0,!1,0,0,e,t?Z(o,s):0].concat(n),le=({rowIndex:s,rowKey:e,sel:t,data:n},r,o)=>{let[a,u,,c,,g,...i]=n;return[s,r.keyFor(s),c,u,a,g,e,t?Z(o,s):0].concat(i)};var it=1;var{debug:E,debugEnabled:L,error:O,info:S,infoEnabled:Wt,warn:k}=w("server-proxy"),C=()=>\`\${it++}\`,\$t={},qt=s=>s.disabled!==!0&&s.suspended!==!0,Bt={type:"NO_ACTION"},Gt=(s,e,t)=>s.map(n=>n.parentVpId===e?{...n,label:t}:n);function Kt(s,e){return s.map(t=>{let{parentVpId:n}=t,r=e.get(n);if(r)return{...t,parentClientVpId:r.clientViewportId,label:r.title};throw Error("addLabelsToLinks viewport not found")})}var J=class{constructor(e,t){this.authToken="";this.user="user";this.pendingTableMetaRequests=new Map;this.pendingRequests=new Map;this.queuedRequests=[];this.cachedTableSchemas=new Map;this.connection=e,this.postMessageToClient=t,this.viewports=new Map,this.mapClientToServerViewport=new Map}async reconnect(){await this.login(this.authToken);let[e,t]=he(Array.from(this.viewports.values()),qt);this.viewports.clear(),this.mapClientToServerViewport.clear();let n=r=>{r.forEach(o=>{let{clientViewportId:a}=o;this.viewports.set(a,o),this.sendMessageToServer(o.subscribe(),a)})};n(e),setTimeout(()=>{n(t)},2e3)}async login(e,t="user"){if(e)return this.authToken=e,this.user=t,new Promise((n,r)=>{this.sendMessageToServer({type:Ye,token:this.authToken,user:t},""),this.pendingLogin={resolve:n,reject:r}});this.authToken===""&&O("login, cannot login until auth token has been obtained")}subscribe(e){if(this.mapClientToServerViewport.has(e.viewport))O(\`spurious subscribe call \${e.viewport}\`);else{if(!this.hasSchemaForTable(e.table)&&!G(e.table)){S==null||S(\`subscribe to \${e.table.table}, no metadata yet, request metadata\`);let n=C();this.sendMessageToServer({type:"GET_TABLE_META",table:e.table},n),this.pendingTableMetaRequests.set(n,e.viewport)}let t=new z(e,this.postMessageToClient);this.viewports.set(e.viewport,t),this.sendIfReady(t.subscribe(),e.viewport,this.sessionId!=="")}}unsubscribe(e){let t=this.mapClientToServerViewport.get(e);t?(S==null||S(\`Unsubscribe Message (Client to Server): + \${t}\`),this.sendMessageToServer({type:et,viewPortId:t})):O(\`failed to unsubscribe client viewport \${e}, viewport not found\`)}getViewportForClient(e,t=!0){let n=this.mapClientToServerViewport.get(e);if(n){let r=this.viewports.get(n);if(r)return r;if(t)throw Error(\`Viewport not found for client viewport \${e}\`);return null}else{if(this.viewports.has(e))return this.viewports.get(e);if(t)throw Error(\`Viewport server id not found for client viewport \${e}\`);return null}}setViewRange(e,t){let n=C(),[r,o,a]=e.rangeRequest(n,t.range);S==null||S(\`setViewRange \${t.range.from} - \${t.range.to}\`),r&&this.sendIfReady(r,n,e.status==="subscribed"),o?(S==null||S(\`setViewRange \${o.length} rows returned from cache\`),this.postMessageToClient({mode:"batch",type:"viewport-update",clientViewportId:e.clientViewportId,rows:o})):a&&this.postMessageToClient(a)}setConfig(e,t){let n=C(),r=e.setConfig(n,t.config);this.sendIfReady(r,n,e.status==="subscribed")}aggregate(e,t){let n=C(),r=e.aggregateRequest(n,t.aggregations);this.sendIfReady(r,n,e.status==="subscribed")}sort(e,t){let n=C(),r=e.sortRequest(n,t.sort);this.sendIfReady(r,n,e.status==="subscribed")}groupBy(e,t){let n=C(),r=e.groupByRequest(n,t.groupBy);this.sendIfReady(r,n,e.status==="subscribed")}filter(e,t){let n=C(),{filter:r}=t,o=e.filterRequest(n,r);this.sendIfReady(o,n,e.status==="subscribed")}setColumns(e,t){let n=C(),{columns:r}=t,o=e.columnRequest(n,r);this.sendIfReady(o,n,e.status==="subscribed")}setTitle(e,t){e&&(e.title=t.title,this.updateTitleOnVisualLinks(e))}select(e,t){let n=C(),{selected:r}=t,o=e.selectRequest(n,r);this.sendIfReady(o,n,e.status==="subscribed")}disableViewport(e){let t=C(),n=e.disable(t);this.sendIfReady(n,t,e.status==="subscribed")}enableViewport(e){if(e.disabled){let t=C(),n=e.enable(t);this.sendIfReady(n,t,e.status==="subscribed")}}suspendViewport(e){e.suspend(),e.suspendTimer=setTimeout(()=>{S==null||S("suspendTimer expired, escalate suspend to disable"),this.disableViewport(e)},3e3)}resumeViewport(e){e.suspendTimer&&(E==null||E("clear suspend timer"),clearTimeout(e.suspendTimer),e.suspendTimer=null);let t=e.resume();this.postMessageToClient({clientViewportId:e.clientViewportId,mode:"batch",rows:t,type:"viewport-update"})}openTreeNode(e,t){if(e.serverViewportId){let n=C();this.sendIfReady(e.openTreeNode(n,t),n,e.status==="subscribed")}}closeTreeNode(e,t){if(e.serverViewportId){let n=C();this.sendIfReady(e.closeTreeNode(n,t),n,e.status==="subscribed")}}createLink(e,t){let{parentClientVpId:n,parentColumnName:r,childColumnName:o}=t,a=C(),u=this.mapClientToServerViewport.get(n);if(u){let c=e.createLink(a,o,u,r);this.sendMessageToServer(c,a)}else O("ServerProxy unable to create link, viewport not found")}removeLink(e){let t=C(),n=e.removeLink(t);this.sendMessageToServer(n,t)}updateTitleOnVisualLinks(e){var r;let{serverViewportId:t,title:n}=e;for(let o of this.viewports.values())if(o!==e&&o.links&&t&&n&&(r=o.links)!=null&&r.some(a=>a.parentVpId===t)){let[a]=o.setLinks(Gt(o.links,t,n));this.postMessageToClient(a)}}removeViewportFromVisualLinks(e){var t;for(let n of this.viewports.values())if((t=n.links)!=null&&t.some(({parentVpId:r})=>r===e)){let[r]=n.setLinks(n.links.filter(({parentVpId:o})=>o!==e));this.postMessageToClient(r)}}menuRpcCall(e){let t=this.getViewportForClient(e.vpId,!1);if(t!=null&&t.serverViewportId){let[n,r]=ne(e);this.sendMessageToServer({...r,vpId:t.serverViewportId},n)}}rpcCall(e){let[t,n]=ne(e),r=st(n.service);this.sendMessageToServer(n,t,{module:r})}handleMessageFromClient(e){if(E==null||E(\`handleMessageFromClient: \${e.type}\`),ke(e))if(e.type==="disable"){let t=this.getViewportForClient(e.viewport,!1);return t!==null?this.disableViewport(t):void 0}else{let t=this.getViewportForClient(e.viewport);switch(e.type){case"setViewRange":return this.setViewRange(t,e);case"config":return this.setConfig(t,e);case"aggregate":return this.aggregate(t,e);case"sort":return this.sort(t,e);case"groupBy":return this.groupBy(t,e);case"filter":return this.filter(t,e);case"select":return this.select(t,e);case"suspend":return this.suspendViewport(t);case"resume":return this.resumeViewport(t);case"enable":return this.enableViewport(t);case"openTreeNode":return this.openTreeNode(t,e);case"closeTreeNode":return this.closeTreeNode(t,e);case"createLink":return this.createLink(t,e);case"removeLink":return this.removeLink(t);case"setColumns":return this.setColumns(t,e);case"setTitle":return this.setTitle(t,e);default:}}else{if(De(e))return this.menuRpcCall(e);{let{type:t,requestId:n}=e;switch(t){case"GET_TABLE_LIST":return this.sendMessageToServer({type:t},n);case"GET_TABLE_META":return this.sendMessageToServer({type:t,table:e.table},n);case"RPC_CALL":return this.rpcCall(e);default:}}}O(\`Vuu ServerProxy Unexpected message from client \${JSON.stringify(e)}\`)}awaitResponseToMessage(e){return new Promise((t,n)=>{let r=C();this.sendMessageToServer(e,r),this.pendingRequests.set(r,{reject:n,resolve:t})})}sendIfReady(e,t,n=!0){return n?this.sendMessageToServer(e,t):this.queuedRequests.push(e),n}sendMessageToServer(e,t=\`\${it++}\`,n=\$t){let{module:r="CORE"}=n;this.authToken&&this.connection.send({requestId:t,sessionId:this.sessionId,token:this.authToken,user:this.user,module:r,body:e})}handleMessageFromServer(e){var u;let{body:t,requestId:n,sessionId:r}=e,o=this.pendingRequests.get(n);if(o){let{resolve:i}=o;this.pendingRequests.delete(n),i(t);return}let{viewports:a}=this;switch(t.type){case ze:this.sendMessageToServer({type:Je,ts:+new Date},"NA");break;case Ze:if(r)this.sessionId=r,(u=this.pendingLogin)==null||u.resolve(r),this.pendingLogin=void 0;else throw Error("LOGIN_SUCCESS did not provide sessionId");break;case qe:{let i=a.get(n);if(i){let{status:l}=i,{viewPortId:f}=t;n!==f&&(a.delete(n),a.set(f,i)),this.mapClientToServerViewport.set(n,f);let R=i.handleSubscribed(t);R&&(this.postMessageToClient(R),L&&E(\`post DataSourceSubscribedMessage to client: \${JSON.stringify(R)}\`)),i.disabled&&this.disableViewport(i),l==="subscribing"&&!G(i.table)&&(this.sendMessageToServer({type:se,vpId:f}),this.sendMessageToServer({type:je,vpId:f}),Array.from(a.entries()).filter(([M,{disabled:A}])=>M!==f&&!A).forEach(([M])=>{this.sendMessageToServer({type:se,vpId:M})}))}}break;case"REMOVE_VP_SUCCESS":{let i=a.get(t.viewPortId);i&&(this.mapClientToServerViewport.delete(i.clientViewportId),a.delete(t.viewPortId),this.removeViewportFromVisualLinks(t.viewPortId))}break;case tt:{let i=this.viewports.get(t.vpId);i&&i.completeOperation(n)}break;case Ue:case Ge:if(a.has(t.viewPortId)){let i=this.viewports.get(t.viewPortId);if(i){let l=i.completeOperation(n);l!==void 0&&(this.postMessageToClient(l),L&&E(\`postMessageToClient \${JSON.stringify(l)}\`))}}break;case He:{let i=this.viewports.get(t.viewPortId);if(i){let l=i.completeOperation(n);if(l){this.postMessageToClient(l);let f=i.currentData();L&&E(\`Enable Response (ServerProxy to Client): \${JSON.stringify(l)}\`),i.size===0?L&&E("Viewport Enabled but size 0, resend to server"):(this.postMessageToClient({clientViewportId:i.clientViewportId,mode:"batch",rows:f,size:i.size,type:"viewport-update"}),L&&E(\`Enable Response (ServerProxy to Client): send size \${i.size} \${f.length} rows from cache\`))}}}break;case nt:{let i=Pe(t.rows);for(let[l,f]of Object.entries(i)){let R=a.get(l);R?R.updateRows(f):k==null||k(\`TABLE_ROW message received for non registered viewport \${l}\`)}this.processUpdates()}break;case Fe:{let i=this.viewports.get(t.viewPortId);if(i){let{from:l,to:f}=t;i.completeOperation(n,l,f)}}break;case Qe:case We:break;case"CREATE_VISUAL_LINK_SUCCESS":{let i=this.viewports.get(t.childVpId),l=this.viewports.get(t.parentVpId);if(i&&l){let{childColumnName:f,parentColumnName:R}=t,M=i.completeOperation(n,f,l.clientViewportId,R);M&&this.postMessageToClient(M)}}break;case"REMOVE_VISUAL_LINK_SUCCESS":{let i=this.viewports.get(t.childVpId);if(i){let l=i.completeOperation(n);l&&this.postMessageToClient(l)}}break;case ae:this.postMessageToClient({type:ae,tables:t.tables,requestId:n});break;case ie:{let i=this.cacheTableMeta(t),l=this.pendingTableMetaRequests.get(n);if(l){this.pendingTableMetaRequests.delete(n);let f=this.viewports.get(l);f?f.setTableSchema(i):k==null||k("Message has come back AFTER CREATE_VP_SUCCESS, what do we do now")}else this.postMessageToClient({type:ie,tableSchema:i,requestId:n})}break;case"VP_VISUAL_LINKS_RESP":{let i=this.getActiveLinks(t.links),l=this.viewports.get(t.vpId);if(i.length&&l){let f=Kt(i,this.viewports),[R,M]=l.setLinks(f);if(this.postMessageToClient(R),M){let{link:A,parentClientVpId:at}=M,de=C(),ge=this.mapClientToServerViewport.get(at);if(ge){let ut=l.createLink(de,A.fromColumn,ge,A.toColumn);this.sendMessageToServer(ut,de)}}}}break;case"VIEW_PORT_MENUS_RESP":if(t.menu.name){let i=this.viewports.get(t.vpId);if(i){let l=i.setMenu(t.menu);this.postMessageToClient(l)}}break;case"VP_EDIT_RPC_RESPONSE":this.postMessageToClient({action:t.action,requestId:n,rpcName:t.rpcName,type:"VP_EDIT_RPC_RESPONSE"});break;case"VP_EDIT_RPC_REJECT":this.viewports.get(t.vpId)&&this.postMessageToClient({requestId:n,type:"VP_EDIT_RPC_REJECT",error:t.error});break;case"VIEW_PORT_MENU_RESP":if(Ae(t)){let{action:i,rpcName:l}=t;this.awaitResponseToMessage({type:"GET_TABLE_META",table:i.table}).then(f=>{let R=re(f);this.postMessageToClient({rpcName:l,type:"VIEW_PORT_MENU_RESP",action:{...i,tableSchema:R},tableAlreadyOpen:this.isTableOpen(i.table),requestId:n})})}else{let{action:i}=t;this.postMessageToClient({type:"VIEW_PORT_MENU_RESP",action:i||Bt,tableAlreadyOpen:i!==null&&this.isTableOpen(i.table),requestId:n})}break;case oe:{let{method:i,result:l}=t;this.postMessageToClient({type:oe,method:i,result:l,requestId:n})}break;case"ERROR":O(t.msg);break;default:Wt&&S(\`handleMessageFromServer \${t.type}.\`)}}hasSchemaForTable(e){return this.cachedTableSchemas.has(\`\${e.module}:\${e.table}\`)}cacheTableMeta(e){let{module:t,table:n}=e.table,r=\`\${t}:\${n}\`,o=this.cachedTableSchemas.get(r);return o||(o=re(e),this.cachedTableSchemas.set(r,o)),o}isTableOpen(e){if(e){let t=e.table;for(let n of this.viewports.values())if(!n.suspended&&n.table.table===t)return!0}}getActiveLinks(e){return e.filter(t=>{let n=this.viewports.get(t.parentVpId);return n&&!n.suspended})}processUpdates(){this.viewports.forEach(e=>{var t;if(e.hasUpdatesToProcess){let n=e.getClientRows();if(n!==j){let[r,o]=n,a=e.getNewRowCount();(a!==void 0||r&&r.length>0)&&(L&&E(\`postMessageToClient #\${e.clientViewportId} viewport-update \${o}, \${(t=r==null?void 0:r.length)!=null?t:"no"} rows, size \${a}\`),o&&this.postMessageToClient({clientViewportId:e.clientViewportId,mode:o,rows:r,size:a,type:"viewport-update"}))}}})}};var D,{info:ce,infoEnabled:pe}=w("worker");async function Ht(s,e,t,n,r,o,a){let u=await Ie(s,e,c=>{Oe(c)?(console.log("post connection metrics"),postMessage({type:"connection-metrics",messages:c})):Le(c)?(r(c),c.status==="reconnected"&&D.reconnect()):D.handleMessageFromServer(c)},o,a);D=new J(u,c=>jt(c)),u.requiresLogin&&await D.login(t,n)}function jt(s){postMessage(s)}var zt=async({data:s})=>{switch(s.type){case"connect":await Ht(s.url,s.protocol,s.token,s.username,postMessage,s.retryLimitDisconnect,s.retryLimitStartup),postMessage({type:"connected"});break;case"subscribe":pe&&ce(\`client subscribe: \${JSON.stringify(s)}\`),D.subscribe(s);break;case"unsubscribe":pe&&ce(\`client unsubscribe: \${JSON.stringify(s)}\`),D.unsubscribe(s.viewport);break;default:pe&&ce(\`client message: \${JSON.stringify(s)}\`),D.handleMessageFromClient(s)}};self.addEventListener("message",zt);postMessage({type:"ready"}); + +`; \ No newline at end of file diff --git a/vuu-ui/packages/vuu-data/src/json-data-source.ts b/vuu-ui/packages/vuu-data/src/json-data-source.ts index 3f032bea7..b7879cf58 100644 --- a/vuu-ui/packages/vuu-data/src/json-data-source.ts +++ b/vuu-ui/packages/vuu-data/src/json-data-source.ts @@ -92,6 +92,7 @@ export class JsonDataSource } [this.columnDescriptors, this.#data] = jsonToDataSourceRows(data); + this.visibleRows = this.#data .filter((row) => row[DEPTH] === 0) .map((row, index) => @@ -133,8 +134,6 @@ export class JsonDataSource ) { this.clientCallback = callback; - console.log(`subscribe range ${range?.from} ${range?.to}`); - if (aggregations) { this.#aggregations = aggregations; } @@ -320,6 +319,10 @@ export class JsonDataSource this.#aggregations = aggregations; } + set data(data: JsonData) { + console.log(`set JsonDataSource data`); + } + get sort() { return this.#sort; } diff --git a/vuu-ui/packages/vuu-data/src/remote-data-source.ts b/vuu-ui/packages/vuu-data/src/remote-data-source.ts index 3ebc48a57..1d81b5807 100644 --- a/vuu-ui/packages/vuu-data/src/remote-data-source.ts +++ b/vuu-ui/packages/vuu-data/src/remote-data-source.ts @@ -1,4 +1,4 @@ -import { DataSourceFilter } from "@finos/vuu-data-types"; +import { DataSourceFilter, DataSourceRow } from "@finos/vuu-data-types"; import { Selection } from "@finos/vuu-datagrid-types"; import { ClientToServerEditRpc, @@ -18,6 +18,7 @@ import { EventEmitter, itemsOrOrderChanged, logger, + metadataKeys, throttle, uuid, } from "@finos/vuu-utils"; @@ -43,6 +44,19 @@ type RangeRequest = (range: VuuRange) => void; const { info } = logger("RemoteDataSource"); +const { KEY } = metadataKeys; + +type DataSourceStatus = + | "disabled" + | "disabling" + | "enabled" + | "enabling" + | "initialising" + | "subscribing" + | "subscribed" + | "suspended" + | "unsubscribed"; + /*----------------------------------------------------------------- A RemoteDataSource manages a single subscription via the ServerProxy ----------------------------------------------------------------*/ @@ -52,7 +66,7 @@ export class RemoteDataSource { private bufferSize: number; private server: ServerAPI | null = null; - private status = "initialising"; + private status: DataSourceStatus = "initialising"; private clientCallback: SubscribeCallback | undefined; private configChangePending: DataSourceConfig | undefined; private rangeRequest: RangeRequest; @@ -135,7 +149,7 @@ export class RemoteDataSource this.#range = range; } - if (this.status !== "initialising") { + if (this.status !== "initialising" && this.status !== "unsubscribed") { return; } @@ -203,7 +217,11 @@ export class RemoteDataSource this.server?.unsubscribe(this.viewport); } this.server?.destroy(this.viewport); + this.server = null; this.removeAllListeners(); + this.status = "unsubscribed"; + this.viewport = undefined; + this.range = { from: 0, to: 0 }; } suspend() { @@ -598,8 +616,15 @@ export class RemoteDataSource } } - applyEdit(rowIndex: number, columnName: string, value: VuuColumnDataType) { - console.log(`ArrayDataSource applyEdit ${rowIndex} ${columnName} ${value}`); + applyEdit(row: DataSourceRow, columnName: string, value: VuuColumnDataType) { + this.menuRpcCall({ + rowKey: row[KEY], + field: columnName, + value: parseInt(value), + type: "VP_EDIT_CELL_RPC", + }).then(() => { + console.log("response"); + }); return true; } } diff --git a/vuu-ui/packages/vuu-data/src/server-proxy/array-backed-moving-window.ts b/vuu-ui/packages/vuu-data/src/server-proxy/array-backed-moving-window.ts index a5357ecd5..40cebe351 100644 --- a/vuu-ui/packages/vuu-data/src/server-proxy/array-backed-moving-window.ts +++ b/vuu-ui/packages/vuu-data/src/server-proxy/array-backed-moving-window.ts @@ -7,6 +7,27 @@ type RangeTuple = [boolean, readonly VuuRow[] /*, readonly VuuRow[]*/]; const log = logger("array-backed-moving-window"); +function dataIsUnchanged(newRow: VuuRow, existingRow?: VuuRow) { + if (!existingRow) { + return false; + } + + if (existingRow.data.length !== newRow.data.length) { + return false; + } + + if (existingRow.sel !== newRow.sel) { + return false; + } + + for (let i = 0; i < existingRow.data.length; i++) { + if (existingRow.data[i] !== newRow.data[i]) { + return false; + } + } + return true; +} + export class ArrayBackedMovingWindow { #range: WindowRange; @@ -79,9 +100,13 @@ export class ArrayBackedMovingWindow { setAtIndex(row: VuuRow) { const { rowIndex: index } = row; + const internalIndex = index - this.#range.from; + //TODO measure the performance impact of this check + if (dataIsUnchanged(row, this.internalData[internalIndex])) { + return false; + } const isWithinClientRange = this.isWithinClientRange(index); if (isWithinClientRange || this.isWithinRange(index)) { - const internalIndex = index - this.#range.from; if (!this.internalData[internalIndex] && isWithinClientRange) { this.rowsWithinRange += 1; } diff --git a/vuu-ui/packages/vuu-data/src/server-proxy/server-proxy.ts b/vuu-ui/packages/vuu-data/src/server-proxy/server-proxy.ts index 035bb129d..34a8f09f3 100644 --- a/vuu-ui/packages/vuu-data/src/server-proxy/server-proxy.ts +++ b/vuu-ui/packages/vuu-data/src/server-proxy/server-proxy.ts @@ -506,8 +506,6 @@ export class ServerProxy { | WithRequestId | WithRequestId ) { - debug?.(`handleMessageFromClient: ${message.type}`); - if (isViewportMessage(message)) { if (message.type === "disable") { // Viewport may already have been unsubscribed @@ -720,7 +718,7 @@ export class ServerProxy { case "REMOVE_VP_SUCCESS": { - const viewport = this.viewports.get(body.viewPortId); + const viewport = viewports.get(body.viewPortId); if (viewport) { this.mapClientToServerViewport.delete(viewport.clientViewportId); viewports.delete(body.viewPortId); diff --git a/vuu-ui/packages/vuu-data/src/server-proxy/viewport.ts b/vuu-ui/packages/vuu-data/src/server-proxy/viewport.ts index 4a51c0a71..3858fcab2 100644 --- a/vuu-ui/packages/vuu-data/src/server-proxy/viewport.ts +++ b/vuu-ui/packages/vuu-data/src/server-proxy/viewport.ts @@ -258,7 +258,6 @@ export class Viewport { if (lastMode === mode) { const ts = Date.now(); - console.log(`read data now ${ts}`); this.lastUpdateStatus.count += 1; this.lastUpdateStatus.ts = ts; elapsedTime = lastTS === 0 ? 0 : ts - lastTS; @@ -919,7 +918,6 @@ export class Viewport { // alleviate pressure on UI DataTable. private shouldThrottleMessage = (mode: DataUpdateMode) => { const elapsedTime = this.setLastUpdate(mode); - console.log(`elapsed time = ${elapsedTime}`); return ( mode === "size-only" && elapsedTime > 0 && @@ -930,7 +928,7 @@ export class Viewport { private throttleMessage = (mode: DataUpdateMode) => { if (this.shouldThrottleMessage(mode)) { - console.log("throttling updates setTimeout to 2000"); + info?.("throttling updates setTimeout to 2000"); if (this.updateThrottleTimer === undefined) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore diff --git a/vuu-ui/packages/vuu-data/src/websocket-connection.ts b/vuu-ui/packages/vuu-data/src/websocket-connection.ts index e0a8a5976..604138cbd 100644 --- a/vuu-ui/packages/vuu-data/src/websocket-connection.ts +++ b/vuu-ui/packages/vuu-data/src/websocket-connection.ts @@ -69,12 +69,14 @@ export async function connect( async function reconnect(connection: WebsocketConnection) { //TODO it's not enough to reconnect with a new websocket, we have to log back in as well - makeConnection( - connection.url, - connection.protocol, - connection[connectionCallback], - connection - ); + // Temp don't try to reconnect at all until better interop with a proxy is implemented + // makeConnection( + // connection.url, + // connection.protocol, + // connection[connectionCallback], + // connection + // ); + throw Error("connection broken"); } async function makeConnection( diff --git a/vuu-ui/packages/vuu-data/src/worker.ts b/vuu-ui/packages/vuu-data/src/worker.ts index 35952e442..881746c68 100644 --- a/vuu-ui/packages/vuu-data/src/worker.ts +++ b/vuu-ui/packages/vuu-data/src/worker.ts @@ -36,9 +36,10 @@ async function connectToServer( // never be called until subscriptions have been made, so this is safe. //TODO do we need to listen in to the connection messages here so we can lock back in, in the event of a reconnenct ? (msg) => { - if (isConnectionQualityMetrics(msg)) + if (isConnectionQualityMetrics(msg)) { + console.log("post connection metrics"); postMessage({ type: "connection-metrics", messages: msg }); - else if (isConnectionStatusMessage(msg)) { + } else if (isConnectionStatusMessage(msg)) { onConnectionStatusChange(msg); if (msg.status === "reconnected") { server.reconnect(); diff --git a/vuu-ui/packages/vuu-data/test/server-proxy.test.ts b/vuu-ui/packages/vuu-data/test/server-proxy.test.ts index fc78984e7..0824c8771 100644 --- a/vuu-ui/packages/vuu-data/test/server-proxy.test.ts +++ b/vuu-ui/packages/vuu-data/test/server-proxy.test.ts @@ -2574,9 +2574,9 @@ describe("ServerProxy", () => { body: { ...COMMON_TABLE_ROW_ATTRS, rows: [ - ...createTableRows("server-vp-1", 0, 1, 100, 1, 1), + ...createTableRows("server-vp-1", 0, 1, 100, 1, 1, 2000), sizeRow("server-vp-2", 20), - ...createTableRows("server-vp-2", 0, 10), + ...createTableRows("server-vp-2", 0, 10, 100, 2, 0, 2000), ], }, }); @@ -2587,7 +2587,7 @@ describe("ServerProxy", () => { { mode: "update", rows: [ - [0,0,true,false,0,0,'key-00', 0,'key-00', 'name 00',1000,true], + [0,0,true,false,0,0,'key-00', 0,'key-00', 'name 00',2000,true], ], type: 'viewport-update', clientViewportId: 'client-vp-1' @@ -2598,16 +2598,16 @@ describe("ServerProxy", () => { { mode: "batch", rows: [ - [0,0,true,false,0,0,'key-00', 0,'key-00', 'name 00',1000,true], - [1,1,true,false,0,0,"key-01",0,"key-01","name 01",1001,true], - [2,2,true,false,0,0,"key-02",0,"key-02","name 02",1002,true], - [3,3,true,false,0,0,"key-03",0,"key-03","name 03",1003,true], - [4,4,true,false,0,0,"key-04",0,"key-04","name 04",1004,true], - [5,5,true,false,0,0,"key-05",0,"key-05","name 05",1005,true], - [6,6,true,false,0,0,"key-06",0,"key-06","name 06",1006,true], - [7,7,true,false,0,0,"key-07",0,"key-07","name 07",1007,true], - [8,8,true,false,0,0,"key-08",0,"key-08","name 08",1008,true], - [9,9,true,false,0,0,"key-09",0,"key-09","name 09",1009,true] + [0,0,true,false,0,0,'key-00', 0,'key-00', 'name 00',2000,true], + [1,1,true,false,0,0,"key-01",0,"key-01","name 01",2001,true], + [2,2,true,false,0,0,"key-02",0,"key-02","name 02",2002,true], + [3,3,true,false,0,0,"key-03",0,"key-03","name 03",2003,true], + [4,4,true,false,0,0,"key-04",0,"key-04","name 04",2004,true], + [5,5,true,false,0,0,"key-05",0,"key-05","name 05",2005,true], + [6,6,true,false,0,0,"key-06",0,"key-06","name 06",2006,true], + [7,7,true,false,0,0,"key-07",0,"key-07","name 07",2007,true], + [8,8,true,false,0,0,"key-08",0,"key-08","name 08",2008,true], + [9,9,true,false,0,0,"key-09",0,"key-09","name 09",2009,true] ], size: 100, type: 'viewport-update', diff --git a/vuu-ui/packages/vuu-data/test/test-utils.ts b/vuu-ui/packages/vuu-data/test/test-utils.ts index 44e2570fc..43a4d2e0c 100644 --- a/vuu-ui/packages/vuu-data/test/test-utils.ts +++ b/vuu-ui/packages/vuu-data/test/test-utils.ts @@ -46,14 +46,15 @@ export const createTableRows = ( to, vpSize = 100, ts = 1, - sel: 0 | 1 = 0 + sel: 0 | 1 = 0, + numericValue = 1000 ): VuuRow[] => { const results: VuuRow[] = []; for (let rowIndex = from; rowIndex < to; rowIndex++) { const key = ("0" + rowIndex).slice(-2); const rowKey = `key-${key}`; results.push({ - data: [rowKey, `name ${key}`, 1000 + rowIndex, true], + data: [rowKey, `name ${key}`, numericValue + rowIndex, true], rowIndex, rowKey, updateType: "U", diff --git a/vuu-ui/packages/vuu-data/tsconfig.json b/vuu-ui/packages/vuu-data/tsconfig.json new file mode 100644 index 000000000..db9582a16 --- /dev/null +++ b/vuu-ui/packages/vuu-data/tsconfig.json @@ -0,0 +1,6 @@ +{ +"extends": "../../tsconfig.json", +"compilerOptions":{ + "composite": true +}, +} diff --git a/vuu-ui/packages/vuu-datagrid-types/index.d.ts b/vuu-ui/packages/vuu-datagrid-types/index.d.ts index 81b58b000..92b7b7ea7 100644 --- a/vuu-ui/packages/vuu-datagrid-types/index.d.ts +++ b/vuu-ui/packages/vuu-datagrid-types/index.d.ts @@ -20,7 +20,7 @@ export type TableHeading = { label: string; width: number }; export type TableHeadings = TableHeading[][]; export type DataCellEditHandler = ( - rowIndex: number, + row: DataSourceRow, columnName: string, value: VuuColumnDataType ) => boolean; @@ -43,6 +43,7 @@ export interface TableAttributes { columnDefaultWidth?: number; columnFormatHeader?: "capitalize" | "uppercase"; columnSeparators?: boolean; + showHighlightedRow?: boolean; rowSeparators?: boolean; zebraStripes?: boolean; } @@ -128,7 +129,6 @@ export interface ColumnDescriptor { align?: ColumnAlignment; className?: string; editable?: boolean; - expression?: string; flex?: number; /** Optional additional level(s) of heading to display above label. diff --git a/vuu-ui/packages/vuu-datagrid-types/tsconfig.json b/vuu-ui/packages/vuu-datagrid-types/tsconfig.json new file mode 100644 index 000000000..db9582a16 --- /dev/null +++ b/vuu-ui/packages/vuu-datagrid-types/tsconfig.json @@ -0,0 +1,6 @@ +{ +"extends": "../../tsconfig.json", +"compilerOptions":{ + "composite": true +}, +} diff --git a/vuu-ui/packages/vuu-datagrid/src/ColumnBearer.tsx b/vuu-ui/packages/vuu-datagrid/src/ColumnBearer.tsx index 30aa5c68a..a41f5a104 100644 --- a/vuu-ui/packages/vuu-datagrid/src/ColumnBearer.tsx +++ b/vuu-ui/packages/vuu-datagrid/src/ColumnBearer.tsx @@ -17,8 +17,8 @@ import "./column-bearer.css"; import { GridModelType } from "./grid-model"; import { ColumnDragState, dragPhase } from "./gridTypes"; import { buildColumnMap } from "@finos/vuu-utils"; -import { KeyedColumnDescriptor } from "packages/vuu-datagrid-types"; -import { DataSourceRow } from "packages/vuu-data-types"; +import { KeyedColumnDescriptor } from "@finos/vuu-datagrid-types"; +import { DataSourceRow } from "@finos/vuu-data-types"; const LEFT = "left"; const RIGHT = "right"; diff --git a/vuu-ui/packages/vuu-datagrid/src/cell-renderers/progress-cell.tsx b/vuu-ui/packages/vuu-datagrid/src/cell-renderers/progress-cell.tsx index cab062d9c..863b9cd12 100644 --- a/vuu-ui/packages/vuu-datagrid/src/cell-renderers/progress-cell.tsx +++ b/vuu-ui/packages/vuu-datagrid/src/cell-renderers/progress-cell.tsx @@ -5,7 +5,7 @@ import React from "react"; import { isTypeDescriptor } from "@finos/vuu-utils"; import { GridCellProps } from "../grid-cells"; import "./progress-cell.css"; -import { ColumnTypeRenderer } from "packages/vuu-datagrid-types"; +import { ColumnTypeRenderer } from "@finos/vuu-datagrid-types"; const ProgressCell = React.memo(function ProgressCell({ column, diff --git a/vuu-ui/packages/vuu-datagrid/src/context-menu/build-context-menu-descriptors.ts b/vuu-ui/packages/vuu-datagrid/src/context-menu/build-context-menu-descriptors.ts index 26a15ed81..b581ae1de 100644 --- a/vuu-ui/packages/vuu-datagrid/src/context-menu/build-context-menu-descriptors.ts +++ b/vuu-ui/packages/vuu-datagrid/src/context-menu/build-context-menu-descriptors.ts @@ -4,7 +4,7 @@ import { ContextMenuGroupItemDescriptor, ContextMenuItemDescriptor, MenuBuilder, -} from "packages/vuu-data-types"; +} from "@finos/vuu-data-types"; import { VuuAggregation, VuuGroupBy, diff --git a/vuu-ui/packages/vuu-datagrid/src/context-menu/useContextMenu.ts b/vuu-ui/packages/vuu-datagrid/src/context-menu/useContextMenu.ts index af6b3bcb6..ae21ba02a 100644 --- a/vuu-ui/packages/vuu-datagrid/src/context-menu/useContextMenu.ts +++ b/vuu-ui/packages/vuu-datagrid/src/context-menu/useContextMenu.ts @@ -2,8 +2,8 @@ import { DataSource } from "@finos/vuu-data"; import { DataSourceFilter, MenuActionHandler } from "@finos/vuu-data-types"; import { KeyedColumnDescriptor } from "@finos/vuu-datagrid-types"; +import { MenuActionClosePopup } from "@finos/vuu-popups"; import { removeColumnFromFilter, setAggregations } from "@finos/vuu-utils"; -import { MenuActionClosePopup } from "packages/vuu-popups/src"; import { AggregationType } from "../constants"; import { GridModelDispatch } from "../grid-context"; import { GridModelType } from "../grid-model/gridModelTypes"; diff --git a/vuu-ui/packages/vuu-datagrid/src/grid-cells/HeaderCell.tsx b/vuu-ui/packages/vuu-datagrid/src/grid-cells/HeaderCell.tsx index 75971e900..956020dc8 100644 --- a/vuu-ui/packages/vuu-datagrid/src/grid-cells/HeaderCell.tsx +++ b/vuu-ui/packages/vuu-datagrid/src/grid-cells/HeaderCell.tsx @@ -14,7 +14,7 @@ import { SortIndicator, sortStatus } from "./sort-indicator"; import { useCellResize } from "./useCellResize"; import "./HeaderCell.css"; -import { DataSourceFilter } from "packages/vuu-data-types"; +import { DataSourceFilter } from "@finos/vuu-data-types"; const classBase = "hwHeaderCell"; const NO_AGGREGATION = { aggType: -1 }; diff --git a/vuu-ui/packages/vuu-datagrid/src/grid-cells/filter-indicator.tsx b/vuu-ui/packages/vuu-datagrid/src/grid-cells/filter-indicator.tsx index 1bfbc2a1f..886ef56a6 100644 --- a/vuu-ui/packages/vuu-datagrid/src/grid-cells/filter-indicator.tsx +++ b/vuu-ui/packages/vuu-datagrid/src/grid-cells/filter-indicator.tsx @@ -5,7 +5,7 @@ import cx from "classnames"; import { HTMLAttributes, useCallback, useMemo } from "react"; import "./filter-indicator.css"; -import { KeyedColumnDescriptor } from "packages/vuu-datagrid-types"; +import { KeyedColumnDescriptor } from "@finos/vuu-datagrid-types"; export const Direction = { ASC: "asc", diff --git a/vuu-ui/packages/vuu-datagrid/src/grid-context.tsx b/vuu-ui/packages/vuu-datagrid/src/grid-context.tsx index 4ba6f7c18..87e908643 100644 --- a/vuu-ui/packages/vuu-datagrid/src/grid-context.tsx +++ b/vuu-ui/packages/vuu-datagrid/src/grid-context.tsx @@ -14,7 +14,7 @@ import { GridAction, KeyedColumnDescriptor, } from "@finos/vuu-datagrid-types"; -import { DataSourceFilter } from "packages/vuu-data-types"; +import { DataSourceFilter } from "@finos/vuu-data-types"; export interface GridActionGroup { type: "group"; diff --git a/vuu-ui/packages/vuu-datagrid/src/grid-hooks/use-data-source.ts b/vuu-ui/packages/vuu-datagrid/src/grid-hooks/use-data-source.ts index 01515f741..4f5bfd144 100644 --- a/vuu-ui/packages/vuu-datagrid/src/grid-hooks/use-data-source.ts +++ b/vuu-ui/packages/vuu-datagrid/src/grid-hooks/use-data-source.ts @@ -7,7 +7,7 @@ import { toColumnDescriptor, WindowRange, } from "@finos/vuu-utils"; -import { DataSourceRow } from "packages/vuu-data-types"; +import { DataSourceRow } from "@finos/vuu-data-types"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { useGridContext } from "../grid-context"; import { GridModelType } from "../grid-model/gridModelTypes"; diff --git a/vuu-ui/packages/vuu-datagrid/src/grid-hooks/useGridActionDispatcher.ts b/vuu-ui/packages/vuu-datagrid/src/grid-hooks/useGridActionDispatcher.ts index f23b7641c..945c29065 100644 --- a/vuu-ui/packages/vuu-datagrid/src/grid-hooks/useGridActionDispatcher.ts +++ b/vuu-ui/packages/vuu-datagrid/src/grid-hooks/useGridActionDispatcher.ts @@ -3,7 +3,7 @@ import { DataSourceAction, GridAction, ScrollAction, -} from "packages/vuu-datagrid-types"; +} from "@finos/vuu-datagrid-types"; import { useCallback } from "react"; import { GridActionSelection, GridModelDispatch } from "../grid-context"; diff --git a/vuu-ui/packages/vuu-datagrid/tsconfig.json b/vuu-ui/packages/vuu-datagrid/tsconfig.json new file mode 100644 index 000000000..db9582a16 --- /dev/null +++ b/vuu-ui/packages/vuu-datagrid/tsconfig.json @@ -0,0 +1,6 @@ +{ +"extends": "../../tsconfig.json", +"compilerOptions":{ + "composite": true +}, +} diff --git a/vuu-ui/packages/vuu-datatable/src/configurable-table/ConfigurableTable.tsx b/vuu-ui/packages/vuu-datatable/src/configurable-table/ConfigurableTable.tsx index 0afc6f2ea..1b60895f8 100644 --- a/vuu-ui/packages/vuu-datatable/src/configurable-table/ConfigurableTable.tsx +++ b/vuu-ui/packages/vuu-datatable/src/configurable-table/ConfigurableTable.tsx @@ -1,5 +1,5 @@ import { GridConfig } from "@finos/vuu-datagrid-types"; -import { Table, TableProps } from "@finos/vuu-table"; +import { Table, TablePropsDeprecated as TableProps } from "@finos/vuu-table"; import { ReactElement, useCallback, useState } from "react"; import { Dialog } from "@finos/vuu-popups"; diff --git a/vuu-ui/packages/vuu-datatable/src/filter-table/FilterTable.css b/vuu-ui/packages/vuu-datatable/src/filter-table/FilterTable.css index 9ba374908..55ae31733 100644 --- a/vuu-ui/packages/vuu-datatable/src/filter-table/FilterTable.css +++ b/vuu-ui/packages/vuu-datatable/src/filter-table/FilterTable.css @@ -1,4 +1,5 @@ .vuuFilterTable { + --vuuFilterBar-flex: 0 0 33px; display: flex; flex-direction: column; } \ No newline at end of file diff --git a/vuu-ui/packages/vuu-datatable/src/json-table/JsonTable.tsx b/vuu-ui/packages/vuu-datatable/src/json-table/JsonTable.tsx index 990c3acad..5c128e1d2 100644 --- a/vuu-ui/packages/vuu-datatable/src/json-table/JsonTable.tsx +++ b/vuu-ui/packages/vuu-datatable/src/json-table/JsonTable.tsx @@ -2,33 +2,53 @@ import { TableProps } from "@finos/vuu-table"; import { JsonData } from "@finos/vuu-utils"; import { TableNext } from "@finos/vuu-table"; import { JsonDataSource } from "@finos/vuu-data"; -import { useMemo } from "react"; +import { useEffect, useMemo, useRef } from "react"; import { TableConfig } from "@finos/vuu-datagrid-types"; export interface JsonTableProps extends Omit { - config: Pick< + config?: Pick< TableConfig, - "columns" | "columnSeparators" | "rowSeparators" | "zebraStripes" + "columnSeparators" | "rowSeparators" | "zebraStripes" >; source: JsonData | undefined; } export const JsonTable = ({ config, - source = { "": "" }, + source: sourceProp = { "": "" }, ...tableProps }: JsonTableProps) => { - const [dataSource, tableConfig] = useMemo< - [JsonDataSource, JsonTableProps["config"]] - >(() => { - const ds = new JsonDataSource({ - data: source, + const sourceRef = useRef(sourceProp); + const dataSourceRef = useRef(); + useMemo(() => { + dataSourceRef.current = new JsonDataSource({ + data: sourceRef.current, }); + }, []); + + const tableConfig = useMemo(() => { + return { + ...config, + columns: dataSourceRef.current?.columnDescriptors ?? [], + }; + }, [config]); + + useEffect(() => { + if (dataSourceRef.current) { + dataSourceRef.current.data = sourceProp; + } + }, [sourceProp]); + + if (dataSourceRef.current === undefined) { + return null; + } - return [ds, { ...config, columns: ds.columnDescriptors }]; - }, [config, source]); return ( - + ); }; diff --git a/vuu-ui/packages/vuu-datatable/tsconfig.json b/vuu-ui/packages/vuu-datatable/tsconfig.json new file mode 100644 index 000000000..db9582a16 --- /dev/null +++ b/vuu-ui/packages/vuu-datatable/tsconfig.json @@ -0,0 +1,6 @@ +{ +"extends": "../../tsconfig.json", +"compilerOptions":{ + "composite": true +}, +} diff --git a/vuu-ui/packages/vuu-filter-parser/tsconfig.json b/vuu-ui/packages/vuu-filter-parser/tsconfig.json new file mode 100644 index 000000000..db9582a16 --- /dev/null +++ b/vuu-ui/packages/vuu-filter-parser/tsconfig.json @@ -0,0 +1,6 @@ +{ +"extends": "../../tsconfig.json", +"compilerOptions":{ + "composite": true +}, +} diff --git a/vuu-ui/packages/vuu-filter-types/tsconfig.json b/vuu-ui/packages/vuu-filter-types/tsconfig.json new file mode 100644 index 000000000..db9582a16 --- /dev/null +++ b/vuu-ui/packages/vuu-filter-types/tsconfig.json @@ -0,0 +1,6 @@ +{ +"extends": "../../tsconfig.json", +"compilerOptions":{ + "composite": true +}, +} diff --git a/vuu-ui/packages/vuu-filters/src/filter-bar/FilterBar.css b/vuu-ui/packages/vuu-filters/src/filter-bar/FilterBar.css index ee35b49f2..eda2b904a 100644 --- a/vuu-ui/packages/vuu-filters/src/filter-bar/FilterBar.css +++ b/vuu-ui/packages/vuu-filters/src/filter-bar/FilterBar.css @@ -1,7 +1,7 @@ .vuuFilterBar { --vuu-svg-tune: url('data:image/svg+xml;utf8,'); - --vuuToolbar-height: 26px; + --vuuToolbar-height: 28px; --salt-container-primary-borderColor: var(--vuu-color-purple-10); --vuuOverflowContainer-minWidth: 0; --saltButton-height: 26px; @@ -11,9 +11,10 @@ background-color: var(--salt-container-secondary-background); border-bottom: solid 1px #D6D7DA; display: flex; + flex: var(--vuuFilterBar-flex); gap: 4px; height: 33px; - padding: 3px 8px; + padding: 0px 8px; } .vuuFilterbar-icon { diff --git a/vuu-ui/packages/vuu-filters/src/filter-bar/FilterBar.tsx b/vuu-ui/packages/vuu-filters/src/filter-bar/FilterBar.tsx index a21e330e3..7186d9d31 100644 --- a/vuu-ui/packages/vuu-filters/src/filter-bar/FilterBar.tsx +++ b/vuu-ui/packages/vuu-filters/src/filter-bar/FilterBar.tsx @@ -1,7 +1,7 @@ import { TableSchema } from "@finos/vuu-data"; import { DataSourceFilter } from "@finos/vuu-data-types"; import { Filter } from "@finos/vuu-filter-types"; -import { Toolbar } from "@finos/vuu-layout"; +import { ActiveItemChangeHandler, Toolbar } from "@finos/vuu-layout"; import { Prompt } from "@finos/vuu-popups"; import { Button } from "@salt-ds/core"; import cx from "classnames"; @@ -19,6 +19,7 @@ export interface FilterBarProps extends HTMLAttributes { activeFilterIndex?: number[]; filters: Filter[]; onApplyFilter: (filter: DataSourceFilter) => void; + onChangeActiveFilterIndex: ActiveItemChangeHandler; onFiltersChanged?: (filters: Filter[]) => void; showMenu?: boolean; tableSchema: TableSchema; @@ -32,6 +33,7 @@ export const FilterBar = ({ className: classNameProp, filters: filtersProp, onApplyFilter, + onChangeActiveFilterIndex: onChangeActiveFilterIndexProp, onFiltersChanged, showMenu: showMenuProp = false, tableSchema, @@ -40,12 +42,14 @@ export const FilterBar = ({ const rootRef = useRef(null); const { activeFilterIndex, + addButtonProps, editFilter, filters, onClickAddFilter, onClickRemoveFilter, onChangeFilterClause, onChangeActiveFilterIndex, + onNavigateOutOfBounds, onKeyDown, onMenuAction, pillProps, @@ -56,6 +60,7 @@ export const FilterBar = ({ containerRef: rootRef, filters: filtersProp, onApplyFilter, + onChangeActiveFilterIndex: onChangeActiveFilterIndexProp, onFiltersChanged, showMenu: showMenuProp, }); @@ -122,14 +127,16 @@ export const FilterBar = ({ {getChildren()} {editFilter === undefined ? (