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

RoundingWell / care-ops-frontend / 7a9e0dfe-a1cb-47f6-baca-e6adf9c664aa

06 Aug 2025 08:26PM UTC coverage: 89.726% (-10.3%) from 100.0%
7a9e0dfe-a1cb-47f6-baca-e6adf9c664aa

push

circleci

web-flow
Merge pull request #1485 from RoundingWell/pt-search-updates

Implement `match` object in patient search api response data

1589 of 1839 branches covered (86.41%)

Branch coverage included in aggregate %.

5616 of 6191 relevant lines covered (90.71%)

202.72 hits per line

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

98.39
/src/js/views/programs/program/flow/flow_views.js
1
import Radio from 'backbone.radio';
2
import hbs from 'handlebars-inline-precompile';
3
import { View, CollectionView } from 'marionette';
4

5
import PreloadRegion from 'js/regions/preload_region';
6

7
import { OwnerComponent as FlowOwnerComponent, FlowBehaviorComponent } from 'js/views/programs/shared/flows_views';
8
import { DueDayComponent, OwnerComponent, BehaviorComponent } from 'js/views/programs/shared/actions_views';
9
import SortableList from 'js/behaviors/sortable-list';
10

11
import ActionItemTemplate from './action-item.hbs';
12
import HeaderTemplate from './header.hbs';
13

14
import './program-flow.scss';
15

16
const ContextTrailView = View.extend({
134✔
17
  modelEvents: {
18
    'change:name': 'render',
19
  },
20
  initialize({ program }) {
21
    this.program = program;
11✔
22

23
    this.listenTo(this.program, 'change:name', this.render);
11✔
24
  },
25
  className: 'program-flow__context-trail',
26
  template: hbs`
27
    {{#if hasLatestList}}
28
      <a class="js-back program-flow__context-link">
29
        {{fas "chevron-left"}}{{ @intl.programs.program.flow.flowViews.contextBackBtn }}
30
      </a>
31
      {{fas "chevron-right"}}
32
    {{/if}}
33
    <a class="js-program program-flow__context-link">{{ programName }}</a>{{fas "chevron-right"}}{{ name }}
34
  `,
35
  triggers: {
36
    'click .js-back': 'click:back',
37
    'click .js-program': 'click:program',
38
  },
39
  onClickBack() {
40
    Radio.request('history', 'go:latestList');
1✔
41
  },
42
  onClickProgram() {
43
    Radio.trigger('event-router', 'program:details', this.program.id);
1✔
44
  },
45
  templateContext() {
46
    return {
12✔
47
      hasLatestList: Radio.request('history', 'has:latestList'),
48
      programName: this.program.get('name'),
49
    };
50
  },
51
});
52

53
const HeaderView = View.extend({
134✔
54
  className: 'program-flow__header',
55
  modelEvents: {
56
    'editing': 'onEditing',
57
    'change': 'render',
58
  },
59
  onEditing(isEditing) {
60
    this.$el.toggleClass('is-selected', isEditing);
×
61
  },
62
  template: HeaderTemplate,
63
  regions: {
64
    behavior: '[data-behavior-region]',
65
    owner: '[data-owner-region]',
66
  },
67
  triggers: {
68
    'click': 'edit',
69
  },
70
  onRender() {
71
    this.showBehavior();
17✔
72
    this.showOwner();
17✔
73
  },
74
  showBehavior() {
75
    const behaviorComponent = new FlowBehaviorComponent({
17✔
76
      behavior: this.model.get('behavior'),
77
      isCompact: true,
78
    });
79

80
    this.listenTo(behaviorComponent, 'change:status', ({ behavior }) => {
17✔
81
      this.model.save({ behavior });
2✔
82
    });
83

84
    this.showChildView('behavior', behaviorComponent);
17✔
85
  },
86
  showOwner() {
87
    const ownerComponent = new FlowOwnerComponent({ owner: this.model.getOwner(), isCompact: true });
17✔
88

89
    this.listenTo(ownerComponent, 'change:owner', owner => {
17✔
90
      this.model.saveOwner(owner);
1✔
91
    });
92

93
    this.showChildView('owner', ownerComponent);
17✔
94
  },
95
});
96

97
const AddActionView = View.extend({
134✔
98
  className: 'program-flow__actions',
99
  template: hbs`
100
    <button class="button-primary js-add-action">
101
      {{far "circle-plus"}}<span>{{ @intl.programs.program.flow.flowViews.addActionBtn }}</span>
102
    </button>
103
  `,
104
  triggers: {
105
    'click .js-add-action': 'click:addAction',
106
  },
107
});
108

109
const EmptyView = View.extend({
134✔
110
  tagName: 'tr',
111
  template: hbs`
112
    <td class="program-flow__empty-list">
113
      <h2>{{ @intl.programs.program.flow.flowViews.emptyView }}</h2>
114
    </td>
115
  `,
116
});
117

118
const ActionItemView = View.extend({
134✔
119
  modelEvents: {
120
    'change': 'render',
121
    'editing': 'onEditing',
122
  },
123
  className() {
124
    const className = 'table-list__item program-flow__action-item js-draggable';
33✔
125
    if (this.model.isNew()) return `${ className } is-selected`;
33✔
126

127
    return className;
31✔
128
  },
129
  template: ActionItemTemplate,
130
  templateContext() {
131
    return {
61✔
132
      hasForm: this.model.getForm(),
133
      icon: this.model.hasOutreach() ? 'share-from-square' : 'file-lines',
61✔
134
    };
135
  },
136
  tagName: 'tr',
137
  regions: {
138
    behavior: '[data-behavior-region]',
139
    owner: '[data-owner-region]',
140
    due: '[data-due-region]',
141
  },
142
  triggers: {
143
    'click': 'click',
144
  },
145
  onClick() {
146
    if (this.model.isNew()) {
6✔
147
      Radio.trigger('event-router', 'programFlow:action:new', this.model.getProgramFlow().id);
1✔
148
      return;
1✔
149
    }
150
    Radio.trigger('event-router', 'programFlow:action', this.model.getProgramFlow().id, this.model.id);
5✔
151
  },
152
  onEditing(isEditing) {
153
    this.$el.toggleClass('is-selected', isEditing);
19✔
154
  },
155
  onRender() {
156
    this.showBehavior();
61✔
157
    this.showOwner();
61✔
158
    this.showDue();
61✔
159
  },
160
  showDue() {
161
    const isDisabled = this.model.isNew();
61✔
162
    const dueDayComponent = new DueDayComponent({ day: this.model.get('days_until_due'), isCompact: true, state: { isDisabled } });
61✔
163

164
    this.listenTo(dueDayComponent, 'change:day', day => {
61✔
165
      this.model.save({ days_until_due: day });
2✔
166
    });
167

168
    this.showChildView('due', dueDayComponent);
61✔
169
  },
170
  showBehavior() {
171
    const isDisabled = this.model.isNew();
61✔
172
    const behaviorComponent = new BehaviorComponent({
61✔
173
      behavior: this.model.get('behavior'),
174
      isCompact: true,
175
      state: { isDisabled },
176
    });
177

178
    this.listenTo(behaviorComponent, 'change:status', ({ behavior }) => {
61✔
179
      this.model.save({ behavior });
1✔
180
    });
181

182
    this.showChildView('behavior', behaviorComponent);
61✔
183
  },
184
  showOwner() {
185
    const isDisabled = this.model.isNew();
61✔
186
    const isFromFlow = !!this.model.getProgramFlow();
61✔
187
    const ownerComponent = new OwnerComponent({ owner: this.model.getOwner(), isFromFlow, isCompact: true, state: { isDisabled } });
61✔
188

189
    this.listenTo(ownerComponent, 'change:owner', owner => {
61✔
190
      this.model.saveOwner(owner);
1✔
191
    });
192

193
    this.showChildView('owner', ownerComponent);
61✔
194
  },
195
});
196

197
const ListView = CollectionView.extend({
134✔
198
  behaviors: [
199
    {
200
      behaviorClass: SortableList,
201
      shouldDisable() {
202
        return this.view.collection.length < 2 || this.view.collection.last().isNew();
16✔
203
      },
204
    },
205
  ],
206
  collectionEvents: {
207
    'change:id': 'onChangeId',
208
  },
209
  className: 'table-list program-flow__list',
210
  tagName: 'table',
211
  childView: ActionItemView,
212
  emptyView: EmptyView,
213
  onDragEnd() {
214
    this.collection.updateSequences();
1✔
215
  },
216
  onChangeId() {
217
    this.collection.updateSequences();
1✔
218
  },
219
});
220

221
const LayoutView = View.extend({
134✔
222
  className: 'program-flow__frame',
223
  template: hbs`
224
    <div class="program-flow__layout">
225
      <div data-context-trail-region></div>
226
      <div data-header-region></div>
227
      <div data-add-action-region></div>
228
      <div data-action-list-region></div>
229
    </div>
230
    <div class="program-flow__sidebar" data-sidebar-region></div>
231
  `,
232
  regions: {
233
    contextTrail: {
234
      el: '[data-context-trail-region]',
235
      replaceElement: true,
236
    },
237
    header: '[data-header-region]',
238
    addAction: '[data-add-action-region]',
239
    sidebar: '[data-sidebar-region]',
240
    actionList: {
241
      el: '[data-action-list-region]',
242
      regionClass: PreloadRegion,
243
      replaceElement: true,
244
    },
245
  },
246
});
247

248
export {
249
  LayoutView,
250
  ContextTrailView,
251
  HeaderView,
252
  AddActionView,
253
  ListView,
254
};
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