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

vanvalenlab / deepcell-label / 5192775555

pending completion
5192775555

Pull #469

github

web-flow
Merge 47d83f6d6 into a468f41ad
Pull Request #469: Feature: drag celltype cards for reordering

465 of 1194 branches covered (38.94%)

Branch coverage included in aggregate %.

7 of 26 new or added lines in 5 files covered. (26.92%)

2 existing lines in 2 files now uncovered.

2533 of 4567 relevant lines covered (55.46%)

616.79 hits per line

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

58.06
/frontend/src/Project/service/raw/rawMachine.js
1
/** Manages the controls for the raw image, including
2
 * whether color is on and what channel to show in grayscale mode.
3
 *
4
 * Spawns layerMachines and channelMachines for controlling each channel in color and grayscale mode respectively.
5
 */
6

7
import { actions, assign, forwardTo, Machine, send, sendParent, spawn } from 'xstate';
8
import { fromEventBus } from '../eventBus';
9
import createChannelMachine from './channelMachine';
10
import createLayerMachine from './layerMachine';
11

12
const { pure, respond } = actions;
19✔
13

14
const createRawMachine = ({ projectId, eventBuses, undoRef }) =>
19✔
15
  Machine(
866✔
16
    {
17
      invoke: [
18
        { id: 'eventBus', src: fromEventBus('raw', () => eventBuses.raw) },
18✔
19
        { src: fromEventBus('raw', () => eventBuses.load, 'LOADED') },
18✔
20
        { src: fromEventBus('raw', () => eventBuses.load, 'DIMENSIONS') },
18✔
21
      ],
22
      context: {
23
        projectId,
24
        numChannels: 1,
25
        channel: 0,
26
        channels: [], // channel machines
27
        channelNames: ['channel 0'],
28
        layersOpen: [],
29
        layers: [],
30
        isGrayscale: true,
31
      },
32
      entry: [send('REGISTER_UI', { to: undoRef }), 'spawnLayers', 'spawnChannels'],
33
      initial: 'loading',
34
      states: {
35
        loading: {
36
          type: 'parallel',
37
          states: {
38
            getChannelNames: {
39
              initial: 'waiting',
40
              states: {
41
                waiting: {
42
                  on: {
43
                    LOADED: { actions: ['setChannelNames'], target: 'done' },
44
                  },
45
                },
46
                done: { type: 'final' },
47
              },
48
            },
49
            getDimensions: {
50
              initial: 'waiting',
51
              states: {
52
                waiting: {
53
                  on: {
54
                    DIMENSIONS: {
55
                      actions: ['setNumChannels', 'spawnLayers', 'spawnChannels'],
56
                      target: 'done',
57
                    },
58
                  },
59
                },
60
                done: { type: 'final' },
61
              },
62
            },
63
          },
64
          onDone: { actions: 'checkChannels', target: 'loaded' },
65
        },
66
        loaded: {
67
          initial: 'checkDisplay',
68
          states: {
69
            checkDisplay: {
70
              always: [{ cond: 'isGrayscale', target: 'grayscale' }, { target: 'color' }],
71
            },
72
            color: {
73
              entry: [send('COLOR', { to: 'eventBus' }), assign({ isGrayscale: false })],
74
              on: {
75
                TOGGLE_COLOR_MODE: 'grayscale',
76
                // Need propagate event to root actor to rerender canvas
77
                ADD_LAYER: {
78
                  actions: ['addLayer', sendParent((c, e) => e)],
×
79
                },
80
                FETCH_LAYERS: {
81
                  actions: ['fetchLayers', 'resetColors', 'setLayers', sendParent((c, e) => e)],
×
82
                },
83
                REMOVE_LAYER: {
84
                  actions: ['removeLayer', sendParent((c, e) => e), 'setLayers'],
1✔
85
                },
86
                EDIT_CHANNEL: {
87
                  actions: ['editLayer'],
88
                },
89
                EDIT_NAME: { actions: 'editChannelName' },
90
              },
91
            },
92
            grayscale: {
93
              entry: [send('GRAYSCALE', { to: 'eventBus' }), assign({ isGrayscale: true })],
94
              on: {
95
                TOGGLE_COLOR_MODE: 'color',
96
                RESET: { actions: 'forwardToChannel' },
97
                SET_CHANNEL: { actions: ['setChannel', 'sendToEventBus'] },
98
              },
99
            },
100
          },
101
          on: {
102
            GET_CHANNELS: { actions: 'sendChannels' },
103
            TOGGLE_INVERT: { actions: 'forwardToChannel' },
104
            SAVE: { actions: 'save' },
105
            RESTORE: { actions: ['restore', respond('RESTORED')] },
106
          },
107
        },
108
      },
109
    },
110
    {
111
      guards: {
112
        isGrayscale: ({ isGrayscale }) => isGrayscale,
13✔
113
      },
114
      actions: {
115
        setNumChannels: assign({
116
          numChannels: (context, event) => event.numChannels,
13✔
117
          isGrayscale: (context, event) => event.numChannels === 1,
13✔
118
        }),
119
        setChannelNames: assign({
120
          channelNames: (ctx, evt) => evt.channels,
13✔
121
        }),
122
        editChannelName: assign({
123
          channelNames: (ctx, evt) => {
124
            let channelNames = ctx.channelNames;
1✔
125
            channelNames[evt.channel] = evt.name;
1✔
126
            return channelNames;
1✔
127
          },
128
        }),
129
        editLayer: assign({
130
          layersOpen: ({ channelNames, layersOpen }, { channel, index }) => [
×
131
            ...layersOpen.map((c, i) => (i === index ? channelNames[channel] : c)),
×
132
          ],
133
        }),
134
        checkChannels: assign({
135
          channelNames: (ctx) => {
136
            let channelNames = ctx.channelNames;
13✔
137
            channelNames = channelNames.map((name, i) => (name ? name : `channel ${i}`));
34!
138
            return channelNames;
13✔
139
          },
140
          layersOpen: ({ numChannels, channelNames }) => {
141
            const layers = [];
13✔
142
            for (let i = 0; i < Math.min(6, numChannels); i++) {
13✔
143
              layers.push(channelNames[i]);
34✔
144
            }
145
            return layers;
13✔
146
          },
147
        }),
148
        sendToEventBus: send((c, e) => e, { to: 'eventBus' }),
×
149
        setChannel: assign({ channel: (_, { channel }) => channel }),
×
150
        /** Creates a channel machines and names */
151
        spawnChannels: assign({
152
          channels: ({ numChannels }, event) => {
153
            const channels = [];
879✔
154
            for (let i = 0; i < numChannels; i++) {
879✔
155
              const channel = spawn(createChannelMachine(i), `channel${i}`);
900✔
156
              channels.push(channel);
900✔
157
            }
158
            return channels;
879✔
159
          },
160
        }),
NEW
161
        sendChannels: respond((ctx) => ({
×
162
          type: 'CHANNELS',
163
          channels: ctx.channelNames, // Send the channel names list for export
164
        })),
UNCOV
165
        forwardToChannel: forwardTo((ctx) => `channel${ctx.channel}`),
×
166
        spawnLayers: assign({
167
          layers: ({ numChannels }) => {
168
            const layers = [];
879✔
169
            for (let i = 0; i < Math.min(6, numChannels); i++) {
879✔
170
              const layer = spawn(createLayerMachine(i, numChannels), `layer ${i}`);
900✔
171
              layers.push(layer);
900✔
172
            }
173
            return layers;
879✔
174
          },
175
        }),
176
        addLayer: assign({
177
          layers: ({ layers, numChannels }) => [
×
178
            ...layers,
179
            spawn(createLayerMachine(layers.length, numChannels), `layer ${layers.length}`),
180
          ],
181
          layersOpen: ({ layersOpen, channelNames }) => [
×
182
            ...layersOpen,
183
            channelNames[layersOpen.length],
184
          ],
185
        }),
186
        fetchLayers: assign({
187
          layers: ({ numChannels }, evt) => {
188
            const layers = [];
×
189
            for (let i = 0; i < evt.channels.length; i++) {
×
190
              const layer = spawn(createLayerMachine(evt.channels[i], numChannels), `layer ${i}`);
×
191
              layers.push(layer);
×
192
            }
193
            return layers;
×
194
          },
195
          layersOpen: ({ channelNames }, evt) => {
196
            const layers = [];
×
197
            for (let i = 0; i < evt.channels.length; i++) {
×
198
              layers.push(channelNames[evt.channels[i]]);
×
199
            }
200
            return layers;
×
201
          },
202
        }),
203
        removeLayer: assign({
204
          layers: ({ layers }, { layer }) => [...layers.filter((val) => val !== layer)],
3✔
205
          layersOpen: ({ layersOpen }, { index }) => [...layersOpen.filter((_, i) => i !== index)],
3✔
206
        }),
207
        setLayers: pure((context) =>
208
          context.layers.map((layer, i) => send({ type: 'SET_LAYER', layer: i }, { to: layer }))
2✔
209
        ),
210
        resetColors: pure((context) =>
211
          context.layers.map((layer, i) => send({ type: 'RESET_COLORS', layer: i }, { to: layer }))
×
212
        ),
213
        save: respond(({ channel, isGrayscale }) => ({ type: 'RESTORE', isGrayscale, channel })),
12✔
214
        restore: pure((context, event) =>
215
          context.isGrayscale === event.isGrayscale
×
216
            ? [send({ type: 'SET_CHANNEL', channel: event.channel })]
217
            : [
218
                send({ type: 'SET_CHANNEL', channel: event.channel }),
219
                send({ type: 'TOGGLE_COLOR_MODE' }),
220
              ]
221
        ),
222
      },
223
    }
224
  );
225

226
export default createRawMachine;
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

© 2025 Coveralls, Inc