идентификаторы удалений, заготовки
This commit is contained in:
@@ -2561,13 +2561,11 @@ function startCustomTooltips() {
|
||||
state.config.tabs = (Array.isArray(state.config.tabs) ? state.config.tabs : []).filter((tab) => tab?.id !== "prematch");
|
||||
state.config.components = components.filter((component) => component?.type !== "hockey_prematch_panel" && component?.action_id !== "hockey_prematch_panel");
|
||||
if (!state.config.tabs.length) state.config.tabs = [{ id: "main", label: "Игра" }];
|
||||
// BUILD84: "Заготовки" is a built-in runtime workspace rather than a canvas
|
||||
// component. Keep it near the game tab and recreate it if an older config
|
||||
// does not contain it yet.
|
||||
if (!state.config.tabs.some((tab) => tab?.id === "prepared_titles")) {
|
||||
const mainIndex = Math.max(0, state.config.tabs.findIndex((tab) => tab?.id === "main"));
|
||||
state.config.tabs.splice(mainIndex + 1, 0, { id: "prepared_titles", label: "Заготовки" });
|
||||
}
|
||||
// BUILD86: "Заготовки" is always the final top-level runtime tab.
|
||||
// Reorder it on every config normalisation as older published configs may
|
||||
// already contain the tab near "Игра" from BUILD84/85.
|
||||
state.config.tabs = state.config.tabs.filter((tab) => tab?.id !== "prepared_titles");
|
||||
state.config.tabs.push({ id: "prepared_titles", label: "Заготовки" });
|
||||
if (state.activeTab === "prematch") state.activeTab = state.config.tabs.find((tab) => tab.id === "main")?.id || state.config.tabs[0].id;
|
||||
}
|
||||
|
||||
@@ -8934,7 +8932,15 @@ function hockeyPreparedNumber(value, fallback = 999999) {
|
||||
function hockeyPreparedInventoryInputs() {
|
||||
const inventory = state.preparedTitleInventory?.inventory || {};
|
||||
return (Array.isArray(inventory.inputs) ? inventory.inputs : [])
|
||||
.filter((item) => item && typeof item === "object" && Array.isArray(item.fields) && item.fields.length)
|
||||
.filter((item) => {
|
||||
if (!item || typeof item !== "object") return false;
|
||||
const fields = Array.isArray(item.fields) ? item.fields : [];
|
||||
const type = String(item.type || "").trim();
|
||||
// BUILD86: keep title Inputs visible even when an older Agent inventory
|
||||
// did not yet include their child fields. This makes the left-hand title
|
||||
// browser useful instead of showing an empty list.
|
||||
return fields.length > 0 || /(?:^|\b)(GT|XAML|TITLE)(?:$|\b)/i.test(type);
|
||||
})
|
||||
.slice()
|
||||
.sort((a, b) => hockeyPreparedNumber(a.number) - hockeyPreparedNumber(b.number) || String(a.title || "").localeCompare(String(b.title || ""), "ru", { numeric: true, sensitivity: "base" }));
|
||||
}
|
||||
@@ -8978,6 +8984,8 @@ function hockeyPreparedWorkspaceKey() {
|
||||
return [currentRuntimeVmixDeviceId(), hockeyTimerSelectedGameId()].join("|");
|
||||
}
|
||||
|
||||
// BUILD86: direct backend endpoint family: /api/hockey/prepared-titles
|
||||
// hockeyGameControlRequest() adds the /api/hockey prefix exactly once.
|
||||
async function hockeyLoadPreparedMappingSources(panelId = state.preparedTitlePanelId, { render = false } = {}) {
|
||||
const clean = String(panelId || "").trim();
|
||||
if (!clean) {
|
||||
@@ -8990,7 +8998,7 @@ async function hockeyLoadPreparedMappingSources(panelId = state.preparedTitlePan
|
||||
const deviceId = currentRuntimeVmixDeviceId();
|
||||
if (deviceId) params.set("device_id", deviceId);
|
||||
params.set("panel_id", clean);
|
||||
const payload = await api(`/api/hockey/prepared-titles/mapping-sources?${params.toString()}`);
|
||||
const payload = await hockeyGameControlRequest(`/prepared-titles/mapping-sources?${params.toString()}`);
|
||||
state.preparedTitleMappingSources = Array.isArray(payload?.items) ? payload.items : [];
|
||||
if (!state.preparedTitleSourceKey && state.preparedTitleMappingSources.length === 1) {
|
||||
const source = state.preparedTitleMappingSources[0];
|
||||
@@ -9030,10 +9038,26 @@ async function hockeyLoadPreparedTitlesWorkspace({ force = false, render = true
|
||||
const listParams = new URLSearchParams();
|
||||
if (deviceId) listParams.set("device_id", deviceId);
|
||||
if (gameId) listParams.set("game_id", gameId);
|
||||
const [inventoryPayload, preparedPayload] = await Promise.all([
|
||||
api(`/api/hockey/agents/vmix-inventory${invParams.toString() ? `?${invParams}` : ""}`),
|
||||
api(`/api/hockey/prepared-titles${listParams.toString() ? `?${listParams}` : ""}`),
|
||||
]);
|
||||
let inventoryPayload = null;
|
||||
try {
|
||||
inventoryPayload = await hockeyGameControlRequest(`/agents/vmix-inventory${invParams.toString() ? `?${invParams}` : ""}`);
|
||||
} catch (inventoryError) {
|
||||
// A browser can retain an obsolete locally-selected Agent id. Retry the
|
||||
// active account Agent before giving up, so the title browser still opens.
|
||||
if (deviceId) {
|
||||
inventoryPayload = await hockeyGameControlRequest("/agents/vmix-inventory");
|
||||
} else {
|
||||
throw inventoryError;
|
||||
}
|
||||
}
|
||||
let preparedPayload = { items: [] };
|
||||
try {
|
||||
preparedPayload = await hockeyGameControlRequest(`/prepared-titles${listParams.toString() ? `?${listParams}` : ""}`);
|
||||
} catch (preparedListError) {
|
||||
console.error("Prepared titles saved-list error", preparedListError);
|
||||
// Saved-list failure must not hide the source title inventory/editor.
|
||||
preparedPayload = { items: [] };
|
||||
}
|
||||
state.preparedTitleInventory = inventoryPayload || { device_id: "", device_name: "", inventory: { inputs: [] } };
|
||||
state.preparedTitles = Array.isArray(preparedPayload?.items) ? preparedPayload.items : [];
|
||||
state.preparedTitlesLoadedKey = key;
|
||||
@@ -9088,7 +9112,7 @@ async function hockeyApplyPreparedMappingSnapshot() {
|
||||
if (input.number) params.set("input_number", input.number);
|
||||
if (input.title) params.set("input_title", input.title);
|
||||
if (state.preparedTitlePanelId) params.set("panel_id", state.preparedTitlePanelId);
|
||||
const payload = await api(`/api/hockey/prepared-titles/mapping-snapshot?${params.toString()}`);
|
||||
const payload = await hockeyGameControlRequest(`/prepared-titles/mapping-snapshot?${params.toString()}`);
|
||||
const fields = Array.isArray(payload?.fields) ? payload.fields : [];
|
||||
if (!fields.length) {
|
||||
toast(state.preparedTitlePanelId ? "Для этого блока и Input нет Mapping-связей" : "Для этого Input нет Mapping-связей", true);
|
||||
@@ -9130,7 +9154,7 @@ async function hockeyCreatePreparedTitle() {
|
||||
state.preparedTitlesLoading = true;
|
||||
renderRuntime();
|
||||
try {
|
||||
const payload = await api("/api/hockey/prepared-titles", {
|
||||
const payload = await hockeyGameControlRequest("/prepared-titles", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
@@ -9163,7 +9187,7 @@ async function hockeyCreatePreparedTitle() {
|
||||
|
||||
async function hockeyPreviewPreparedTitle(id) {
|
||||
try {
|
||||
await api(`/api/hockey/prepared-titles/${encodeURIComponent(id)}/preview`, {
|
||||
await hockeyGameControlRequest(`/prepared-titles/${encodeURIComponent(id)}/preview`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ device_id: currentRuntimeVmixDeviceId(), session_token: currentRuntimeHockeySessionToken() }),
|
||||
@@ -9179,7 +9203,7 @@ async function hockeyPreviewPreparedTitle(id) {
|
||||
async function hockeyDeletePreparedTitle(id) {
|
||||
if (!confirm("Убрать заготовку из списка? Сам vMix Input останется в проекте.")) return false;
|
||||
try {
|
||||
await api(`/api/hockey/prepared-titles/${encodeURIComponent(id)}`, { method: "DELETE" });
|
||||
await hockeyGameControlRequest(`/prepared-titles/${encodeURIComponent(id)}`, { method: "DELETE" });
|
||||
state.preparedTitles = state.preparedTitles.filter((item) => String(item.id) !== String(id));
|
||||
renderRuntime();
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user