Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add required as a tag type attribute #4430

Merged
merged 8 commits into from
Feb 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
"""Adds required column to tag_type
Revision ID: 27e6558e26a8
Revises: 0283f2bbe9dd
Create Date: 2024-02-21 14:08:48.787183

"""
from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision = "27e6558e26a8"
down_revision = "0283f2bbe9dd"
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column("tag_type", sa.Column("required", sa.Boolean(), nullable=True))
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column("tag_type", "required")
# ### end Alembic commands ###
49 changes: 41 additions & 8 deletions src/dispatch/static/dispatch/src/tag/TagPicker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
variant="outlined"
v-model="dummyText"
class="main-panel"
:rules="[is_tag_in_project]"
:rules="[check_for_error]"
>
<template #prepend-inner>
<v-icon class="panel-button">
Expand Down Expand Up @@ -80,7 +80,7 @@
:style="getBackgroundColorAsStyle(group.color)"
/>
<strong v-text="group.label" />
<!-- <span v-show="group.isRequired" class="tag-group-rule">Required</span> -->
<span v-show="group.isRequired" class="tag-group-rule">Required</span>
<span v-show="group.isExclusive" class="tag-group-rule">Exclusive</span>
<span class="tag-group-icon-down"><v-icon>mdi-chevron-down</v-icon></span>
<v-icon class="tag-group-icon-up">mdi-chevron-up</v-icon>
Expand Down Expand Up @@ -187,10 +187,23 @@ watch(
validateTags(selectedItems.value)
}
)
const is_tag_in_project = () => {
const check_for_error = () => {
return error.value
}

function are_required_tags_selected(sel) {
// iterate through all tag types and ensure that at least one tag of each required tag type is selected
const tagTypes = groups.value
for (let i = 0; i < tagTypes.length; i++) {
if (tagTypes[i].isRequired) {
if (!sel.some((item) => item.tag_type?.id === tagTypes[i]?.id)) {
return false
}
}
}
return true
}

const fetchData = () => {
loading.value = true

Expand Down Expand Up @@ -260,6 +273,7 @@ const fetchData = () => {
}
groups.value = convertData(items.value)
loading.value = false
validateTags(selectedItems.value)
})
}

Expand All @@ -269,14 +283,33 @@ const emit = defineEmits(["update:modelValue"])

function validateTags(value) {
const project_id = props.project?.id || 0
const all_tags_in_project = value.every((tag) => tag.project?.id == project_id)
var all_tags_in_project = false
if (project_id) {
all_tags_in_project = value.every((tag) => tag.project?.id == project_id)
} else {
const project_name = props.project?.name
if (!project_name) {
error.value = true
dummyText.value += " "
return
}
all_tags_in_project = value.every((tag) => tag.project?.name == project_name)
}
if (all_tags_in_project) {
error.value = true
dummyText.value += " "
if (are_required_tags_selected(value)) {
error.value = true
} else {
const required_tag_types = groups.value
.filter((tag_type) => tag_type.isRequired)
.map((tag_type) => tag_type.label)
error.value = `Please select at least one tag from each required category (${required_tag_types.join(
", "
)})`
}
} else {
error.value = "Only tags in selected project are allowed"
dummyText.value += " "
}
dummyText.value += " "
}

const selectedItems = computed({
Expand Down Expand Up @@ -356,7 +389,7 @@ const convertData = (data) => {
label: a.tag_type.name,
desc: a.tag_type.description,
color: a.tag_type.color,
// isRequired: a.tag_type.required,
isRequired: a.tag_type.required,
isExclusive: a.tag_type.exclusive,
menuItems: [],
}
Expand Down
22 changes: 21 additions & 1 deletion src/dispatch/static/dispatch/src/tag_type/NewEditSheet.vue
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,26 @@
<template #activator="{ props }">
<v-icon class="mt-4" v-bind="props">mdi-information</v-icon>
</template>
<span> If activated, only one tag of this type is allowed per incident. </span>
<span>
If activated, only one tag of this type is allowed per discoverable type.
</span>
</v-tooltip>
</v-col>
<v-col cols="5">
<v-checkbox
v-model="required"
label="Required"
hint="Is this tag type required for new entities of the discoverable types?"
/>
</v-col>
<v-col cols="7">
<v-tooltip max-width="500px" open-delay="50" location="bottom">
<template #activator="{ props }">
<v-icon class="mt-4" v-bind="props">mdi-information</v-icon>
</template>
<span>
If activated, at least one tag of this type is required per discoverable type.
</span>
</v-tooltip>
</v-col>
</v-row>
Expand Down Expand Up @@ -170,6 +189,7 @@ export default {
"selected.icon",
"selected.color",
"selected.exclusive",
"selected.required",
"selected.loading",
]),
...mapFields("tag_type", {
Expand Down
1 change: 1 addition & 0 deletions src/dispatch/static/dispatch/src/tag_type/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const getDefaultSelectedState = () => {
project: null,
default: false,
exclusive: false,
required: false,
icon: null,
color: null,
discoverable: true,
Expand Down
2 changes: 2 additions & 0 deletions src/dispatch/tag_type/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class TagType(Base, TimeStampMixin, ProjectMixin):
name = Column(String)
description = Column(String)
exclusive = Column(Boolean, default=False)
required = Column(Boolean, default=False)
discoverable_case = Column(Boolean, default=True)
discoverable_incident = Column(Boolean, default=True)
discoverable_query = Column(Boolean, default=True)
Expand All @@ -38,6 +39,7 @@ class TagType(Base, TimeStampMixin, ProjectMixin):
class TagTypeBase(DispatchBase):
name: NameStr
exclusive: Optional[bool] = False
required: Optional[bool] = False
discoverable_case: Optional[bool] = True
discoverable_incident: Optional[bool] = True
discoverable_query: Optional[bool] = True
Expand Down
Loading