renderSeedRuns function

String? renderSeedRuns(
  1. LiveBlock block,
  2. Object? payload, {
  3. String rollback = 'seed:rollback',
  4. ({String done, String running}) verbs = (running: 'Seeding', done: 'Seeded'),
})

Adds each run in a seeders.run payload to block: its changes, its messages and how it ended. After seeding, it ends with how to undo it with rollback.

verbs name what an up run did: Seeding and Seeded for seeders, Importing and Imported for snapshots.

Returns why a run failed, or null when every run succeeded.

Implementation

String? renderSeedRuns(
  LiveBlock block,
  Object? payload, {
  String rollback = 'seed:rollback',
  ({String running, String done}) verbs = (running: 'Seeding', done: 'Seeded'),
}) {
  final Object? runs = payload is Map ? payload['runs'] : null;
  if (runs is! List || runs.isEmpty) {
    block.note('Nothing ran');
    return null;
  }

  String? failure;
  final List<String> seeded = [];
  for (final Object? run in runs) {
    if (run is! Map) continue;
    final String name = '${run['name']}';
    final bool down = run['direction'] == 'down';
    final List<Map<Object?, Object?>> log = [
      if (run['log'] case final List entries)
        for (final Object? entry in entries)
          if (entry is Map) entry,
    ];
    final Iterable<Map<Object?, Object?>> changes = log.where(
      (entry) => entry['level'] == 'change',
    );
    final int storeWidth = changes.fold(
      0,
      (width, entry) => max(width, '${entry['store']}'.length),
    );
    final int keyWidth = changes.fold(
      0,
      (width, entry) => max(width, '${entry['key']}'.length),
    );

    block.plain(down ? 'Rolling back $name' : '${verbs.running} $name');
    for (final Map<Object?, Object?> entry in log) {
      final String message = '${entry['message'] ?? ''}';
      switch (entry['level']) {
        case 'change':
          final String change = '${entry['change']}';
          final (String symbol, LiveTone tone) = switch (change) {
            'added' => ('+', LiveTone.success),
            'removed' => ('-', LiveTone.failure),
            _ => ('~', LiveTone.warning),
          };
          block.add(
            '  $symbol ${'${entry['store']}'.padRight(storeWidth + 2)}'
            '${'${entry['key']}'.padRight(keyWidth + 2)}'
            '${change == 'restored' ? 'put back' : change}',
            tone,
          );
        case 'success':
          block.add('  ✓ $message', LiveTone.success);
        case 'error':
          block.add('  ✗ $message', LiveTone.failure);
        case 'warning':
          block.add('  ! $message', LiveTone.warning);
        default:
          block.plain('  $message');
      }
    }

    if (run['failed'] == true) {
      failure = '$name failed: ${run['error'] ?? 'unknown error'}';
      block.failure('$name failed');
    } else {
      if (!down) seeded.add(name);
      block.success(
        '${down ? 'Rolled back' : verbs.done} $name in ${run['ms'] ?? 0}ms',
      );
    }
  }
  if (seeded.isNotEmpty && failure == null) {
    block.note('Undo with $rollback ${seeded.join(' ')}');
  }
  return failure;
}