feat(ui): add environment media playlists

This commit is contained in:
DCCONSTRUCTIONS
2026-07-29 14:20:19 +03:00
parent c455301764
commit 8b1f109b09
11 changed files with 1076 additions and 138 deletions
@@ -0,0 +1,76 @@
import assert from "node:assert/strict";
import { after, before, test } from "node:test";
import React from "react";
import { renderToStaticMarkup } from "react-dom/server";
import { createServer } from "vite";
let server;
let backgroundMedia;
before(async () => {
server = await createServer({
appType: "custom",
logLevel: "silent",
server: { middlewareMode: true },
});
backgroundMedia = await server.ssrLoadModule(
"/src/components/EnvironmentBackgroundMedia.tsx",
);
});
after(async () => {
await server?.close();
});
test("background playlist starts with its oldest media item", () => {
const markup = renderToStaticMarkup(
React.createElement(backgroundMedia.EnvironmentBackgroundMedia, {
background: {
enabled: true,
imageDurationSeconds: 10,
items: [
{
id: "media-oldest",
source: "url",
url: "https://example.test/oldest.png",
mediaKind: "image",
fileName: null,
},
{
id: "media-newest",
source: "url",
url: "https://example.test/newest.mp4",
mediaKind: "video",
fileName: null,
},
],
},
}),
);
assert.match(markup, /oldest\.png/);
assert.doesNotMatch(markup, /newest\.mp4/);
});
test("disabled background renders no media", () => {
const markup = renderToStaticMarkup(
React.createElement(backgroundMedia.EnvironmentBackgroundMedia, {
background: {
enabled: false,
imageDurationSeconds: 10,
items: [
{
id: "media-hidden",
source: "url",
url: "https://example.test/hidden.png",
mediaKind: "image",
fileName: null,
},
],
},
}),
);
assert.equal(markup, "");
});
@@ -24,7 +24,7 @@ after(async () => {
function serverDocument(overrides = {}) {
const defaults = environment.defaultEnvironmentSettings();
return {
schema_version: "missioncore.operator-environment/v2",
schema_version: "missioncore.operator-environment/v3",
revision: defaults.revision,
pages: Object.fromEntries(
Object.entries(defaults.pages).map(([surfaceId, page]) => [
@@ -38,10 +38,14 @@ function serverDocument(overrides = {}) {
secondary_workspace_id: page.secondaryWorkspaceId,
background: {
enabled: page.background.enabled,
source: page.background.source,
url: page.background.url,
media_kind: page.background.mediaKind,
file_name: page.background.fileName,
image_duration_seconds: page.background.imageDurationSeconds,
items: page.background.items.map((item) => ({
id: item.id,
source: item.source,
url: item.url,
media_kind: item.mediaKind,
file_name: item.fileName,
})),
},
},
]),
@@ -81,10 +85,23 @@ test("server document decodes and re-encodes the complete page contract", () =>
primary_workspace_id: "contour-health",
background: {
enabled: true,
source: "file",
url: `/api/v1/environment/media/fleet?generation=${"a".repeat(64)}`,
media_kind: "video",
file_name: "stage.mp4",
image_duration_seconds: 12,
items: [
{
id: "media-11111111-1111-4111-8111-111111111111",
source: "file",
url: `/api/v1/environment/media/fleet?generation=${"a".repeat(64)}`,
media_kind: "video",
file_name: "stage.mp4",
},
{
id: "media-22222222-2222-4222-8222-222222222222",
source: "url",
url: "https://example.test/background.png",
media_kind: "image",
file_name: null,
},
],
},
},
},
@@ -95,8 +112,11 @@ test("server document decodes and re-encodes the complete page contract", () =>
assert.equal(decoded.revision, 4);
assert.equal(decoded.pages.observation.headerLabel, "Контроль");
assert.equal(decoded.pages.observation.title, "Контроль пространства");
assert.equal(decoded.pages.fleet.background.mediaKind, "video");
assert.equal(encoded.pages.fleet.background.media_kind, "video");
assert.equal(decoded.pages.fleet.background.items.length, 2);
assert.equal(decoded.pages.fleet.background.items[0].mediaKind, "video");
assert.equal(decoded.pages.fleet.background.imageDurationSeconds, 12);
assert.equal(encoded.pages.fleet.background.items[1].media_kind, "image");
assert.equal(encoded.pages.fleet.background.image_duration_seconds, 12);
assert.equal(encoded.pages.fleet.primary_workspace_id, "contour-health");
assert.equal("schema_version" in encoded, false);
});
@@ -115,7 +135,11 @@ test("editing a cloned page cannot mutate accepted settings", () => {
const draft = environment.cloneEnvironmentSettings(accepted);
draft.pages.observation.headerLabel = "Изменено";
draft.pages.fleet.background.enabled = true;
draft.pages.fleet.background.items.push(
environment.createEnvironmentMediaItem(),
);
assert.equal(accepted.pages.observation.headerLabel, "Наблюдение");
assert.equal(accepted.pages.fleet.background.enabled, false);
assert.equal(accepted.pages.fleet.background.items.length, 0);
});