mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-11 18:33:53 +00:00
expose mcp server in ontime
This commit is contained in:
@@ -16,7 +16,7 @@ import {
|
||||
deleteAllEntries,
|
||||
deleteEntries,
|
||||
deleteRundown,
|
||||
duplicateRundown,
|
||||
duplicateExistingRundown,
|
||||
editEntry,
|
||||
groupEntries,
|
||||
loadRundown,
|
||||
@@ -107,7 +107,7 @@ router.post(
|
||||
paramsWithId,
|
||||
async (req: Request, res: Response<ProjectRundownsList | ErrorResponse>) => {
|
||||
try {
|
||||
const projectRundowns = await duplicateRundown(req.params.id);
|
||||
const projectRundowns = await duplicateExistingRundown(req.params.id);
|
||||
res.status(201).json({ loaded: getCurrentRundown().id, rundowns: normalisedToRundownArray(projectRundowns) });
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error);
|
||||
|
||||
@@ -643,7 +643,7 @@ export function isCurrentRundown(id: string) {
|
||||
/**
|
||||
* @throws if the provided id does not exist
|
||||
*/
|
||||
export function loadRundown(id: string) {
|
||||
export async function loadRundown(id: string) {
|
||||
const dataProvider = getDataProvider();
|
||||
if (isCurrentRundown(id)) {
|
||||
return dataProvider.getProjectRundowns();
|
||||
@@ -651,7 +651,7 @@ export function loadRundown(id: string) {
|
||||
|
||||
const rundown = dataProvider.getRundown(id);
|
||||
const customField = dataProvider.getCustomFields();
|
||||
initRundown(rundown, customField);
|
||||
await initRundown(rundown, customField);
|
||||
return dataProvider.getProjectRundowns();
|
||||
}
|
||||
|
||||
@@ -659,7 +659,11 @@ export function loadRundown(id: string) {
|
||||
* Sets a new rundown in the cache
|
||||
* and marks it as the currently loaded one
|
||||
*/
|
||||
export function initRundown(rundown: Readonly<Rundown>, customFields: Readonly<CustomFields>, reload: boolean = false) {
|
||||
export async function initRundown(
|
||||
rundown: Readonly<Rundown>,
|
||||
customFields: Readonly<CustomFields>,
|
||||
reload: boolean = false,
|
||||
) {
|
||||
runtimeService.stop();
|
||||
const { rundownMetadata, revision } = rundownCache.init(rundown, customFields);
|
||||
logger.info(LogOrigin.Server, `Switch to rundown: ${rundown.id}`);
|
||||
@@ -690,36 +694,14 @@ export async function createNewRundown(title: string) {
|
||||
}
|
||||
|
||||
/**
|
||||
* duplicate a rundown
|
||||
* @throws
|
||||
*/
|
||||
export async function duplicateRundown(id: string) {
|
||||
const dataProvider = getDataProvider();
|
||||
const rundown = dataProvider.getRundown(id);
|
||||
|
||||
const newRundownId = generateId();
|
||||
const newRundown: Rundown = structuredClone(rundown);
|
||||
newRundown.id = newRundownId;
|
||||
newRundown.title = `Copy of ${rundown.title}`;
|
||||
newRundown.revision = 0;
|
||||
|
||||
const newProjectRundowns = await dataProvider.setRundown(newRundownId, newRundown);
|
||||
|
||||
setImmediate(() => {
|
||||
sendRefetch(RefetchKey.ProjectRundowns);
|
||||
});
|
||||
|
||||
return newProjectRundowns;
|
||||
}
|
||||
|
||||
/**
|
||||
* rename a rundown
|
||||
* @throws
|
||||
* Renames an existing rundown
|
||||
* @throws if the provided id does not exist
|
||||
*/
|
||||
export async function renameRundown(id: string, title: string) {
|
||||
const dataProvider = getDataProvider();
|
||||
const rundown = dataProvider.getRundown(id);
|
||||
const newProjectRundowns = await dataProvider.setRundown(rundown.id, { ...rundown, title });
|
||||
|
||||
await dataProvider.setRundown(id, { ...rundown, title });
|
||||
|
||||
/**
|
||||
* If we are modifying the loaded rundown we re-init it
|
||||
@@ -728,33 +710,58 @@ export async function renameRundown(id: string, title: string) {
|
||||
if (isCurrentRundown(id)) {
|
||||
const rundown = dataProvider.getRundown(id);
|
||||
const customField = dataProvider.getCustomFields();
|
||||
initRundown(rundown, customField);
|
||||
// init rundown does its own refetch
|
||||
await initRundown(rundown, customField);
|
||||
} else {
|
||||
setImmediate(() => {
|
||||
sendRefetch(RefetchKey.ProjectRundowns);
|
||||
});
|
||||
}
|
||||
|
||||
return newProjectRundowns;
|
||||
return dataProvider.getProjectRundowns();
|
||||
}
|
||||
|
||||
/**
|
||||
* delete a rundown
|
||||
* @throws
|
||||
* Duplicates an existing rundown without making it the loaded one
|
||||
* @throws if the provided id does not exist
|
||||
*/
|
||||
export async function deleteRundown(id: string) {
|
||||
if (isCurrentRundown(id)) throw new Error('Cannot delete loaded rundown');
|
||||
|
||||
export async function duplicateExistingRundown(id: string) {
|
||||
const dataProvider = getDataProvider();
|
||||
const projectRundowns = dataProvider.getProjectRundowns();
|
||||
const rundown = dataProvider.getRundown(id);
|
||||
|
||||
// might never hit this as it is likely covered by the case of trying to delete the loaded rundown
|
||||
if (Object.keys(projectRundowns).length <= 1) throw new Error('Cannot delete the last rundown');
|
||||
const newProjectRundowns = await dataProvider.deleteRundown(id);
|
||||
const duplicatedRundown: Rundown = structuredClone(rundown);
|
||||
duplicatedRundown.id = generateId();
|
||||
duplicatedRundown.title = `Copy of ${rundown.title}`;
|
||||
duplicatedRundown.revision = 0;
|
||||
|
||||
await dataProvider.setRundown(duplicatedRundown.id, duplicatedRundown);
|
||||
|
||||
setImmediate(() => {
|
||||
sendRefetch(RefetchKey.ProjectRundowns);
|
||||
});
|
||||
|
||||
return newProjectRundowns;
|
||||
return dataProvider.getProjectRundowns();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a rundown
|
||||
* @throws if attempting to delete the loaded rundown or the last rundown in the project
|
||||
*/
|
||||
export async function deleteRundown(id: string) {
|
||||
if (isCurrentRundown(id)) {
|
||||
throw new Error('Cannot delete loaded rundown');
|
||||
}
|
||||
|
||||
const dataProvider = getDataProvider();
|
||||
if (Object.keys(dataProvider.getProjectRundowns()).length <= 1) {
|
||||
throw new Error('Cannot delete the last rundown');
|
||||
}
|
||||
|
||||
const projectRundowns = await dataProvider.deleteRundown(id);
|
||||
|
||||
setImmediate(() => {
|
||||
sendRefetch(RefetchKey.ProjectRundowns);
|
||||
});
|
||||
|
||||
return projectRundowns;
|
||||
}
|
||||
|
||||
@@ -34,43 +34,34 @@ import {
|
||||
|
||||
import { RundownMetadata } from './rundown.types.js';
|
||||
|
||||
type CompleteEntry<T> =
|
||||
T extends Partial<OntimeEvent>
|
||||
? OntimeEvent
|
||||
: T extends Partial<OntimeDelay>
|
||||
? OntimeDelay
|
||||
: T extends Partial<OntimeGroup>
|
||||
? OntimeGroup
|
||||
: T extends Partial<OntimeMilestone>
|
||||
? OntimeMilestone
|
||||
: never;
|
||||
|
||||
/**
|
||||
* Generates a fully formed RundownEntry of the patch type
|
||||
*/
|
||||
export function generateEvent<
|
||||
T extends Partial<OntimeEvent> | Partial<OntimeDelay> | Partial<OntimeGroup> | Partial<OntimeMilestone>,
|
||||
>(rundown: Rundown, eventData: T, afterId: EntryId | null, parent?: EntryId): CompleteEntry<T> {
|
||||
export function generateEvent(
|
||||
rundown: Rundown,
|
||||
eventData: Partial<OntimeEvent> | Partial<OntimeDelay> | Partial<OntimeGroup> | Partial<OntimeMilestone>,
|
||||
afterId: EntryId | null,
|
||||
parent?: EntryId,
|
||||
): OntimeEntry {
|
||||
if (isOntimeEvent(eventData)) {
|
||||
return createEvent(
|
||||
eventData,
|
||||
getCueCandidate(rundown.entries, rundown.flatOrder, afterId, parent),
|
||||
) as CompleteEntry<T>;
|
||||
const event = createEvent(eventData, getCueCandidate(rundown.entries, rundown.flatOrder, afterId, parent));
|
||||
if (!event) throw new Error('Invalid event type');
|
||||
return event;
|
||||
}
|
||||
|
||||
const id = eventData.id || getUniqueId(rundown);
|
||||
|
||||
if (isOntimeDelay(eventData)) {
|
||||
return createDelay({ duration: eventData.duration ?? 0, id }) as CompleteEntry<T>;
|
||||
return createDelay({ duration: eventData.duration ?? 0, id });
|
||||
}
|
||||
|
||||
// TODO(v4): allow user to provide a larger patch of the group entry
|
||||
if (isOntimeGroup(eventData)) {
|
||||
return createGroup({ id, title: eventData.title ?? '' }) as CompleteEntry<T>;
|
||||
return createGroup({ id, title: eventData.title ?? '' });
|
||||
}
|
||||
|
||||
if (isOntimeMilestone(eventData)) {
|
||||
return createMilestone({ ...eventData, id }) as CompleteEntry<T>;
|
||||
return createMilestone({ ...eventData, id });
|
||||
}
|
||||
|
||||
throw new Error('Invalid event type');
|
||||
|
||||
Reference in New Issue
Block a user