Bin
2025-12-17 bc6aa38242b0a7dea4b18bc90e2d78740436a58b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import { types } from "mobx-state-tree";
import isMatch from "lodash/isMatch";
import InfoModal from "../../components/Infomodal/Infomodal";
import { AnnotationMixin } from "../../mixins/AnnotationMixin";
import { FF_DEV_3391, isFF } from "../../utils/feature-flags";
import { BaseTag } from "../TagBase";
 
const ObjectBase = types
  .model({
    ...(isFF(FF_DEV_3391)
      ? {
          id: types.identifier,
          name: types.string,
        }
      : {
          name: types.identifier,
        }),
    // TODO there should be a better way to force an update
    _needsUpdate: types.optional(types.number, 0),
  })
  .volatile(() => ({
    isObjectTag: true,
    supportSuggestions: false,
  }))
  .views((self) => ({
    /**
     * A list of all related regions
     * it is using for validation purposes
     */
    get allRegs() {
      return self.annotation?.regionStore.regions.filter((r) => r.object === self) || [];
    },
    /**
     * A list of regions related to the current object state
     * (it could be overridden)
     */
    get regs() {
      return self.allRegs;
    },
    findRegion(params) {
      let obj = null;
 
      if (self._regionsCache && self._regionsCache.length) {
        obj = self._regionsCache.find(({ region }) => isMatch(region, params));
      }
 
      return obj || self.regions.find((r) => isMatch(r, params));
    },
    get isReady() {
      return true;
    },
  }))
  .actions((self) => {
    const props = {};
 
    function addProp(name, value) {
      props[name] = value;
      self._needsUpdate = self._needsUpdate + 1;
    }
 
    function getProps() {
      return props;
    }
 
    // @todo maybe not a best place for this method?
    // check that maxUsages was not exceeded for labels
    // and if it was - don't allow to create new region and unselect all regions
    // unselect labels which was exceeded maxUsages
    // return all states left untouched - available labels and others
    function getAvailableStates() {
      // `checkMaxUsages` may unselect labels with already reached `maxUsages`
      const checkAndCollect = (list, s) => (s.checkMaxUsages ? list.concat(s.checkMaxUsages()) : list);
      const allStates = self.states() || [];
      const exceeded = allStates.reduce(checkAndCollect, []).filter((e) => e.selected);
      exceeded.forEach((e) => e.setSelected(false));
 
      const states = self.activeStates() || [];
 
      if (states.length === 0) {
        if (exceeded.length) {
          const label = exceeded[0];
 
          InfoModal.warning(`You can't use ${label.value} more than ${label.maxUsages} time(s)`);
        }
        self.annotation.unselectAll();
      }
      return states;
    }
 
    return {
      addProp,
      getProps,
      getAvailableStates,
    };
  });
 
export default types.compose(ObjectBase, BaseTag, AnnotationMixin);