env(admin): per-environment color field + V2 migration
- V2__add_environment_color.sql adds a CHECK-constrained VARCHAR color column (default 'slate'); existing rows backfill to slate. - Environment record + EnvironmentColor constants (8 preset values) flow through repository, service, and admin API. - UpdateEnvironmentRequest.color nullable: null preserves existing; unknown values → 400. - ITs cover valid / invalid / null-preserves behaviour; existing Environment constructor call-sites updated with the new color arg. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -12,5 +12,6 @@ public record Environment(
|
||||
boolean enabled,
|
||||
Map<String, Object> defaultContainerConfig,
|
||||
Integer jarRetentionCount,
|
||||
String color,
|
||||
Instant createdAt
|
||||
) {}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.cameleer.server.core.runtime;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Preset palette for the per-environment UI color indicator. Stored as a plain
|
||||
* lowercase string on {@link Environment#color()}. The eight values are
|
||||
* CHECK-constrained in PostgreSQL (V2 migration) and validated again here on
|
||||
* the write path so the controller can return a 400 with a readable message.
|
||||
*
|
||||
* <p>Unknown values are silently tolerated on read (the UI falls back to
|
||||
* {@link #DEFAULT}), so a manual DB tweak won't break rendering — but the API
|
||||
* refuses to persist anything outside this set.
|
||||
*/
|
||||
public final class EnvironmentColor {
|
||||
|
||||
public static final String DEFAULT = "slate";
|
||||
|
||||
public static final Set<String> VALUES = Set.of(
|
||||
"slate", "red", "amber", "green", "teal", "blue", "purple", "pink"
|
||||
);
|
||||
|
||||
private EnvironmentColor() {}
|
||||
|
||||
public static boolean isValid(String color) {
|
||||
return color != null && VALUES.contains(color);
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ public interface EnvironmentRepository {
|
||||
Optional<Environment> findById(UUID id);
|
||||
Optional<Environment> findBySlug(String slug);
|
||||
UUID create(String slug, String displayName, boolean production);
|
||||
void update(UUID id, String displayName, boolean production, boolean enabled);
|
||||
void update(UUID id, String displayName, boolean production, boolean enabled, String color);
|
||||
void updateDefaultContainerConfig(UUID id, Map<String, Object> defaultContainerConfig);
|
||||
void updateJarRetentionCount(UUID id, Integer jarRetentionCount);
|
||||
void delete(UUID id);
|
||||
|
||||
@@ -43,9 +43,17 @@ public class EnvironmentService {
|
||||
return repo.create(slug, displayName, production);
|
||||
}
|
||||
|
||||
public void update(UUID id, String displayName, boolean production, boolean enabled) {
|
||||
/**
|
||||
* Update mutable environment fields. Color is validated against
|
||||
* {@link EnvironmentColor#VALUES}. Unknown colors raise
|
||||
* {@link IllegalArgumentException}; the controller maps that to 400.
|
||||
*/
|
||||
public void update(UUID id, String displayName, boolean production, boolean enabled, String color) {
|
||||
getById(id); // verify exists
|
||||
repo.update(id, displayName, production, enabled);
|
||||
if (!EnvironmentColor.isValid(color)) {
|
||||
throw new IllegalArgumentException("unknown environment color: " + color);
|
||||
}
|
||||
repo.update(id, displayName, production, enabled, color);
|
||||
}
|
||||
|
||||
public void updateDefaultContainerConfig(UUID id, Map<String, Object> defaultContainerConfig) {
|
||||
|
||||
Reference in New Issue
Block a user