• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

RoundingWell / care-ops-frontend / 8b61514d-90b5-45fb-b81d-e60b440f5d22

09 Apr 2026 07:39PM UTC coverage: 92.417% (-7.6%) from 99.976%
8b61514d-90b5-45fb-b81d-e60b440f5d22

push

circleci

nmajor25
On incoming call ringing, show 'Incoming Call' in UI panel header

1735 of 1923 branches covered (90.22%)

Branch coverage included in aggregate %.

5919 of 6359 relevant lines covered (93.08%)

195.4 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

72.58
/src/js/views/programs/program/workflows/workflows_views.js
1
import Radio from 'backbone.radio';
2

3
import hbs from 'handlebars-inline-precompile';
4
import { View, CollectionView, Behavior } from 'marionette';
5

6
import { alphaSort } from 'js/utils/sorting';
7

8
import 'scss/modules/buttons.scss';
9
import 'scss/modules/table-list.scss';
10

11
import { PROGRAM_BEHAVIORS } from 'js/static';
12
import intl from 'js/i18n';
13

14
import Droplist from 'js/components/droplist';
15

16
import PreloadRegion from 'js/regions/preload_region';
17

18
import { OwnerComponent as FlowOwnerComponent } from 'js/views/programs/shared/flows_views';
19
import { DueDayComponent, OwnerComponent, BehaviorComponent } from 'js/views/programs/shared/actions_views';
20

21
import ActionItemTemplate from './action-item.hbs';
22
import FlowItemTemplate from './flow-item.hbs';
23
import LayoutTemplate from './layout.hbs';
24

25
import 'scss/domain/program-action-state.scss';
26
import 'scss/domain/action-icons.scss';
27
import './workflows.scss';
28

29
const EmptyView = View.extend({
151✔
30
  className: 'table-list__empty-list',
31
  template: hbs`<h2>{{ @intl.programs.program.workflows.workflowsViews.emptyView }}</h2>`,
32
});
33

34
const RowBehavior = Behavior.extend({
151✔
35
  modelEvents: {
36
    'editing': 'onEditing',
37
    'change': 'onChange',
38
  },
39
  onChange() {
40
    this.view.render();
2✔
41
  },
42
  onEditing(isEditing) {
43
    this.$el.toggleClass('is-selected', isEditing);
5✔
44
  },
45
  onInitialize() {
46
    if (this.view.model.isNew()) this.$el.addClass('is-selected');
52✔
47
  },
48
});
49

50
const ActionItemView = View.extend({
151✔
51
  className: 'table-list__item',
52
  behaviors: [RowBehavior],
53
  regions: {
54
    behavior: '[data-behavior-region]',
55
    owner: '[data-owner-region]',
56
    due: '[data-due-region]',
57
  },
58
  template: ActionItemTemplate,
59
  templateContext() {
60
    return {
33✔
61
      hasForm: this.model.getForm(),
62
      icon: this.model.hasOutreach() ? 'share-from-square' : 'file-lines',
33!
63
    };
64
  },
65
  triggers: {
66
    'click': 'click',
67
  },
68
  onClick() {
69
    if (this.model.isNew()) {
×
70
      Radio.trigger('event-router', 'program:action:new', this.model.getProgram().id);
×
71
      return;
×
72
    }
73

74
    Radio.trigger('event-router', 'program:action', this.model.getProgram().id, this.model.id);
×
75
  },
76
  onRender() {
77
    this.showBehavior();
33✔
78
    this.showOwner();
33✔
79
    this.showDue();
33✔
80
  },
81
  showBehavior() {
82
    const isDisabled = this.model.isNew();
33✔
83
    const isFromFlow = !!this.model.getProgramFlow();
33✔
84
    const behaviorComponent = new BehaviorComponent({
33✔
85
      isConditionalAvailable: isFromFlow,
86
      behavior: this.model.get('behavior'),
87
      isCompact: true,
88
      state: { isDisabled },
89
    });
90

91
    this.listenTo(behaviorComponent, 'change:status', ({ behavior }) => {
33✔
92
      this.model.save({ behavior });
×
93
    });
94

95
    this.showChildView('behavior', behaviorComponent);
33✔
96
  },
97
  showOwner() {
98
    const isDisabled = this.model.isNew();
33✔
99
    const isFromFlow = !!this.model.getProgramFlow();
33✔
100
    const ownerComponent = new OwnerComponent({ owner: this.model.getOwner(), isFromFlow, isCompact: true, state: { isDisabled } });
33✔
101

102
    this.listenTo(ownerComponent, 'change:owner', owner => {
33✔
103
      this.model.saveOwner(owner);
×
104
    });
105

106
    this.showChildView('owner', ownerComponent);
33✔
107
  },
108
  showDue() {
109
    const isDisabled = this.model.isNew();
33✔
110
    const dueDayComponent = new DueDayComponent({ day: this.model.get('days_until_due'), isCompact: true, state: { isDisabled } });
33✔
111

112
    this.listenTo(dueDayComponent, 'change:day', day => {
33✔
113
      this.model.save({ days_until_due: day });
×
114
    });
115

116
    this.showChildView('due', dueDayComponent);
33✔
117
  },
118
});
119

120
const FlowItemView = View.extend({
151✔
121
  className: 'table-list__item',
122
  behaviors: [RowBehavior],
123
  regions: {
124
    owner: '[data-owner-region]',
125
  },
126
  template: FlowItemTemplate,
127
  templateContext() {
128
    return {
21✔
129
      published: !!this.model.get('published_at'),
130
      isAutomated: this.model.get('behavior') === PROGRAM_BEHAVIORS.AUTOMATED,
131
    };
132
  },
133
  triggers: {
134
    'click': 'click',
135
  },
136
  onClick() {
137
    if (this.model.isNew()) {
×
138
      Radio.trigger('event-router', 'programFlow:new', this.model.getProgram().id);
×
139
      return;
×
140
    }
141

142
    Radio.trigger('event-router', 'programFlow', this.model.id);
×
143
  },
144
  onRender() {
145
    this.showOwner();
21✔
146
  },
147
  showOwner() {
148
    const isDisabled = this.model.isNew();
21✔
149
    const ownerComponent = new FlowOwnerComponent({ owner: this.model.getOwner(), isCompact: true, state: { isDisabled } });
21✔
150

151
    this.listenTo(ownerComponent, 'change:owner', owner => {
21✔
152
      this.model.saveOwner(owner);
×
153
    });
154

155
    this.showChildView('owner', ownerComponent);
21✔
156
  },
157
});
158

159
const ListView = CollectionView.extend({
151✔
160
  className: 'table-list__list list-page__list',
161
  childView(item) {
162
    if (item.type === 'program-flows') {
52✔
163
      return FlowItemView;
20✔
164
    }
165

166
    return ActionItemView;
32✔
167
  },
168
  emptyView: EmptyView,
169
  viewComparator(viewA, viewB) {
170
    return alphaSort('desc', viewA.model.get('updated_at'), viewB.model.get('updated_at'));
93✔
171
  },
172
});
173

174
const LayoutView = View.extend({
151✔
175
  className: 'flex-region workflows__content',
176
  regions: {
177
    content: {
178
      el: '[data-content-region]',
179
      regionClass: PreloadRegion,
180
      replaceElement: true,
181
    },
182
    add: '[data-add-region]',
183
  },
184
  template: LayoutTemplate,
185
});
186

187
const AddActionDroplist = Droplist.extend({
151✔
188
  popWidth: 248,
189
  picklistOptions() {
190
    return {
2✔
191
      headingText: intl.programs.program.workflows.workflowsViews.addActionHeading,
192
      itemClassName: 'u-text--italic',
193
    };
194
  },
195
  viewOptions: {
196
    className: 'button-primary',
197
    template: hbs`{{far "circle-plus"}}<span>{{ @intl.programs.program.workflows.workflowsViews.addAction }}</span>{{far "angle-down" classes="workflows__arrow"}}`,
198
  },
199
  picklistEvents: {
200
    'picklist:item:select': 'onSelect',
201
  },
202
  onSelect({ model }) {
203
    model.get('onSelect')();
2✔
204
  },
205
});
206

207
export {
208
  ListView,
209
  LayoutView,
210
  AddActionDroplist,
211
};
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc