diff --git a/caster-back/gencaster/schema.py b/caster-back/gencaster/schema.py index d8db5834..b1231b21 100644 --- a/caster-back/gencaster/schema.py +++ b/caster-back/gencaster/schema.py @@ -54,6 +54,7 @@ ScriptCell, ScriptCellInputCreate, ScriptCellInputUpdate, + UpdateGraphInput, create_python_highlight_string, ) from stream.exceptions import NoStreamAvailableException @@ -486,6 +487,23 @@ async def add_graph(self, info, graph_input: AddGraphInput) -> Graph: # https://docs.djangoproject.com/en/4.2/ref/models/instances/#django.db.models.Model.arefresh_from_db return await story_graph_models.Graph.objects.aget(uuid=graph.uuid) # type: ignore + @strawberry.mutation + async def update_graph( + self, info, graph_input: UpdateGraphInput, graph_uuid: uuid.UUID + ) -> Graph: + await graphql_check_authenticated(info) + + graph = await story_graph_models.Graph.objects.aget(uuid=graph_uuid) + + for key, value in graph_input.__dict__.items(): + if value == strawberry.UNSET: + continue + graph.__setattr__(key, value) + + await graph.asave() + + return graph # type: ignore + @strawberry.mutation async def add_audio_file(self, info, new_audio_file: AddAudioFile) -> AudioFileUploadResponse: # type: ignore if new_audio_file.file is None or len(new_audio_file.file) == 0: diff --git a/caster-back/operations.gql b/caster-back/operations.gql index e2ef38d9..5e3a9158 100644 --- a/caster-back/operations.gql +++ b/caster-back/operations.gql @@ -208,6 +208,25 @@ subscription node($uuid: UUID!) { } } +fragment GraphMetaData on Graph { + uuid + templateName + startText + slugName + name + endText + displayName + aboutText + streamAssignmentPolicy + publicVisible +} + +query GetGraph($graphUuid:ID!) { + graph(pk: $graphUuid) { + ...GraphMetaData + } +} + mutation CreateGraph($graphInput: AddGraphInput!) { addGraph(graphInput: $graphInput) { name @@ -220,6 +239,15 @@ mutation CreateGraph($graphInput: AddGraphInput!) { } } +mutation UpdateGraph($graphUuid:UUID!, $graphUpdate: UpdateGraphInput!) { + updateGraph( + graphInput: $graphUpdate + graphUuid: $graphUuid + ) { + uuid + } +} + subscription stream($graphUuid: UUID!) { streamInfo(graphUuid: $graphUuid) { __typename diff --git a/caster-back/schema.gql b/caster-back/schema.gql index b3f6906f..227ab87b 100644 --- a/caster-back/schema.gql +++ b/caster-back/schema.gql @@ -47,7 +47,7 @@ input AddGraphInput { publicVisible: Boolean """Manages the stream assignment for this graph""" - streamAssignmentPolicy: String + streamAssignmentPolicy: StreamAssignmentPolicy """ Allows to switch to a different template in the frontend with different connection flows or UI @@ -360,6 +360,14 @@ type Graph { """ templateName: GraphDetailTemplate! + """Manages the stream assignment for this graph""" + streamAssignmentPolicy: StreamAssignmentPolicy! + + """ + If the graph is not public it will not be listed in the frontend, yet it is still accessible via URL + """ + publicVisible: Boolean! + """ Text about the graph which will be displayed at the start of a stream - only if this is set """ @@ -492,6 +500,7 @@ type Mutation { """Deletes a given :class:`~story_graph.models.ScriptCell`.""" deleteScriptCell(scriptCellUuid: UUID!): Void addGraph(graphInput: AddGraphInput!): Graph! + updateGraph(graphInput: UpdateGraphInput!, graphUuid: UUID!): Graph! addAudioFile(newAudioFile: AddAudioFile!): AudioFileUploadResponse! createUpdateStreamVariable(streamVariables: [StreamVariableInput!]!): [StreamVariable!]! createNodeDoor(nodeDoorInput: NodeDoorInputCreate!, nodeUuid: UUID!): NodeDoor! @@ -758,6 +767,13 @@ type Stream { streamPoint: StreamPoint! } +"""An enumeration.""" +enum StreamAssignmentPolicy { + ONE_GRAPH_ONE_STREAM + ONE_USER_ONE_STREAM + DEACTIVATE +} + type StreamInfo { stream: Stream! streamInstruction: StreamInstruction @@ -930,6 +946,53 @@ input UpdateAudioFile { name: String } +""" +A collection of :class:`~Node` and :class:`~Edge`. +This can be considered a score as well as a program as it +has an entry point as a :class:`~Node` and can jump to any +other :class:`~Node`, also allowing for recursive loops/cycles. + +Each node can be considered a little program on its own which can consist +of multiple :class:`~ScriptCell` which can be coded in a variety of +languages which can control the frontend and the audio (by e.g. speaking +on the stream) or setting a background music. + +The story graph is a core concept and can be edited with a native editor. +""" +input UpdateGraphInput { + """Name of the graph""" + name: String + + """Will be used as a display name in the frontend""" + displayName: String + + """ + Text about the graph which will be displayed at the start of a stream - only if this is set + """ + startText: String + + """ + Text about the graph which can be accessed during a stream - only if this is set + """ + aboutText: String + + """Text which will be displayed at the end of a stream""" + endText: String + + """ + If the graph is not public it will not be listed in the frontend, yet it is still accessible via URL + """ + publicVisible: Boolean + + """Manages the stream assignment for this graph""" + streamAssignmentPolicy: StreamAssignmentPolicy + + """ + Allows to switch to a different template in the frontend with different connection flows or UI + """ + templateName: GraphDetailTemplate +} + scalar Upload """ diff --git a/caster-back/story_graph/types.py b/caster-back/story_graph/types.py index 20f19a23..749a8ebd 100644 --- a/caster-back/story_graph/types.py +++ b/caster-back/story_graph/types.py @@ -22,6 +22,7 @@ PlaybackType = strawberry.enum(models.AudioCell.PlaybackChoices) # type: ignore TemplateType = strawberry.enum(models.Graph.GraphDetailTemplate) # type: ignore NodeDoorType = strawberry.enum(models.NodeDoor.DoorType) # type: ignore +StreamAssignmentPolicy = strawberry.enum(models.Graph.StreamAssignmentPolicy) # type: ignore def create_python_highlight_string(e: SyntaxError) -> str: @@ -85,6 +86,8 @@ class Graph: display_name: auto slug_name: auto template_name: TemplateType + stream_assignment_policy: StreamAssignmentPolicy + public_visible: auto start_text: auto about_text: auto end_text: auto @@ -95,6 +98,31 @@ def edges(self) -> List["Edge"]: return models.Edge.objects.filter(out_node_door__node__graph=self) # type: ignore +@strawberry.django.input(models.Graph) +class AddGraphInput: + name: auto + display_name: auto + slug_name: auto + start_text: auto + about_text: auto + end_text: auto + public_visible: auto + stream_assignment_policy: StreamAssignmentPolicy + template_name: TemplateType + + +@strawberry.django.input(model=models.Graph, partial=True) +class UpdateGraphInput: + name: auto + display_name: auto + start_text: auto + about_text: auto + end_text: auto + public_visible: auto + stream_assignment_policy: StreamAssignmentPolicy + template_name: TemplateType + + @strawberry.django.type(models.Node) class Node: uuid: auto @@ -210,16 +238,3 @@ class ScriptCellInputUpdate: cell_code: Optional[str] cell_order: Optional[int] audio_cell: Optional[AudioCellInput] - - -@strawberry.django.input(models.Graph) -class AddGraphInput: - name: auto - display_name: auto - slug_name: auto - start_text: auto - about_text: auto - end_text: auto - public_visible: auto - stream_assignment_policy: auto - template_name: TemplateType diff --git a/caster-editor/src/assets/scss/_elementplus.scss b/caster-editor/src/assets/scss/_elementplus.scss index baf31ff6..5b5463ae 100644 --- a/caster-editor/src/assets/scss/_elementplus.scss +++ b/caster-editor/src/assets/scss/_elementplus.scss @@ -142,6 +142,19 @@ border: none; } +.el-loading-mask { + // background-color: $white-transparent; + color: #{$black}; +} + +.el-loading-spinner .el-loading-text { + color: #{$black}; +} + +.el-loading-spinner .path { + stroke: #{$black}; +} + /* OLD */ .messages-editor { diff --git a/caster-editor/src/components/MenuTabEdit.vue b/caster-editor/src/components/MenuTabEdit.vue index 6ed7c67e..0b143931 100644 --- a/caster-editor/src/components/MenuTabEdit.vue +++ b/caster-editor/src/components/MenuTabEdit.vue @@ -54,8 +54,9 @@ const removeSelection = async () => { }); if (error) { ElMessage.error(`Could not delete edge ${edgeUuid}: ${error.message}`); + } else { + ElMessage.info(`Deleted edge ${edgeUuid}`); } - ElMessage.info(`Deleted edge ${edgeUuid}`); }); selectedNodeUUIDs.value.forEach(async (nodeUuid) => { @@ -64,8 +65,9 @@ const removeSelection = async () => { }); if (error) { ElMessage.error(`Could not delete node ${nodeUuid}: ${error.message}`); + } else { + ElMessage.info(`Deleted node ${nodeUuid}`); } - ElMessage.info(`Deleted node ${nodeUuid}`); }); }; diff --git a/caster-editor/src/components/MenuTabHeader.vue b/caster-editor/src/components/MenuTabHeader.vue index 893716b4..fa888932 100644 --- a/caster-editor/src/components/MenuTabHeader.vue +++ b/caster-editor/src/components/MenuTabHeader.vue @@ -1,3 +1,10 @@ + + - - diff --git a/caster-editor/src/components/Meta.vue b/caster-editor/src/components/Meta.vue new file mode 100644 index 00000000..4fe432db --- /dev/null +++ b/caster-editor/src/components/Meta.vue @@ -0,0 +1,264 @@ + + + + + + diff --git a/caster-editor/src/components/Wysiwyg.vue b/caster-editor/src/components/Wysiwyg.vue new file mode 100644 index 00000000..ffd39754 --- /dev/null +++ b/caster-editor/src/components/Wysiwyg.vue @@ -0,0 +1,83 @@ + + + + + + diff --git a/caster-editor/src/graphql.ts b/caster-editor/src/graphql.ts index a734c295..9940e210 100644 --- a/caster-editor/src/graphql.ts +++ b/caster-editor/src/graphql.ts @@ -63,7 +63,7 @@ export type AddGraphInput = { /** Text about the graph which will be displayed at the start of a stream - only if this is set */ startText?: InputMaybe; /** Manages the stream assignment for this graph */ - streamAssignmentPolicy?: InputMaybe; + streamAssignmentPolicy?: InputMaybe; /** Allows to switch to a different template in the frontend with different connection flows or UI */ templateName?: InputMaybe; }; @@ -362,10 +362,14 @@ export type Graph = { /** Name of the graph */ name: Scalars["String"]; nodes: Array; + /** If the graph is not public it will not be listed in the frontend, yet it is still accessible via URL */ + publicVisible: Scalars["Boolean"]; /** Will be used as a URL */ slugName: Scalars["String"]; /** Text about the graph which will be displayed at the start of a stream - only if this is set */ startText: Scalars["String"]; + /** Manages the stream assignment for this graph */ + streamAssignmentPolicy: StreamAssignmentPolicy; /** Allows to switch to a different template in the frontend with different connection flows or UI */ templateName: GraphDetailTemplate; uuid: Scalars["UUID"]; @@ -478,6 +482,7 @@ export type Mutation = { deleteScriptCell?: Maybe; /** Update metadata of an :class:`~stream.models.AudioFile` via a UUID */ updateAudioFile: AudioFile; + updateGraph: Graph; /** * Updates a given :class:`~story_graph.models.Node` which can be used * for renaming or moving it across the canvas. @@ -556,6 +561,12 @@ export type MutationUpdateAudioFileArgs = { uuid: Scalars["UUID"]; }; +/** Mutations for Gencaster via GraphQL. */ +export type MutationUpdateGraphArgs = { + graphInput: UpdateGraphInput; + graphUuid: Scalars["UUID"]; +}; + /** Mutations for Gencaster via GraphQL. */ export type MutationUpdateNodeArgs = { nodeUpdate: NodeUpdate; @@ -858,6 +869,13 @@ export type Stream = { uuid: Scalars["UUID"]; }; +/** An enumeration. */ +export enum StreamAssignmentPolicy { + Deactivate = "DEACTIVATE", + OneGraphOneStream = "ONE_GRAPH_ONE_STREAM", + OneUserOneStream = "ONE_USER_ONE_STREAM", +} + export type StreamInfo = { stream: Stream; streamInstruction?: Maybe; @@ -1037,6 +1055,38 @@ export type UpdateAudioFile = { name?: InputMaybe; }; +/** + * A collection of :class:`~Node` and :class:`~Edge`. + * This can be considered a score as well as a program as it + * has an entry point as a :class:`~Node` and can jump to any + * other :class:`~Node`, also allowing for recursive loops/cycles. + * + * Each node can be considered a little program on its own which can consist + * of multiple :class:`~ScriptCell` which can be coded in a variety of + * languages which can control the frontend and the audio (by e.g. speaking + * on the stream) or setting a background music. + * + * The story graph is a core concept and can be edited with a native editor. + */ +export type UpdateGraphInput = { + /** Text about the graph which can be accessed during a stream - only if this is set */ + aboutText?: InputMaybe; + /** Will be used as a display name in the frontend */ + displayName?: InputMaybe; + /** Text which will be displayed at the end of a stream */ + endText?: InputMaybe; + /** Name of the graph */ + name?: InputMaybe; + /** If the graph is not public it will not be listed in the frontend, yet it is still accessible via URL */ + publicVisible?: InputMaybe; + /** Text about the graph which will be displayed at the start of a stream - only if this is set */ + startText?: InputMaybe; + /** Manages the stream assignment for this graph */ + streamAssignmentPolicy?: InputMaybe; + /** Allows to switch to a different template in the frontend with different connection flows or UI */ + templateName?: InputMaybe; +}; + /** * Users within the Django authentication system are represented by this * model. @@ -1312,6 +1362,38 @@ export type NodeSubscription = { }; }; +export type GraphMetaDataFragment = { + uuid: any; + templateName: GraphDetailTemplate; + startText: string; + slugName: string; + name: string; + endText: string; + displayName: string; + aboutText: string; + streamAssignmentPolicy: StreamAssignmentPolicy; + publicVisible: boolean; +}; + +export type GetGraphQueryVariables = Exact<{ + graphUuid: Scalars["ID"]; +}>; + +export type GetGraphQuery = { + graph: { + uuid: any; + templateName: GraphDetailTemplate; + startText: string; + slugName: string; + name: string; + endText: string; + displayName: string; + aboutText: string; + streamAssignmentPolicy: StreamAssignmentPolicy; + publicVisible: boolean; + }; +}; + export type CreateGraphMutationVariables = Exact<{ graphInput: AddGraphInput; }>; @@ -1324,6 +1406,13 @@ export type CreateGraphMutation = { }; }; +export type UpdateGraphMutationVariables = Exact<{ + graphUuid: Scalars["UUID"]; + graphUpdate: UpdateGraphInput; +}>; + +export type UpdateGraphMutation = { updateGraph: { uuid: any } }; + export type StreamSubscriptionVariables = Exact<{ graphUuid: Scalars["UUID"]; }>; @@ -1674,6 +1763,20 @@ export const NodeDoorDetailFragmentDoc = gql` doorType } `; +export const GraphMetaDataFragmentDoc = gql` + fragment GraphMetaData on Graph { + uuid + templateName + startText + slugName + name + endText + displayName + aboutText + streamAssignmentPolicy + publicVisible + } +`; export const StreamInfoFragmentFragmentDoc = gql` fragment StreamInfoFragment on Stream { uuid @@ -1981,6 +2084,20 @@ export function useNodeSubscription( handler, ); } +export const GetGraphDocument = gql` + query GetGraph($graphUuid: ID!) { + graph(pk: $graphUuid) { + ...GraphMetaData + } + } + ${GraphMetaDataFragmentDoc} +`; + +export function useGetGraphQuery( + options: Omit, "query"> = {}, +) { + return Urql.useQuery({ query: GetGraphDocument, ...options }); +} export const CreateGraphDocument = gql` mutation CreateGraph($graphInput: AddGraphInput!) { addGraph(graphInput: $graphInput) { @@ -2000,6 +2117,19 @@ export function useCreateGraphMutation() { CreateGraphDocument, ); } +export const UpdateGraphDocument = gql` + mutation UpdateGraph($graphUuid: UUID!, $graphUpdate: UpdateGraphInput!) { + updateGraph(graphInput: $graphUpdate, graphUuid: $graphUuid) { + uuid + } + } +`; + +export function useUpdateGraphMutation() { + return Urql.useMutation( + UpdateGraphDocument, + ); +} export const StreamDocument = gql` subscription stream($graphUuid: UUID!) { streamInfo(graphUuid: $graphUuid) { diff --git a/caster-editor/src/stores/InterfaceStore.ts b/caster-editor/src/stores/InterfaceStore.ts index 3720670c..f9668c95 100644 --- a/caster-editor/src/stores/InterfaceStore.ts +++ b/caster-editor/src/stores/InterfaceStore.ts @@ -1,5 +1,5 @@ import { defineStore } from "pinia"; -import { type Ref, ref, computed } from "vue"; +import { type Ref, ref, computed, watch } from "vue"; import { type NodeSubscription, type ScriptCellInputUpdate, @@ -14,6 +14,7 @@ import { ElMessage } from "element-plus"; export enum Tab { Edit = "Edit", Play = "Play", + Meta = "Meta", } // some hack to avoid @@ -31,6 +32,12 @@ export const useInterfaceStore = defineStore("interface", () => { const tab: Ref = ref(Tab.Edit); + watch(tab, (newValue, oldValue) => { + if (oldValue == Tab.Edit && newValue == Tab.Meta) { + showNodeEditor.value = false; + } + }); + // this acts as a clutch between our local changes and the // updates from the server. const cachedNodeData: Ref = ref(undefined); diff --git a/caster-editor/src/views/GraphDetailView.vue b/caster-editor/src/views/GraphDetailView.vue index 8c4ab461..7994b61f 100644 --- a/caster-editor/src/views/GraphDetailView.vue +++ b/caster-editor/src/views/GraphDetailView.vue @@ -3,13 +3,14 @@ import { storeToRefs } from "pinia"; import { watch } from "vue"; import { useRoute, useRouter } from "vue-router"; import Graph from "@/components/Graph.vue"; +import Meta from "@/components/Meta.vue"; import Menu from "@/components/Menu.vue"; import NodeEditor from "@/components/NodeEditor.vue"; -import { useInterfaceStore } from "@/stores/InterfaceStore"; +import { useInterfaceStore, Tab } from "@/stores/InterfaceStore"; import { useGraphSubscription } from "@/graphql"; import { ElMessage } from "element-plus"; -const { showNodeEditor, selectedNodeForEditorUuid } = storeToRefs( +const { showNodeEditor, selectedNodeForEditorUuid, tab } = storeToRefs( useInterfaceStore(), ); @@ -40,6 +41,11 @@ watch(graphSubscription.error, () => { + + ; /** Manages the stream assignment for this graph */ - streamAssignmentPolicy?: InputMaybe; + streamAssignmentPolicy?: InputMaybe; /** Allows to switch to a different template in the frontend with different connection flows or UI */ templateName?: InputMaybe; }; @@ -362,10 +362,14 @@ export type Graph = { /** Name of the graph */ name: Scalars["String"]; nodes: Array; + /** If the graph is not public it will not be listed in the frontend, yet it is still accessible via URL */ + publicVisible: Scalars["Boolean"]; /** Will be used as a URL */ slugName: Scalars["String"]; /** Text about the graph which will be displayed at the start of a stream - only if this is set */ startText: Scalars["String"]; + /** Manages the stream assignment for this graph */ + streamAssignmentPolicy: StreamAssignmentPolicy; /** Allows to switch to a different template in the frontend with different connection flows or UI */ templateName: GraphDetailTemplate; uuid: Scalars["UUID"]; @@ -478,6 +482,7 @@ export type Mutation = { deleteScriptCell?: Maybe; /** Update metadata of an :class:`~stream.models.AudioFile` via a UUID */ updateAudioFile: AudioFile; + updateGraph: Graph; /** * Updates a given :class:`~story_graph.models.Node` which can be used * for renaming or moving it across the canvas. @@ -556,6 +561,12 @@ export type MutationUpdateAudioFileArgs = { uuid: Scalars["UUID"]; }; +/** Mutations for Gencaster via GraphQL. */ +export type MutationUpdateGraphArgs = { + graphInput: UpdateGraphInput; + graphUuid: Scalars["UUID"]; +}; + /** Mutations for Gencaster via GraphQL. */ export type MutationUpdateNodeArgs = { nodeUpdate: NodeUpdate; @@ -858,6 +869,13 @@ export type Stream = { uuid: Scalars["UUID"]; }; +/** An enumeration. */ +export enum StreamAssignmentPolicy { + Deactivate = "DEACTIVATE", + OneGraphOneStream = "ONE_GRAPH_ONE_STREAM", + OneUserOneStream = "ONE_USER_ONE_STREAM", +} + export type StreamInfo = { stream: Stream; streamInstruction?: Maybe; @@ -1037,6 +1055,38 @@ export type UpdateAudioFile = { name?: InputMaybe; }; +/** + * A collection of :class:`~Node` and :class:`~Edge`. + * This can be considered a score as well as a program as it + * has an entry point as a :class:`~Node` and can jump to any + * other :class:`~Node`, also allowing for recursive loops/cycles. + * + * Each node can be considered a little program on its own which can consist + * of multiple :class:`~ScriptCell` which can be coded in a variety of + * languages which can control the frontend and the audio (by e.g. speaking + * on the stream) or setting a background music. + * + * The story graph is a core concept and can be edited with a native editor. + */ +export type UpdateGraphInput = { + /** Text about the graph which can be accessed during a stream - only if this is set */ + aboutText?: InputMaybe; + /** Will be used as a display name in the frontend */ + displayName?: InputMaybe; + /** Text which will be displayed at the end of a stream */ + endText?: InputMaybe; + /** Name of the graph */ + name?: InputMaybe; + /** If the graph is not public it will not be listed in the frontend, yet it is still accessible via URL */ + publicVisible?: InputMaybe; + /** Text about the graph which will be displayed at the start of a stream - only if this is set */ + startText?: InputMaybe; + /** Manages the stream assignment for this graph */ + streamAssignmentPolicy?: InputMaybe; + /** Allows to switch to a different template in the frontend with different connection flows or UI */ + templateName?: InputMaybe; +}; + /** * Users within the Django authentication system are represented by this * model. @@ -1312,6 +1362,38 @@ export type NodeSubscription = { }; }; +export type GraphMetaDataFragment = { + uuid: any; + templateName: GraphDetailTemplate; + startText: string; + slugName: string; + name: string; + endText: string; + displayName: string; + aboutText: string; + streamAssignmentPolicy: StreamAssignmentPolicy; + publicVisible: boolean; +}; + +export type GetGraphQueryVariables = Exact<{ + graphUuid: Scalars["ID"]; +}>; + +export type GetGraphQuery = { + graph: { + uuid: any; + templateName: GraphDetailTemplate; + startText: string; + slugName: string; + name: string; + endText: string; + displayName: string; + aboutText: string; + streamAssignmentPolicy: StreamAssignmentPolicy; + publicVisible: boolean; + }; +}; + export type CreateGraphMutationVariables = Exact<{ graphInput: AddGraphInput; }>; @@ -1324,6 +1406,13 @@ export type CreateGraphMutation = { }; }; +export type UpdateGraphMutationVariables = Exact<{ + graphUuid: Scalars["UUID"]; + graphUpdate: UpdateGraphInput; +}>; + +export type UpdateGraphMutation = { updateGraph: { uuid: any } }; + export type StreamSubscriptionVariables = Exact<{ graphUuid: Scalars["UUID"]; }>; @@ -1674,6 +1763,20 @@ export const NodeDoorDetailFragmentDoc = gql` doorType } `; +export const GraphMetaDataFragmentDoc = gql` + fragment GraphMetaData on Graph { + uuid + templateName + startText + slugName + name + endText + displayName + aboutText + streamAssignmentPolicy + publicVisible + } +`; export const StreamInfoFragmentFragmentDoc = gql` fragment StreamInfoFragment on Stream { uuid @@ -1981,6 +2084,20 @@ export function useNodeSubscription( handler, ); } +export const GetGraphDocument = gql` + query GetGraph($graphUuid: ID!) { + graph(pk: $graphUuid) { + ...GraphMetaData + } + } + ${GraphMetaDataFragmentDoc} +`; + +export function useGetGraphQuery( + options: Omit, "query"> = {}, +) { + return Urql.useQuery({ query: GetGraphDocument, ...options }); +} export const CreateGraphDocument = gql` mutation CreateGraph($graphInput: AddGraphInput!) { addGraph(graphInput: $graphInput) { @@ -2000,6 +2117,19 @@ export function useCreateGraphMutation() { CreateGraphDocument, ); } +export const UpdateGraphDocument = gql` + mutation UpdateGraph($graphUuid: UUID!, $graphUpdate: UpdateGraphInput!) { + updateGraph(graphInput: $graphUpdate, graphUuid: $graphUuid) { + uuid + } + } +`; + +export function useUpdateGraphMutation() { + return Urql.useMutation( + UpdateGraphDocument, + ); +} export const StreamDocument = gql` subscription stream($graphUuid: UUID!) { streamInfo(graphUuid: $graphUuid) {