feat(api): block-playout history + sequential-schedule validation endpoints
Adds the REST surface for the #145 troubleshooting leftovers (#158 items 4-5): - GET /api/playouts/{id}/blocks - blocks a block playout schedules - GET /api/playouts/{id}/blocks/{blockId}/history - paged block history - GET /api/playouts/history/{id} - decode a history row by id - POST /api/troubleshoot/validate-schedule - validate sequential YAML New MediatR queries GetPlayoutHistoryDetails (Either, 404 unknown row / 422 malformed JSON) and ValidateSequentialSchedule (wraps ISequentialScheduleValidator, never throws). DecodePlayoutHistoryHandler and the new by-id handler now share PlayoutHistoryDecoder. Regenerated openapi/v1.json. Refs #145 #158 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,8 @@ using System.ComponentModel.DataAnnotations;
|
||||
using ErsatzTV.Application.Playouts;
|
||||
using ErsatzTV.Application.ProgramSchedules;
|
||||
using ErsatzTV.Application.Scheduling;
|
||||
using ErsatzTV.Application.Troubleshooting;
|
||||
using ErsatzTV.Application.Troubleshooting.Queries;
|
||||
using ErsatzTV.Controllers.Api.Requests;
|
||||
using ErsatzTV.Core;
|
||||
using ErsatzTV.Core.Api.Playouts;
|
||||
@@ -18,6 +20,8 @@ namespace ErsatzTV.Controllers.Api;
|
||||
[ApiController]
|
||||
public class PlayoutController(IMediator mediator) : ControllerBase
|
||||
{
|
||||
private const int MaxPageSize = 100;
|
||||
|
||||
[HttpGet("/api/playouts", Name = "GetPlayouts")]
|
||||
[Tags("Playouts")]
|
||||
[EndpointSummary("List playouts")]
|
||||
@@ -430,6 +434,82 @@ public class PlayoutController(IMediator mediator) : ControllerBase
|
||||
return new OkObjectResult(refreshed.OrderBy(i => i.Index).Select(ToResponse).ToList());
|
||||
}
|
||||
|
||||
[HttpGet("/api/playouts/{id:int}/blocks", Name = "GetPlayoutBlocks")]
|
||||
[Tags("Playouts")]
|
||||
[EndpointSummary("Get the blocks scheduled by a block playout")]
|
||||
[EndpointDescription(
|
||||
"Lists the distinct blocks reachable through a Block playout's templates, ordered by group then name. " +
|
||||
"A playout with no templates (including non-Block playouts) returns an empty list.")]
|
||||
[EndpointGroupName("general")]
|
||||
[ProducesResponseType(typeof(List<BlockResponseModel>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> GetBlocks(int id, CancellationToken cancellationToken)
|
||||
{
|
||||
Option<PlayoutNameViewModel> maybePlayout = await mediator.Send(new GetPlayoutById(id), cancellationToken);
|
||||
if (maybePlayout.IsNone)
|
||||
{
|
||||
return ApiResults.NotFoundProblem();
|
||||
}
|
||||
|
||||
List<BlockViewModel> blocks = await mediator.Send(new GetAllBlocksForPlayout(id), cancellationToken);
|
||||
return new OkObjectResult(blocks.Map(ToBlockResponse).ToList());
|
||||
}
|
||||
|
||||
[HttpGet("/api/playouts/{id:int}/blocks/{blockId:int}/history", Name = "GetPlayoutBlockHistory")]
|
||||
[Tags("Playouts")]
|
||||
[EndpointSummary("Get a block's playout history")]
|
||||
[EndpointDescription(
|
||||
"Returns the paged scheduling history for a single block within a block playout, oldest first. Each row's " +
|
||||
"Key and Details carry raw JSON; decode a row via GET /api/playouts/history/{id}.")]
|
||||
[EndpointGroupName("general")]
|
||||
[ProducesResponseType(typeof(PagedPlayoutHistoryResponseModel), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> GetBlockHistory(
|
||||
int id,
|
||||
int blockId,
|
||||
[FromQuery] int pageNum = 0,
|
||||
[FromQuery] int pageSize = 100,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
Option<PlayoutNameViewModel> maybePlayout = await mediator.Send(new GetPlayoutById(id), cancellationToken);
|
||||
if (maybePlayout.IsNone)
|
||||
{
|
||||
return ApiResults.NotFoundProblem();
|
||||
}
|
||||
|
||||
int clampedPageNum = Math.Max(0, pageNum);
|
||||
int clampedPageSize = Math.Clamp(pageSize, 1, MaxPageSize);
|
||||
|
||||
PagedPlayoutHistoryViewModel result = await mediator.Send(
|
||||
new GetBlockPlayoutHistory(id, blockId, clampedPageNum, clampedPageSize),
|
||||
cancellationToken);
|
||||
|
||||
return new OkObjectResult(
|
||||
new PagedPlayoutHistoryResponseModel(
|
||||
result.TotalCount,
|
||||
result.Page.Map(ToHistoryResponse).ToList()));
|
||||
}
|
||||
|
||||
[HttpGet("/api/playouts/history/{id:int}", Name = "GetPlayoutHistoryDetails")]
|
||||
[Tags("Playouts")]
|
||||
[EndpointSummary("Decode a playout history row")]
|
||||
[EndpointDescription(
|
||||
"Decodes a single playout history row (by its id) into its playback order, collection, and media-item " +
|
||||
"details. Returns 422 if the row's stored Key/Details JSON cannot be decoded.")]
|
||||
[EndpointGroupName("general")]
|
||||
[ProducesResponseType(typeof(PlayoutHistoryDetailsResponseModel), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status422UnprocessableEntity)]
|
||||
public async Task<IActionResult> GetHistoryDetails(int id, CancellationToken cancellationToken)
|
||||
{
|
||||
Either<BaseError, PlayoutHistoryDetailsViewModel> result =
|
||||
await mediator.Send(new GetPlayoutHistoryDetails(id), cancellationToken);
|
||||
|
||||
return result.Match(
|
||||
Left: error => error.ToErrorResult(),
|
||||
Right: vm => (IActionResult)new OkObjectResult(ToDetailsResponse(vm)));
|
||||
}
|
||||
|
||||
[HttpPost("/api/playouts/reset-all", Name = "ResetAllPlayouts")]
|
||||
[Tags("Playouts")]
|
||||
[EndpointSummary("Reset all playouts")]
|
||||
@@ -501,6 +581,15 @@ public class PlayoutController(IMediator mediator) : ControllerBase
|
||||
return Option<BaseError>.None;
|
||||
}
|
||||
|
||||
private static BlockResponseModel ToBlockResponse(BlockViewModel vm) =>
|
||||
new(vm.Id, vm.GroupId, vm.GroupName, vm.Name, vm.Minutes, vm.StopScheduling);
|
||||
|
||||
private static PlayoutHistoryResponseModel ToHistoryResponse(PlayoutHistoryViewModel vm) =>
|
||||
new(vm.Id, vm.When, vm.Finish, vm.Key, vm.Details);
|
||||
|
||||
private static PlayoutHistoryDetailsResponseModel ToDetailsResponse(PlayoutHistoryDetailsViewModel vm) =>
|
||||
new(vm.PlaybackOrder, vm.CollectionType, vm.Name, vm.MediaItemType, vm.MediaItemTitle);
|
||||
|
||||
private static PlayoutResponseModel ToResponse(PlayoutNameViewModel vm) =>
|
||||
PlayoutResponseModel.From(
|
||||
vm.PlayoutId,
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
using ErsatzTV.Application.Troubleshooting.Queries;
|
||||
|
||||
namespace ErsatzTV.Controllers.Api.Requests;
|
||||
|
||||
public record ValidateSequentialScheduleRequest(string Yaml, bool IsImport)
|
||||
{
|
||||
public ValidateSequentialSchedule ToQuery() => new(Yaml, IsImport);
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.IO.Abstractions;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
@@ -6,6 +7,7 @@ using ErsatzTV.Application;
|
||||
using ErsatzTV.Application.MediaItems;
|
||||
using ErsatzTV.Application.Troubleshooting;
|
||||
using ErsatzTV.Application.Troubleshooting.Queries;
|
||||
using ErsatzTV.Controllers.Api.Requests;
|
||||
using ErsatzTV.Core;
|
||||
using ErsatzTV.Core.Api.Troubleshooting;
|
||||
using ErsatzTV.Core.Domain;
|
||||
@@ -71,6 +73,36 @@ public class TroubleshootController(
|
||||
info.VideoToolboxCapabilities);
|
||||
}
|
||||
|
||||
[HttpPost("api/troubleshoot/validate-schedule", Name = "ValidateSequentialSchedule")]
|
||||
[Tags("Troubleshooting")]
|
||||
[EndpointSummary("Validate a sequential schedule YAML document")]
|
||||
[EndpointDescription(
|
||||
"Validates a sequential-schedule YAML string against the full (or import) schema. Returns whether it is " +
|
||||
"valid, any validation messages, and the JSON conversion of the YAML. Parse/validator errors are reported " +
|
||||
"as messages (IsValid=false), never as a 500.")]
|
||||
[EndpointGroupName("general")]
|
||||
[ProducesResponseType(typeof(ValidateSequentialScheduleResponseModel), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
|
||||
public async Task<IActionResult> ValidateSchedule(
|
||||
[Required] [FromBody] ValidateSequentialScheduleRequest request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(request.Yaml))
|
||||
{
|
||||
return new BadRequestObjectResult(
|
||||
new ProblemDetails
|
||||
{
|
||||
Status = StatusCodes.Status400BadRequest,
|
||||
Title = "Validation failed",
|
||||
Detail = "[Yaml] must not be empty"
|
||||
});
|
||||
}
|
||||
|
||||
ValidateSequentialScheduleViewModel result = await mediator.Send(request.ToQuery(), cancellationToken);
|
||||
return new OkObjectResult(
|
||||
new ValidateSequentialScheduleResponseModel(result.IsValid, result.Messages, result.Json));
|
||||
}
|
||||
|
||||
[HttpHead("api/troubleshoot/playback.m3u8")]
|
||||
[HttpGet("api/troubleshoot/playback.m3u8")]
|
||||
[Tags("Troubleshooting")]
|
||||
|
||||
@@ -6315,6 +6315,251 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/playouts/{id}/blocks": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Playouts"
|
||||
],
|
||||
"summary": "Get the blocks scheduled by a block playout",
|
||||
"description": "Lists the distinct blocks reachable through a Block playout's templates, ordered by group then name. A playout with no templates (including non-Block playouts) returns an empty list.",
|
||||
"operationId": "GetPlayoutBlocks",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"content": {
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/BlockResponseModel"
|
||||
}
|
||||
}
|
||||
},
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/BlockResponseModel"
|
||||
}
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/BlockResponseModel"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"content": {
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/playouts/{id}/blocks/{blockId}/history": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Playouts"
|
||||
],
|
||||
"summary": "Get a block's playout history",
|
||||
"description": "Returns the paged scheduling history for a single block within a block playout, oldest first. Each row's Key and Details carry raw JSON; decode a row via GET /api/playouts/history/{id}.",
|
||||
"operationId": "GetPlayoutBlockHistory",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "blockId",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "pageNum",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "pageSize",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"default": 100
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"content": {
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PagedPlayoutHistoryResponseModel"
|
||||
}
|
||||
},
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PagedPlayoutHistoryResponseModel"
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PagedPlayoutHistoryResponseModel"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"content": {
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/playouts/history/{id}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Playouts"
|
||||
],
|
||||
"summary": "Decode a playout history row",
|
||||
"description": "Decodes a single playout history row (by its id) into its playback order, collection, and media-item details. Returns 422 if the row's stored Key/Details JSON cannot be decoded.",
|
||||
"operationId": "GetPlayoutHistoryDetails",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"content": {
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PlayoutHistoryDetailsResponseModel"
|
||||
}
|
||||
},
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PlayoutHistoryDetailsResponseModel"
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PlayoutHistoryDetailsResponseModel"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"content": {
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Unprocessable Entity",
|
||||
"content": {
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/playouts/reset-all": {
|
||||
"post": {
|
||||
"tags": [
|
||||
@@ -10164,6 +10409,83 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/troubleshoot/validate-schedule": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Troubleshooting"
|
||||
],
|
||||
"summary": "Validate a sequential schedule YAML document",
|
||||
"description": "Validates a sequential-schedule YAML string against the full (or import) schema. Returns whether it is valid, any validation messages, and the JSON conversion of the YAML. Parse/validator errors are reported as messages (IsValid=false), never as a 500.",
|
||||
"operationId": "ValidateSequentialSchedule",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json-patch+json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ValidateSequentialScheduleRequest"
|
||||
}
|
||||
},
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ValidateSequentialScheduleRequest"
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ValidateSequentialScheduleRequest"
|
||||
}
|
||||
},
|
||||
"application/*+json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ValidateSequentialScheduleRequest"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"content": {
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ValidateSequentialScheduleResponseModel"
|
||||
}
|
||||
},
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ValidateSequentialScheduleResponseModel"
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ValidateSequentialScheduleResponseModel"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"content": {
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/troubleshoot/playback.m3u8": {
|
||||
"head": {
|
||||
"tags": [
|
||||
@@ -15149,6 +15471,25 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"PagedPlayoutHistoryResponseModel": {
|
||||
"required": [
|
||||
"totalCount",
|
||||
"page"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"totalCount": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"page": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/PlayoutHistoryResponseModel"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"PagedPlayoutItemsResponseModel": {
|
||||
"required": [
|
||||
"totalCount",
|
||||
@@ -15509,6 +15850,63 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"PlayoutHistoryDetailsResponseModel": {
|
||||
"required": [
|
||||
"playbackOrder",
|
||||
"collectionType",
|
||||
"name",
|
||||
"mediaItemType",
|
||||
"mediaItemTitle"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"playbackOrder": {
|
||||
"$ref": "#/components/schemas/PlaybackOrder"
|
||||
},
|
||||
"collectionType": {
|
||||
"$ref": "#/components/schemas/CollectionType"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"mediaItemType": {
|
||||
"type": "string"
|
||||
},
|
||||
"mediaItemTitle": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PlayoutHistoryResponseModel": {
|
||||
"required": [
|
||||
"id",
|
||||
"when",
|
||||
"finish",
|
||||
"key",
|
||||
"details"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"when": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"finish": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"details": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PlayoutItemResponseModel": {
|
||||
"required": [
|
||||
"title",
|
||||
@@ -18276,6 +18674,46 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ValidateSequentialScheduleRequest": {
|
||||
"required": [
|
||||
"yaml",
|
||||
"isImport"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"yaml": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"isImport": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ValidateSequentialScheduleResponseModel": {
|
||||
"required": [
|
||||
"isValid",
|
||||
"messages",
|
||||
"json"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"isValid": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"messages": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"json": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"WatermarkFullResponseModel": {
|
||||
"required": [
|
||||
"id",
|
||||
|
||||
Reference in New Issue
Block a user