diff --git a/src/dispatch/static/dispatch/src/events/ReportSubmissionCard.vue b/src/dispatch/static/dispatch/src/events/ReportSubmissionCard.vue index 8fd780afd5c2..791bb416c79c 100644 --- a/src/dispatch/static/dispatch/src/events/ReportSubmissionCard.vue +++ b/src/dispatch/static/dispatch/src/events/ReportSubmissionCard.vue @@ -65,9 +65,13 @@ import { required } from "@/util/form" import { mapFields } from "vuex-map-fields" import { mapActions } from "vuex" +import { resolveProject } from "@/util/project" import router from "@/router" import CasePrioritySelect from "@/case/priority/CasePrioritySelect.vue" +import CaseTypeApi from "@/case/type/api" +import CasePriorityApi from "@/case/priority/api" +import CaseSeverityApi from "@/case/severity/api" export default { setup() { @@ -83,6 +87,7 @@ export default { formIsValid: false, titleValid: false, descriptionValid: false, + projectValid: false, page_oncall: false, items: [], } @@ -102,6 +107,8 @@ export default { "selected.project", "selected.id", "selected.case_priority", + "selected.case_type", + "selected.case_severity", "selected.event", "default_project", ]), @@ -117,6 +124,10 @@ export default { this.descriptionValid = !!this.description this.checkFormValidity() }, + project() { + this.projectValid = !!this.project + this.checkFormValidity() + }, }, methods: { @@ -131,13 +142,128 @@ export default { } }, checkFormValidity() { - this.formIsValid = this.titleValid && this.descriptionValid + this.formIsValid = this.titleValid && this.descriptionValid && this.projectValid + }, + + loadDefaults(project) { + // Load default case type for the project + CaseTypeApi.getAll({ + filter: JSON.stringify({ + and: [ + { + model: "Project", + field: "id", + op: "==", + value: project.id, + }, + { + field: "default", + op: "==", + value: true, + }, + ], + }), + }).then((response) => { + if (response.data.items.length) { + this.case_type = response.data.items[0] + } + }) + + // Load default case severity for the project + CaseSeverityApi.getAll({ + filter: JSON.stringify({ + and: [ + { + model: "Project", + field: "id", + op: "==", + value: project.id, + }, + { + field: "default", + op: "==", + value: true, + }, + ], + }), + }).then((response) => { + if (response.data.items.length) { + this.case_severity = response.data.items[0] + } + }) + + // Load default case priority for the project + CasePriorityApi.getAll({ + filter: JSON.stringify({ + and: [ + { + model: "Project", + field: "id", + op: "==", + value: project.id, + }, + { + field: "default", + op: "==", + value: true, + }, + ], + }), + }).then((response) => { + if (response.data.items.length) { + this.case_priority = response.data.items[0] + } + }) + + // Set other defaults + this.visibility = "Open" }, + + fetchData() { + // If project is not available yet, we'll load priorities later in onProjectResolved + if (!this.project) { + return + } + + // Load case priority items for the urgent checkbox + CasePriorityApi.getAll({ + filter: JSON.stringify({ + and: [ + { + model: "Project", + field: "id", + op: "==", + value: this.project.id, + }, + ], + }), + }).then((response) => { + this.items = response.data.items + }) + }, + ...mapActions("case_management", ["report", "get", "resetSelected"]), }, created() { this.event = true + this.dedicated_channel = true + + // Use the utility function to resolve the project + resolveProject({ + component: this, + onProjectResolved: (project) => { + // Project has been resolved and set + this.projectValid = !!this.project + this.checkFormValidity() + + // Auto-populate defaults based on the project + this.loadDefaults(project) + + // Fetch case priority items now that we have a project + this.fetchData() + }, + }) if (this.$route.query.title) { this.title = this.$route.query.title @@ -148,12 +274,14 @@ export default { if (this.$route.query.description) { this.description = this.$route.query.description } - this.fetchData() + + // We'll call fetchData after project is resolved this.$watch( (vm) => [vm.project, vm.title, vm.description], () => { var queryParams = { + project: this.project ? this.project.name : null, title: this.title, description: this.description, } diff --git a/src/dispatch/static/dispatch/src/util/project.js b/src/dispatch/static/dispatch/src/util/project.js new file mode 100644 index 000000000000..94c53f792623 --- /dev/null +++ b/src/dispatch/static/dispatch/src/util/project.js @@ -0,0 +1,108 @@ +import ProjectApi from "@/project/api" +import AuthApi from "@/auth/api" + +/** + * Resolves a project for a component based on various fallback strategies + * + * @param {Object} options - Configuration options + * @param {Object} options.component - Vue component instance (for accessing this.project, this.default_project) + * @param {Function} options.onProjectResolved - Callback when project is resolved + * @param {Boolean} options.setDirectly - Whether to set component.project directly (default: true) + * @returns {Promise} - Promise that resolves when project resolution is complete + */ +export const resolveProject = async ({ component, onProjectResolved, setDirectly = true }) => { + // Check if project is already set + if (component.project) { + return component.project + } + + // Try to get project from URL query parameters + if (component.$route && component.$route.query.project) { + const params = { + filter: { field: "name", op: "==", value: component.$route.query.project }, + } + + try { + const response = await ProjectApi.getAll(params) + if (response.data.items.length) { + const project = response.data.items[0] + if (setDirectly) { + component.project = project + } + if (onProjectResolved) { + onProjectResolved(project) + } + return project + } + } catch (error) { + console.error("Error fetching project from query params:", error) + } + } + + // Try to get project from user's projects + if (component.projects && component.projects.length) { + const project = component.projects[0].project + if (setDirectly) { + component.project = project + } + if (onProjectResolved) { + onProjectResolved(project) + } + return project + } + + // Try to get user's default project or organization default + try { + const response = await AuthApi.getUserInfo() + + // If project was set while waiting for API response, exit + if (component.project) { + return component.project + } + + // Check for user's default project + const defaultUserProject = response.data.projects.filter((v) => v.default === true) + if (defaultUserProject.length) { + const project = defaultUserProject[0].project + if (setDirectly) { + component.project = project + } + if (onProjectResolved) { + onProjectResolved(project) + } + return project + } + + // Try component's default_project + if (component.default_project) { + if (setDirectly) { + component.project = component.default_project + } + if (onProjectResolved) { + onProjectResolved(component.default_project) + } + return component.default_project + } + + // Last resort: get organization default project + const defaultParams = { + filter: { field: "default", op: "==", value: true }, + } + + const projectResponse = await ProjectApi.getAll(defaultParams) + if (projectResponse.data.items.length) { + const project = projectResponse.data.items[0] + if (setDirectly) { + component.project = project + } + if (onProjectResolved) { + onProjectResolved(project) + } + return project + } + } catch (error) { + console.error("Error resolving project:", error) + } + + return null +}