flutter_jira_issue_collector
Jira Issue Collector for Flutter -- fetch collector fields dynamically, show customizable forms, or submit issues programmatically in the background. Includes a code generator that produces type-safe Dart helpers from your collector's live fields.
Features
- Code generator -- fetches your collector's fields and generates a typed Dart class (no guessing field IDs)
- Fetches issue collector form fields dynamically from Jira (Data Center / Server)
- Shows a customizable form UI using builder pattern (bring your own widgets)
- Submits issues programmatically in the background without any UI
- Prefill and hide specific fields (e.g. email, reporter name)
- Includes default Material field renderers as opt-in fallback
- Full-screen dialog and bottom sheet presentation modes
Getting Started
Add the package to your pubspec.yaml:
dependencies:
flutter_jira_issue_collector: ^0.1.0
Quick Start (recommended)
Every Jira collector has different fields. The code generator fetches yours and produces a type-safe Dart class so you never have to guess field IDs.
1. Generate your collector helper
dart run flutter_jira_issue_collector:generate_collector \
--base-url https://jira.example.com \
--collector-id 3e3ffaf3 \
--output lib/generated/my_collector.dart \
--class-name MyCollector
This connects to Jira, discovers the form fields, and generates:
// GENERATED FILE — DO NOT EDIT BY HAND
import 'package:flutter_jira_issue_collector/flutter_jira_issue_collector.dart';
abstract final class MyCollector {
// Variable names come from field labels, values are runtime IDs.
/// What went wrong? — textarea
static const whatWentWrong = 'description';
/// Name — text
static const name = 'fullname';
/// Email — text
static const email = 'email';
static const baseUrl = 'https://jira.example.com';
static const collectorId = '3e3ffaf3';
/// Creates a pre-configured [JiraIssueCollector] instance.
static JiraIssueCollector createCollector() { /* ... */ }
/// Builds a field-value map. Only fields that exist in the
/// collector are accepted — the compiler catches the rest.
static Map<String, dynamic> build({
String? whatWentWrong,
String? name,
String? email,
}) {
return {
if (whatWentWrong != null) 'description': whatWentWrong,
if (name != null) 'fullname': name,
if (email != null) 'email': email,
};
}
}
2. Use it in your app
import 'generated/my_collector.dart';
final collector = MyCollector.createCollector();
// Background submission — type-safe, no magic strings.
final result = await collector.submitInBackground(
fieldValues: MyCollector.build(
whatWentWrong: 'Server 500 on login — POST /api/auth',
email: 'ops@example.com',
),
);
// Prefilled UI — use constants for field IDs.
await collector.showCollector(
context,
prefillValues: {
MyCollector.name: 'John Doe',
MyCollector.email: 'user@example.com',
},
hiddenFieldIds: {MyCollector.name, MyCollector.email},
);
If the collector's fields change in Jira, re-run the generator — your code won't compile until you update the call sites.
Generator options
| Flag | Required | Default | Description |
|---|---|---|---|
--base-url |
Yes | -- | Jira Server / Data Center URL |
--collector-id |
Yes | -- | Collector ID from embed script |
--output |
No | lib/generated/jira_collector_fields.dart |
Output file |
--class-name |
No | Derived from ID | Generated class name |
Manual Setup (without code generator)
If you prefer to configure manually:
import 'package:flutter_jira_issue_collector/flutter_jira_issue_collector.dart';
final collector = JiraIssueCollector(
config: JiraCollectorConfig(
baseUrl: 'https://jira.example.com',
collectorId: '3e3ffaf3',
),
);
Discover fields at runtime
final fields = await collector.fetchFields();
for (final field in fields) {
print('${field.id}: ${field.label} (${field.type}, required: ${field.required})');
}
Background submission
final result = await collector.submitInBackground(
fieldValues: {'description': 'Something went wrong.'},
);
if (result.success) {
print('Issue created: ${result.issueKey}');
}
UI Mode -- dialog
final result = await collector.showCollector(context);
UI Mode -- bottom sheet
final result = await collector.showCollectorBottomSheet(context);
Custom field rendering
final result = await collector.showCollector(
context,
fieldBuilder: (context, field, controller, onChanged, defaultWidget) {
if (field.id == 'description') {
return MyCustomDescriptionField(controller: controller);
}
return defaultWidget;
},
layoutBuilder: (context, fieldWidgets, onSubmit, isSubmitting) {
return MyCustomFormLayout(
fields: fieldWidgets,
onSubmit: onSubmit,
isSubmitting: isSubmitting,
);
},
);
Real-world: Automated Error Reporting
A common pattern is reporting server errors to Jira automatically from a Dio interceptor. Using the generated helper:
import 'generated/my_collector.dart';
class JiraErrorReporter {
JiraErrorReporter() : _collector = MyCollector.createCollector();
final JiraIssueCollector _collector;
Future<void> report({
required String method,
required String path,
required int statusCode,
String? requestBody,
String? responseBody,
String? userName,
String? userEmail,
}) async {
try {
final description = StringBuffer()
..writeln('[Mobile] Server $statusCode -- $method $path')
..writeln()
..writeln('Method: $method')
..writeln('Path: $path')
..writeln('Status: $statusCode')
..writeln('Timestamp: ${DateTime.now().toUtc().toIso8601String()}');
if (requestBody != null) {
description
..writeln()
..writeln('--- Request Body ---')
..writeln(requestBody);
}
if (responseBody != null) {
description
..writeln()
..writeln('--- Response Body ---')
..writeln(responseBody);
}
await _collector.submitInBackground(
fieldValues: MyCollector.build(
whatWentWrong: description.toString(),
name: userName,
email: userEmail,
),
);
} catch (_) {
// Never crash the app over a failed Jira report.
}
}
void dispose() => _collector.dispose();
}
Jira Setup
- In Jira, go to Administration > Issue Collectors
- Create or edit a collector
- Copy the collector ID from the embed script URL:
.../issueCollectorBootstrap.js?collectorId=3e3ffaf3 - Use your Jira base URL and collector ID with the code generator or
JiraCollectorConfig
Cleanup
collector.dispose();
License
MIT
Libraries
- flutter_jira_issue_collector
- A Flutter package to connect to Jira Issue Collector — fetch fields dynamically, show customizable forms, or submit issues programmatically in the background.