SeedCompany / cord-api-v3

Bible translation project management API
MIT License
18 stars 4 forks source link

Project Workflow v2 #3236

Closed CarsonF closed 3 weeks ago

CarsonF commented 1 month ago

https://seed-company-squad.monday.com/boards/5989610236/pulses/6639688582

github-actions[bot] commented 1 month ago

🗞 GraphQL Summary

View schema changes ```diff @@ -1608,8 +1608,28 @@ """ transition: ID } +input ExecuteProjectTransitionInput { + """ + Bypass the workflow, and go straight to this state. + `transition` is not required and ignored when using this. + """ + bypassTo: ProjectStep + + """Any additional user notes related to this transition""" + notes: RichText + + """The project ID to transition""" + project: ID! + + """ + The transition `key` to execute. + This is required unless specifying bypassing the workflow with a `step` input. + """ + transition: ID +} + """ First scripture that has been created but managed _outside_ of CORD. `hasFirst` will always be true. """ type ExternalFirstScripture implements FirstScripture { @@ -2233,8 +2253,9 @@ """The project members""" team(input: ProjectMemberListInput = {count: 25, filter: {}, order: ASC, page: 1, sort: "createdAt"}): SecuredProjectMemberList! type: ProjectType! + workflowEvents: [ProjectWorkflowEvent!]! } type InternshipProjectListOutput implements PaginatedList { """Whether the next page exists""" @@ -2731,8 +2752,9 @@ """The project members""" team(input: ProjectMemberListInput = {count: 25, filter: {}, order: ASC, page: 1, sort: "createdAt"}): SecuredProjectMemberList! type: ProjectType! + workflowEvents: [ProjectWorkflowEvent!]! } input MoveFileInput { """The file or directory's ID""" @@ -2847,8 +2869,9 @@ """The project members""" team(input: ProjectMemberListInput = {count: 25, filter: {}, order: ASC, page: 1, sort: "createdAt"}): SecuredProjectMemberList! type: ProjectType! + workflowEvents: [ProjectWorkflowEvent!]! } type Mutation { """Add a location to a language""" @@ -3101,8 +3124,9 @@ """ pinned: Boolean ): Boolean! transitionProgressReport(input: ExecuteProgressReportTransitionInput!): ProgressReport! + transitionProject(input: ExecuteProjectTransitionInput!): Project! """Update a budget""" updateBudget(input: UpdateBudgetInput!): UpdateBudgetOutput! @@ -4423,8 +4447,9 @@ """The project members""" team(input: ProjectMemberListInput = {count: 25, filter: {}, order: ASC, page: 1, sort: "createdAt"}): SecuredProjectMemberList! type: ProjectType! + workflowEvents: [ProjectWorkflowEvent!]! } type ProjectChangeRequest implements Changeset & Resource { """Whether the changes have been applied to live data""" @@ -4627,19 +4652,35 @@ PendingReactivationApproval PendingRegionalDirectorApproval PendingSuspensionApproval PendingTerminationApproval + + """@label Pending Field Operations Approval""" PendingZoneDirectorApproval PrepForConsultantEndorsement PrepForFinancialEndorsement Rejected Suspended Terminated } +""" +A transition for the project workflow. + +This is not a normalized entity. +A transition represented by its `key` can have different field values +based on the workflow's state. +""" type ProjectStepTransition { disabled: Boolean! disabledReason: String + + """ + An local identifier for this transition. + It cannot be used to globally identify a transition. + It is passed to the transition mutation. + """ + key: ID! label: String! to: ProjectStep! type: TransitionType! } @@ -4672,8 +4713,19 @@ projectTypes: [ProjectType!]! user: ID! } +type ProjectWorkflowEvent { + at: DateTime! + id: ID! + notes: SecuredRichTextNullable! + to: ProjectStep! + + """The transition taken, null if workflow was bypassed""" + transition: ProjectStepTransition + who: SecuredActor! +} + type Prompt { """Whether the requesting user can delete this resource""" canDelete: Boolean! createdAt: DateTime! @@ -4878,8 +4930,9 @@ """Look up project members""" projectMembers(input: ProjectMemberListInput = {count: 25, filter: {}, order: ASC, page: 1, sort: "createdAt"}): ProjectMemberListOutput! @deprecated(reason: "Query via project instead") projectTypeFinancialApprovers(projectTypes: [ProjectType!]): [ProjectTypeFinancialApprover!]! + projectWorkflow: Workflow! """Look up projects""" projects(input: ProjectListInput = {count: 25, filter: {}, order: ASC, page: 1, sort: "name"}): ProjectListOutput! @@ -5194,8 +5247,19 @@ canRead: Boolean! } """ +An object with a actor `value` and additional authorization information. +The value is only given if `canRead` is `true` otherwise it is `null`. +These `can*` authorization properties are specific to the user making the request. +""" +type SecuredActor implements Secured { + canEdit: Boolean! + canRead: Boolean! + value: Actor +} + +""" An object with a boolean `value` and additional authorization information. The value is only given if `canRead` is `true` otherwise it is `null`. These `can*` authorization properties are specific to the user making the request. """ @@ -6167,15 +6231,15 @@ """ type SecuredProjectStep implements Secured { """ Is the current user allowed to bypass transitions entirely - and change the step to any other step? + and change to any other state? """ canBypassTransitions: Boolean! canEdit: Boolean! canRead: Boolean! - """The available steps a project can be transitioned to.""" + """The transitions currently available to execute for this project""" transitions: [ProjectStepTransition!]! value: ProjectStep } @@ -6657,8 +6721,9 @@ """The project members""" team(input: ProjectMemberListInput = {count: 25, filter: {}, order: ASC, page: 1, sort: "createdAt"}): SecuredProjectMemberList! type: ProjectType! + workflowEvents: [ProjectWorkflowEvent!]! } type TranslationProjectListOutput implements PaginatedList { """Whether the next page exists""" @@ -7558,4 +7623,69 @@ """ download: Boolean! = false ): URL! } + +type Workflow { + id: ID! + states: [WorkflowState!]! + transitions: [WorkflowTransition!]! +} + +type WorkflowCondition { + label: String! +} + +type WorkflowNotifier { + label: String! +} + +type WorkflowState { + label: String! + value: String! +} + +type WorkflowTransition { + conditions: [WorkflowCondition!]! + devName: String! + from: [WorkflowState!]! + key: ID! + label: String! + notifiers: [WorkflowNotifier!]! + permissions: [WorkflowTransitionPermission!]! + to: WorkflowTransitionTo! + type: TransitionType! +} + +type WorkflowTransitionDynamicTo { + id: ID! + label: String! + relatedStates: [WorkflowState!]! +} + +""" +A permission for a transition. + +This will either have `readEvent` or `execute` as a boolean, +specifying the action this permission defines. +If this is true, there could still be a condition that must be met, +described by the `condition` field. +""" +type WorkflowTransitionPermission { + """ + The action for this permission is conditional, described by this field. + """ + condition: String + + """Can this role execute this transition?""" + execute: Boolean + + """Can this role read historical events for this transition?""" + readEvent: Boolean + role: Role! +} + +type WorkflowTransitionStaticTo { + state: WorkflowState! +} + +union WorkflowTransitionTo = WorkflowTransitionDynamicTo | WorkflowTransitionStaticTo ```
atGit2021 commented 3 weeks ago

@CarsonF Where did you handle the condition for internships and the requirement that project managers should not be able to approve the consultant endorsement step? I didn't see it, so wasn't sure if you added it to this PR or you were planning to add it to a different PR.

CarsonF commented 3 weeks ago

I may have missed it. Going to follow up in another PR with business logic changes. Much easier to discuss now that the workflow can be visualized.