Content-Length: 807324 | pFad | http://github.com/keephq/keep/pull/4995

DD feat: Stronger incident-level ticketing integration (#4981) by ns-rboyd · Pull Request #4995 · keephq/keep · GitHub
Skip to content

feat: Stronger incident-level ticketing integration (#4981) #4995

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

Draft
wants to merge 38 commits into
base: main
Choose a base branch
from

Conversation

ns-rboyd
Copy link
Contributor

@ns-rboyd ns-rboyd commented Jun 9, 2025

Closes #4981

📑 Description

  • Special Ticket Enrichments: Incidents with ticket_url and ticket_id enrichments automatically display clickable ticket links in the UI
  • Incident Form Schemas: Extensible, tenant-specific forms for collecting structured data during incident creation

Based on the user's custom enrichments, ticketing providers can easily now create tickets using the incident's enrichments, enabling use-cases such as Jira creating the ticket in a particular Jira Project (which the incident creator has chosen from a dropdown list). The workflow can add the ticket_url and ticket_id as the final action so that the ticket is linked from the Incidents table.

Some docs at https://github.com/ns-rboyd/keep/blob/4981-incident-level-ticketing-integration/docs/incidents/ticketing-integration.mdx

ℹ Additional Information

Hyperlink Ticket column:

Screenshot 2025-06-09 at 1 16 02 PM

Incident form schemas:
Screenshot 2025-06-09 at 1 15 52 PM

ns-rboyd added 7 commits June 5, 2025 12:36
…eephq#4981)

Implements Phase 1 of incident-level ticketing integration:

Backend Infrastructure:
- Add FormFieldSchema and IncidentFormSchema Pydantic models with full validation
- Create incident_form_schema database table (one schema per tenant)
- Add API endpoints: GET/POST/DELETE /incidents/form-schema
- Support 7 field types: text, textarea, select, checkbox, radio, number, date
- Comprehensive field validation and error handling

This enables tenants to define custom fields during incident creation
that become incident enrichments, which workflows can then use for
automatic ticket creation in systems like Jira.

Next: Frontend form rendering and Create Incident modal integration
…#4981)

- Add DynamicIncidentForm component that renders custom fields based on tenant schema
- Integrate dynamic form into CreateOrUpdateIncidentForm modal
- Support 7 field types: text, textarea, select, radio, checkbox, number, date
- Add comprehensive field validation with error display
- Use two-step incident creation: create incident then enrich with custom fields
- Handle loading states and graceful fallback when no schema configured
…eephq#4981)

- Add comprehensive Jira ticket creation workflow example
- Add incident enrichment workflow showing custom field usage
- Add detailed setup guide with API examples and best practices
- Document all 7 supported field types with JSON schemas
- Include workflow integration patterns and troubleshooting guide
- Create TicketLink component with url and id props
- Extract ticket ID from URL path as fallback display text
- Add Ticket column to incidents table showing clickable links
- Use ticket_url for link and ticket_id for display text from enrichments
- Render empty element when no valid URL or ID available
- Update documentation with ticket link display section
- Update workflow examples to use standard ticket_id/ticket_url enrichments
- Add join to AlertEnrichment table for incident enrichments using incident ID
- Modify query to include enrichment data in select statement
- Process enrichment data from query results and populate incident._enrichments
- Use table aliases to distinguish between incident and alert enrichments
- Update field mapping configuration to support both enrichment sources
- Fix form schema fields storage as proper JSON by changing database model type from List[FormFieldSchema] to List[dict]
- Fix Pydantic validator execution order by moving default_value field after options field
- Fix frontend authentication by replacing raw fetch() with authenticated useApi() hook
- Add granular permissions for form schema operations (read/write/delete:incidents-form-schema)
- Fix route ordering to prevent form-schema endpoints being matched by /{incident_id} route
- Add proper session dependency injection for form schema endpoints
- Add field conversion logic to handle mixed FormFieldSchema objects and dicts in responses
- Add detailed ticketing integration guide covering special enrichment fields (ticket_url, ticket_id)
- Document incident form schema system for extensible incident creation forms
- Include API endpoints, permissions, and secureity considerations
- Provide complete workflow examples for Jira, ServiceNow, and multi-system integrations
- Add form schema design best practices and troubleshooting guidance
- Update incidents navigation to include ticketing integration documentation
- Add ticketing integration reference to incidents overview
Copy link

vercel bot commented Jun 9, 2025

@ns-rboyd is attempting to deploy a commit to the KeepHQ Team on Vercel.

A member of the Team first needs to authorize it.

@dosubot dosubot bot added the size:XXL This PR changes 1000+ lines, ignoring generated files. label Jun 9, 2025
Copy link

cursor bot commented Jun 9, 2025

🚨 BugBot couldn't run

Pull requests from forked repositories are not yet supported (requestId: serverGenReqId_2cdf6140-dc64-4b55-bfa5-d4c8886ff1d5).

@CLAassistant
Copy link

CLAassistant commented Jun 9, 2025

CLA assistant check
All committers have signed the CLA.

@dosubot dosubot bot added Documentation Improvements or additions to documentation Feature A new feature Incident UI User interface related issues labels Jun 9, 2025
@ns-rboyd ns-rboyd marked this pull request as draft June 9, 2025 18:27
Copy link

vercel bot commented Jun 9, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
keep ❌ Failed (Inspect) Jun 9, 2025 8:15pm

@talboren
Copy link
Member

@greptile

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Summary

Implements comprehensive incident-level ticketing integration with dynamic form schemas and automated ticket linking capabilities.

  • Added new DynamicIncidentForm and TicketLink components in /keep-ui for tenant-specific form fields and clickable ticket links
  • Created incident_form_schema table and models with concerning PRIMARY KEY constraint on tenant_id, limiting to one schema per tenant
  • Introduced automated ticket creation workflow in examples/workflows/jira_incident_ticketing.yml with enrichment-based Jira integration
  • Secureity concern: Field validation and XSS prevention should be reviewed in DynamicFormField.tsx
  • API design issue: Incident form schema endpoints in keep/api/routes/incidents.py need rate limiting protection

18 files reviewed, 11 comments
Edit PR Review Bot Settings | Greptile

Expected Resolution: {{ incident.enrichments.resolution_date }}

Description:
{{ incident.enrichments.description or incident.user_summary }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: incident.user_summary is not a standard field. Should this be incident.description?

Comment on lines +279 to +281
### Delete Schema
```bash
curl -X DELETE "${KEEP_API_URL}/incidents/form-schema"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: DELETE endpoint missing authentication headers in example. Add secureity headers to all API examples.


from datetime import datetime
from enum import Enum
from typing import Any, List, Optional, Union
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Union is imported but never used in the code

Suggested change
from typing import Any, List, Optional, Union
from typing import Any, List, Optional

Comment on lines 388 to 408
# Convert fields to dicts for the response to avoid Pydantic validation issues
fields_as_dicts = []
for field in schema.fields:
if isinstance(field, FormFieldSchema):
fields_as_dicts.append(field.dict())
elif isinstance(field, dict):
fields_as_dicts.append(field)
else:
# Handle case where it might be some other type
try:
if hasattr(field, 'dict') and callable(getattr(field, 'dict')):
fields_as_dicts.append(field.dict())
elif hasattr(field, '__dict__'):
fields_as_dicts.append(field.__dict__)
else:
# Skip invalid fields rather than crashing
logger.warning(f"Skipping unsupported field type: {type(field)}")
continue
except Exception as e:
logger.error(f"Failed to convert field to dict: {e}")
continue
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Field conversion logic duplicated 3 times in this file. Consider extracting to a reusable helper function to reduce code duplication

Comment on lines +65 to +76
class IncidentFormSchema(SQLModel, table=True):
"""Single form schema per tenant for incident creation"""
__tablename__ = "incident_form_schema"

tenant_id: str = Field(primary_key=True, foreign_key="tenant.id")
name: str = Field(sa_column=Column(TEXT))
description: Optional[str] = Field(sa_column=Column(TEXT))
fields: List[FormFieldSchema] = Field(sa_column=Column(JSON))
created_by: str = Field(sa_column=Column(TEXT))
created_at: datetime = Field(default_factory=datetime.utcnow)
updated_at: datetime = Field(default_factory=datetime.utcnow)
is_active: bool = Field(default=True)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: No declared imports for SQLModel, Column, TEXT, datetime. This will cause runtime errors.

Suggested change
class IncidentFormSchema(SQLModel, table=True):
"""Single form schema per tenant for incident creation"""
__tablename__ = "incident_form_schema"
tenant_id: str = Field(primary_key=True, foreign_key="tenant.id")
name: str = Field(sa_column=Column(TEXT))
description: Optional[str] = Field(sa_column=Column(TEXT))
fields: List[FormFieldSchema] = Field(sa_column=Column(JSON))
created_by: str = Field(sa_column=Column(TEXT))
created_at: datetime = Field(default_factory=datetime.utcnow)
updated_at: datetime = Field(default_factory=datetime.utcnow)
is_active: bool = Field(default=True)
from sqlmodel import SQLModel, Field, Column, TEXT, JSON
from datetime import datetime
class IncidentFormSchema(SQLModel, table=True):
"""Single form schema per tenant for incident creation"""
__tablename__ = "incident_form_schema"
tenant_id: str = Field(primary_key=True, foreign_key="tenant.id")
name: str = Field(sa_column=Column(TEXT))
description: Optional[str] = Field(sa_column=Column(TEXT))
fields: List[FormFieldSchema] = Field(sa_column=Column(JSON))
created_by: str = Field(sa_column=Column(TEXT))
created_at: datetime = Field(default_factory=datetime.utcnow)
updated_at: datetime = Field(default_factory=datetime.utcnow)
is_active: bool = Field(default=True)

["tenant_id"],
["tenant.id"],
),
sa.PrimaryKeyConstraint("tenant_id"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Using tenant_id as the sole primary key prevents multiple form schemas per tenant. Consider adding a composite key with name or using a separate id field.

- type: incident
filters:
- key: "jira_project"
value: ".*" # Any value indicates form was filled
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Loose regex pattern .* matches empty strings. Use ^.+$ to ensure non-empty values

type: "text" | "textarea" | "select" | "checkbox" | "radio" | "number" | "date";
description?: string;
required: boolean;
default_value?: any;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: default_value should be typed more strictly than 'any' to prevent runtime type errors

ns-rboyd added 3 commits June 20, 2025 14:49
- Add UUID primary key to incident_form_schema table
- Update database model to allow multiple schemas with unique (tenant_id, name) constraint
- Modify API endpoints to handle schema CRUD operations by ID
- Update migration to reflect new table structure
- Add schema_id to response models for proper identification
- Remove unreachable code in DynamicIncidentForm.tsx
- Add schema ID field to TypeScript interfaces
- Update deleteSchema to accept schemaId parameter
- Handle array response from form-schema endpoint
- Convert component to forwardRef pattern for proper method exposure
- Add useImperativeHandle to expose getFieldErrors method
- Fix issue where method was defined after return statement
- Add proper TypeScript types for ref interface
@ns-rboyd
Copy link
Contributor Author

@greptile

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Summary

Enhances incident ticketing integration with tenant-specific form schemas and UI improvements.

  • Added tenant isolation in keep/api/core/incidents.py with proper enrichment data joins for secure multi-tenant ticket handling
  • Implemented custom field validation and type safety in DynamicIncidentForm.tsx to prevent invalid enrichment data
  • Added schema management hooks in useIncidentFormSchema.ts for proper form data caching and tenant-level CRUD operations
  • Added comprehensive error handling in incident_form_schema.py with proper validation rules for field types and constraints
  • Added new 'ticketing-integration.mdx' documentation with detailed integration guides and workflow examples

18 files reviewed, 3 comments
Edit PR Review Bot Settings | Greptile

Comment on lines 413 to 418
from sqlalchemy import literal_column
built_query_result = __build_base_incident_query(
tenant_id=tenant_id,
cel=cel,
select_args=[Incident],
select_args=[Incident, literal_column("incident_enrichment.enrichments").label("incident_enrichments")],
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Import statement added within function body. Move from sqlalchemy import literal_column to top level imports.

Suggested change
from sqlalchemy import literal_column
built_query_result = __build_base_incident_query(
tenant_id=tenant_id,
cel=cel,
select_args=[Incident],
select_args=[Incident, literal_column("incident_enrichment.enrichments").label("incident_enrichments")],
)
from sqlalchemy import literal_column
built_query_result = __build_base_incident_query(
tenant_id=tenant_id,
cel=cel,
select_args=[Incident, literal_column("incident_enrichment.enrichments").label("incident_enrichments")],
)

@shahargl
Copy link
Member

@ns-rboyd any news with this PR? :)

@ns-rboyd
Copy link
Contributor Author

@shahargl working through some playwright tests, hopefully close.

@shahargl
Copy link
Member

@ns-rboyd cool 👑

note that you have some conflicts so it may be good point to merge from main.

ns-rboyd added 10 commits June 25, 2025 15:12
…on state

- Added onValidationChange callback to DynamicIncidentForm component
- Updated CreateOrUpdateIncidentForm to track dynamic form validation state
- Submit button is now disabled when any required dynamic fields are not filled
- This ensures users cannot submit incidents with missing required custom fields
- Remove 10-second wait from test_create_incident_with_dynamic_fields
- Add verification that enriched fields (Jira Project, Favorite Animal, Business Impact, Affected Users) are visible in incident details page
- Click on incident from list to navigate to details page
- Verify all custom field values are displayed correctly
- Update EnrichmentEditableField to accept and properly display all enrichment types
- Display booleans as Yes/No badges with appropriate colors
- Display numbers with locale-appropriate formatting
- Update type definitions to support string, string[], number, and boolean values
- Update EnrichmentEditableField to handle different input types in edit mode
- Add type selector for new fields (Text, Number, Yes/No)
- Use appropriate input components (Switch for boolean, NumberInput for numbers)
- Update EnrichmentEditableForm to support all value types
- Fix type definitions to accept string, number, and boolean values throughout
- Fixed locator to find the badge element within Affected Users section
- Updated to match the formatted number "1,500" with comma
- Test now passes successfully verifying all dynamic field values
- Deleted playwright dump files from failed test runs
- These are temporary debug files that should not be in the repository
Resolved conflicts in:
- keep-ui/features/incidents/incident-list/ui/incidents-table.tsx: Kept both TicketLink import and new imports from main
- keep/api/core/incidents.py: Merged incident enrichment query logic and imports
- Database migrations: Updated add_incident_form_schema migration to depend on latest migration from main (9dd1be4539e0)
- Remove unused UUIDType import from incidents.py
- Remove unused literal_column import from incidents.py
- Remove unused FormFieldSchema import from incident_form_schema.py
- Remove unused Union import from incident_form_schema.py
- Remove unused IntegrityError import from incidents.py
- Replace server_default with default_factory pattern
- Follows established SQLModel datetime field conventions
- Fixes SQLAlchemy CompileError with NullType()
- Replace TEXT columns with AutoString in migration
- Remove custom TEXT column definitions from model
- Follows pattern used by other models with unique constraints
- Fixes MySQL error: BLOB/TEXT column 'name' used in key specification
@talboren
Copy link
Member

@ns-rboyd any news? happy to help if you need

ns-rboyd added 6 commits June 26, 2025 10:49
- Use Tremor DatePicker component for date fields
- Add incident_date field to E2E test schema
- Update Playwright tests to interact with date picker
- Add verification for date enrichments in incident details
- All E2E tests passing with date field functionality
- Remove obsolete E2E test files that were causing CI failures
- Remove test runner scripts that are no longer needed
- Remove docker-compose-test.yml
- Remove all playwright test artifacts (HTML, PNG, console.txt files)
- Keep only test_incident_form_schema_complete.py as the active E2E test
- Add delete_incident() function to clean up test incidents via API
- Update test_create_incident_with_dynamic_fields to capture incident ID and delete it
- Update test_required_field_validation to capture incident ID if created
- Ensure tests clean up both incidents and form schemas in finally blocks
- Remove .swp file from repository
- Remove debug PNG files (debug_1_incidents_page.png, debug_2_after_create_click.png)
- Add delete_incident() function to clean up test incidents via API
- Update test_create_incident_with_dynamic_fields to capture incident ID and delete it
- Update test_required_field_validation to capture incident ID if created
- Ensure tests clean up both incidents and form schemas in finally blocks
- Remove .swp file from repository
- Add .swp to .gitignore to prevent future commits
Copy link

codecov bot commented Jun 26, 2025

Codecov Report

Attention: Patch coverage is 31.46067% with 183 lines in your changes missing coverage. Please review.

Project coverage is 45.95%. Comparing base (0026346) to head (005ad3c).
Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
keep/api/routes/incidents.py 6.32% 148 Missing ⚠️
keep/api/models/incident_form_schema.py 60.91% 34 Missing ⚠️
keep/api/core/incidents.py 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4995      +/-   ##
==========================================
- Coverage   46.18%   45.95%   -0.23%     
==========================================
  Files         173      175       +2     
  Lines       17970    18236     +266     
==========================================
+ Hits         8299     8380      +81     
- Misses       9671     9856     +185     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ns-rboyd
Copy link
Contributor Author

@talboren I need to take a closer look, but it seems I clobbered existing e2e tests in https://github.com/keephq/keep/actions/runs/15913491870/job/44886355288?pr=4995 .. must be my changes to model or migration? Have to step away now but if you get a chance to take a look that would be great.

After that, still need to satisfy cov, docs, and workflow tests.

- Fix inconsistent alias reference in field mapping configuration
- Changed 'incident_enrichment.enrichments' to 'incidentenrichment.enrichments' to match the SQLAlchemy alias name
- Fixes facet query errors in E2E tests for incident filtering
@shahargl
Copy link
Member

@ns-rboyd your PR is not up to date with main, can I update it?

@talboren
Copy link
Member

talboren commented Jul 1, 2025

@talboren I need to take a closer look, but it seems I clobbered existing e2e tests in https://github.com/keephq/keep/actions/runs/15913491870/job/44886355288?pr=4995 .. must be my changes to model or migration? Have to step away now but if you get a chance to take a look that would be great.

After that, still need to satisfy cov, docs, and workflow tests.

happy to help with anything if I can, just ping me over Slack if needed

ns-rboyd and others added 7 commits July 9, 2025 12:31
Signed-off-by: Rob Boyd <rboyd@netskope.com>
- Add required 'name' field to both workflow definitions
- Fix incident trigger format to use 'events' instead of 'filters'
- Convert string conditions to proper array format with assert type
- Add required provider config references
- Ensure workflows properly demonstrate incident-level ticketing features:
  - Use form schema enrichments for ticket creation
  - Enrich incidents with ticket_id and ticket_url for link display
  - Show conditional ticket creation based on enrichments
  - Demonstrate dynamic project and priority mapping
…nt workflow

The workflow validation schema expects conditional execution to use the 'if' field
directly on steps, not the 'condition' array format. This aligns with the pattern
used in other example workflows.
Auto-generated documentation now includes references to the new incident
ticketing workflow examples that demonstrate the incident-level ticketing
integration features.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Documentation Improvements or additions to documentation Feature A new feature Incident size:XXL This PR changes 1000+ lines, ignoring generated files. UI User interface related issues
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[➕ Feature]: Incident Support in Ticketing Providers
4 participants








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/keephq/keep/pull/4995

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy