flutter_jira_issue_collector 0.2.0 copy "flutter_jira_issue_collector: ^0.2.0" to clipboard
flutter_jira_issue_collector: ^0.2.0 copied to clipboard

Jira Issue Collector for Flutter. Fetch collector fields dynamically, show customizable forms, or submit issues programmatically in the background.

flutter_jira_issue_collector #

License: MIT Flutter pub.dev

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

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 #

  1. In Jira, go to Administration > Issue Collectors
  2. Create or edit a collector
  3. Copy the collector ID from the embed script URL:
    .../issueCollectorBootstrap.js?collectorId=3e3ffaf3
    
  4. Use your Jira base URL and collector ID with the code generator or JiraCollectorConfig

Cleanup #

collector.dispose();

License #

MIT

1
likes
160
points
27
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Jira Issue Collector for Flutter. Fetch collector fields dynamically, show customizable forms, or submit issues programmatically in the background.

Homepage
Repository (GitHub)
View/report issues

Topics

#jira #issue-collector #issue-tracking #feedback

License

MIT (license)

Dependencies

dio, flutter, html

More

Packages that depend on flutter_jira_issue_collector