@searpent/react-image-annotate 2.3.5 → 2.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -750,7 +750,7 @@ var examplePhotos = [{
|
|
|
750
750
|
"Y1": 0,
|
|
751
751
|
"Y2": 1
|
|
752
752
|
},
|
|
753
|
-
"text": "[{\"key\":\"articleType\",\"value\":\"news\"}, {\"key\":\"
|
|
753
|
+
"text": "[{\"key\":\"articleType\",\"value\":\"news\"}, {\"key\":\"section\",\"value\":\"editorial\"}]",
|
|
754
754
|
"groupId": "42ba09e0-b2f5-439d-bdae-201e7c37787b",
|
|
755
755
|
"id": "aba453dd-f870-4510-ae40-a19eb52eb7d6"
|
|
756
756
|
}, {
|
|
@@ -762,7 +762,7 @@ var examplePhotos = [{
|
|
|
762
762
|
"Y1": 0,
|
|
763
763
|
"Y2": 1
|
|
764
764
|
},
|
|
765
|
-
"text": "[{\"key\":\"articleType\",\"value\":\"ads\"}, {\"key\":\"
|
|
765
|
+
"text": "[{\"key\":\"articleType\",\"value\":\"ads\"}, {\"key\":\"section\",\"value\":\"last page\"}]",
|
|
766
766
|
"groupId": "1",
|
|
767
767
|
"id": "2615bf87-7247-4bde-a0f9-45413034a6a6"
|
|
768
768
|
}]
|
package/Annotator/index.js
CHANGED
|
@@ -84,8 +84,7 @@ export var Annotator = function Annotator(_ref) {
|
|
|
84
84
|
_ref$save = _ref.save,
|
|
85
85
|
save = _ref$save === void 0 ? function () {} : _ref$save,
|
|
86
86
|
_ref$fetchImage = _ref.fetchImage,
|
|
87
|
-
fetchImage = _ref$fetchImage === void 0 ? function () {} : _ref$fetchImage
|
|
88
|
-
updatedBy = _ref.updatedBy;
|
|
87
|
+
fetchImage = _ref$fetchImage === void 0 ? function () {} : _ref$fetchImage;
|
|
89
88
|
|
|
90
89
|
if (typeof selectedImage === "string") {
|
|
91
90
|
selectedImage = (images || []).findIndex(function (img) {
|
|
@@ -215,14 +214,14 @@ export var Annotator = function Annotator(_ref) {
|
|
|
215
214
|
}
|
|
216
215
|
}
|
|
217
216
|
}, [state.previouslySelectedImage, state.selectedImage, state.images, state, save]); // Automatically save image shortly after specific metadata fields change
|
|
218
|
-
// (ArticleType, PreviousArticleId), but debounce so we don't save on every keystroke.
|
|
217
|
+
// (ArticleType, PreviousArticleId, Section), but debounce so we don't save on every keystroke.
|
|
219
218
|
|
|
220
219
|
useEffect(function () {
|
|
221
220
|
var _state$images;
|
|
222
221
|
|
|
223
222
|
var lastAction = state.lastAction;
|
|
224
223
|
|
|
225
|
-
if (!lastAction || lastAction.type !== "UPDATE_METADATA" || lastAction.name !== "articleType" && lastAction.name !== "previousArticleId" || isNaN(lastAction.imageIndex)) {
|
|
224
|
+
if (!lastAction || lastAction.type !== "UPDATE_METADATA" || lastAction.name !== "articleType" && lastAction.name !== "previousArticleId" && lastAction.name !== "section" || isNaN(lastAction.imageIndex)) {
|
|
226
225
|
return;
|
|
227
226
|
}
|
|
228
227
|
|
|
@@ -446,8 +445,7 @@ export var Annotator = function Annotator(_ref) {
|
|
|
446
445
|
recalcActive: saveActive,
|
|
447
446
|
onMetadataChange: handleMetadataChange,
|
|
448
447
|
onAddGroup: handleAddGroup,
|
|
449
|
-
onRecalcClick: handleRecalcClicked
|
|
450
|
-
updatedBy: updatedBy
|
|
448
|
+
onRecalcClick: handleRecalcClicked
|
|
451
449
|
}))
|
|
452
450
|
);
|
|
453
451
|
};
|
package/MainLayout/index.js
CHANGED
|
@@ -133,8 +133,7 @@ export var MainLayout = function MainLayout(_ref5) {
|
|
|
133
133
|
saveActive = _ref5$saveActive === void 0 ? false : _ref5$saveActive,
|
|
134
134
|
onMetadataChange = _ref5.onMetadataChange,
|
|
135
135
|
onAddGroup = _ref5.onAddGroup,
|
|
136
|
-
onRecalcClick = _ref5.onRecalcClick
|
|
137
|
-
updatedBy = _ref5.updatedBy;
|
|
136
|
+
onRecalcClick = _ref5.onRecalcClick;
|
|
138
137
|
var classes = useStyles();
|
|
139
138
|
var settings = useSettings();
|
|
140
139
|
var fullScreenHandle = useFullScreenHandle();
|
|
@@ -376,8 +375,7 @@ export var MainLayout = function MainLayout(_ref5) {
|
|
|
376
375
|
onPageClick: handlePageClick,
|
|
377
376
|
onMetadataChange: onMetadataChange,
|
|
378
377
|
metadataConfigs: state.metadataConfigs || [],
|
|
379
|
-
onRecalcClick: onRecalcClick
|
|
380
|
-
updatedBy: updatedBy
|
|
378
|
+
onRecalcClick: onRecalcClick
|
|
381
379
|
}),
|
|
382
380
|
/*#__PURE__*/
|
|
383
381
|
React.createElement(WorkspaceWrapper, null,
|
|
@@ -1,29 +1,74 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
|
|
2
|
+
import React, { useEffect, useMemo, useState } from "react";
|
|
3
3
|
export function isUpdatedByAggregator(updatedBy) {
|
|
4
4
|
if (updatedBy == null) return false;
|
|
5
5
|
return String(updatedBy).trim() === "AGGREGATOR";
|
|
6
6
|
}
|
|
7
|
+
/** Non-empty lease string or null (treat undefined / "" / whitespace as no lock). */
|
|
8
|
+
|
|
9
|
+
export function normalizeMediaPresenterLeaseUntil(raw) {
|
|
10
|
+
if (raw == null) return null;
|
|
11
|
+
var s = String(raw).trim();
|
|
12
|
+
return s === "" ? null : s;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* True when Dynamo `mediaPresenterLeaseUntil` (ISO UTC string) is still in the future.
|
|
16
|
+
* Matches the media-presenter webhook lease written by BasicLinkingFunction.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
export function isMediaPresenterLockActive(mediaPresenterLeaseUntil) {
|
|
20
|
+
var s = normalizeMediaPresenterLeaseUntil(mediaPresenterLeaseUntil);
|
|
21
|
+
if (s == null) return false;
|
|
22
|
+
var t = Date.parse(s);
|
|
23
|
+
if (Number.isNaN(t)) return false;
|
|
24
|
+
return t > Date.now();
|
|
25
|
+
}
|
|
7
26
|
/**
|
|
8
27
|
* Case-level “UPDATED BY” indicator for the page strip (left panel).
|
|
9
|
-
* Red (left) / green (right) discs, left-aligned with the page-strip switch column;
|
|
10
|
-
* Green lit only when
|
|
28
|
+
* Red (left) / green (right) discs, left-aligned with the page-strip switch column; status label after them.
|
|
29
|
+
* Green lit only when `updatedBy` is exactly AGGREGATOR and the media-presenter Dynamo lease is not active.
|
|
11
30
|
* `selectionKey` should change per selected page so the control remounts when paging.
|
|
12
31
|
*/
|
|
13
32
|
|
|
14
33
|
export default function UpdatedBySemaphore(_ref) {
|
|
15
34
|
var updatedBy = _ref.updatedBy,
|
|
35
|
+
mediaPresenterLeaseUntil = _ref.mediaPresenterLeaseUntil,
|
|
16
36
|
selectionKey = _ref.selectionKey;
|
|
17
|
-
var
|
|
37
|
+
var leaseStr = useMemo(function () {
|
|
38
|
+
return normalizeMediaPresenterLeaseUntil(mediaPresenterLeaseUntil);
|
|
39
|
+
}, [mediaPresenterLeaseUntil]); // While a lease string is present, re-evaluate every second so expiry clears without a parent refetch.
|
|
40
|
+
|
|
41
|
+
var _useState = useState(0),
|
|
42
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
43
|
+
setLeasePulse = _useState2[1];
|
|
44
|
+
|
|
45
|
+
useEffect(function () {
|
|
46
|
+
if (leaseStr == null) return undefined;
|
|
47
|
+
var id = window.setInterval(function () {
|
|
48
|
+
return setLeasePulse(function (n) {
|
|
49
|
+
return n + 1;
|
|
50
|
+
});
|
|
51
|
+
}, 1000);
|
|
52
|
+
return function () {
|
|
53
|
+
return window.clearInterval(id);
|
|
54
|
+
};
|
|
55
|
+
}, [leaseStr]);
|
|
56
|
+
var lockActive = isMediaPresenterLockActive(leaseStr);
|
|
57
|
+
var green = isUpdatedByAggregator(updatedBy) && !lockActive;
|
|
18
58
|
var source = updatedBy == null || updatedBy === "" ? "—" : String(updatedBy);
|
|
59
|
+
var leaseHint = lockActive ? " Media presenter lock active (lease until ".concat(leaseStr, ").") : "";
|
|
60
|
+
var statusLabel = green ? "Ready" : "Do not modify";
|
|
61
|
+
var title = "Case last updated by: ".concat(source, ".").concat(leaseHint, " Status: ").concat(statusLabel, ". Green lamp: safe to modify (AGGREGATOR and no active media-presenter lease). Red lamp: do not modify (other updater and/or lock).");
|
|
62
|
+
var redClass = "ps-semaphore-lamp ps-semaphore-red" + (green ? "" : " ps-semaphore-lit");
|
|
63
|
+
var greenClass = "ps-semaphore-lamp ps-semaphore-green" + (green ? " ps-semaphore-lit" : "");
|
|
19
64
|
return (
|
|
20
65
|
/*#__PURE__*/
|
|
21
66
|
React.createElement("div", {
|
|
22
|
-
key: selectionKey,
|
|
67
|
+
key: "".concat(selectionKey, "|").concat(leaseStr !== null && leaseStr !== void 0 ? leaseStr : ""),
|
|
23
68
|
className: "ps-updated-by-semaphore",
|
|
24
|
-
title:
|
|
69
|
+
title: title,
|
|
25
70
|
role: "img",
|
|
26
|
-
"aria-label":
|
|
71
|
+
"aria-label": statusLabel
|
|
27
72
|
},
|
|
28
73
|
/*#__PURE__*/
|
|
29
74
|
React.createElement("span", {
|
|
@@ -36,19 +81,15 @@ export default function UpdatedBySemaphore(_ref) {
|
|
|
36
81
|
},
|
|
37
82
|
/*#__PURE__*/
|
|
38
83
|
React.createElement("span", {
|
|
39
|
-
className:
|
|
40
|
-
"ps-semaphore-lit": !green
|
|
41
|
-
})
|
|
84
|
+
className: redClass
|
|
42
85
|
}),
|
|
43
86
|
/*#__PURE__*/
|
|
44
87
|
React.createElement("span", {
|
|
45
|
-
className:
|
|
46
|
-
"ps-semaphore-lit": green
|
|
47
|
-
})
|
|
88
|
+
className: greenClass
|
|
48
89
|
}))),
|
|
49
90
|
/*#__PURE__*/
|
|
50
91
|
React.createElement("span", {
|
|
51
92
|
className: "ps-top-bar-label ps-updated-by-semaphore__label"
|
|
52
|
-
},
|
|
93
|
+
}, statusLabel))
|
|
53
94
|
);
|
|
54
95
|
}
|
package/PageSelector/index.js
CHANGED
|
@@ -4,7 +4,6 @@ import classnames from "classnames";
|
|
|
4
4
|
import './page-selector.css';
|
|
5
5
|
import Locker from '../Locker';
|
|
6
6
|
import Errorer from '../Errorer';
|
|
7
|
-
import UpdatedBySemaphore from './UpdatedBySemaphore';
|
|
8
7
|
|
|
9
8
|
function PageThumbnail(_ref) {
|
|
10
9
|
var _metadata$find, _metadata$find$call;
|
|
@@ -149,24 +148,17 @@ function isLocked(page) {
|
|
|
149
148
|
}
|
|
150
149
|
|
|
151
150
|
function PageSelector(_ref3) {
|
|
152
|
-
var _ref4, _ref5;
|
|
153
|
-
|
|
154
151
|
var pages = _ref3.pages,
|
|
155
152
|
onPageClick = _ref3.onPageClick,
|
|
156
153
|
onMetadataChange = _ref3.onMetadataChange,
|
|
157
154
|
metadataConfigs = _ref3.metadataConfigs,
|
|
158
|
-
onRecalcClick = _ref3.onRecalcClick
|
|
159
|
-
updatedBy = _ref3.updatedBy;
|
|
155
|
+
onRecalcClick = _ref3.onRecalcClick;
|
|
160
156
|
|
|
161
157
|
var _useState = useState(false),
|
|
162
158
|
_useState2 = _slicedToArray(_useState, 2),
|
|
163
159
|
showMetadata = _useState2[0],
|
|
164
160
|
setShowMetadata = _useState2[1];
|
|
165
161
|
|
|
166
|
-
var activePage = pages.find(function (p) {
|
|
167
|
-
return p.isActive;
|
|
168
|
-
});
|
|
169
|
-
var selectionKey = (_ref4 = (_ref5 = activePage === null || activePage === void 0 ? void 0 : activePage.id) !== null && _ref5 !== void 0 ? _ref5 : activePage === null || activePage === void 0 ? void 0 : activePage.src) !== null && _ref4 !== void 0 ? _ref4 : String(pages.length);
|
|
170
162
|
return (
|
|
171
163
|
/*#__PURE__*/
|
|
172
164
|
React.createElement("div", {
|
|
@@ -179,10 +171,6 @@ function PageSelector(_ref3) {
|
|
|
179
171
|
className: "top-buttons"
|
|
180
172
|
},
|
|
181
173
|
/*#__PURE__*/
|
|
182
|
-
React.createElement("div", {
|
|
183
|
-
className: "page-selector-top-controls"
|
|
184
|
-
},
|
|
185
|
-
/*#__PURE__*/
|
|
186
174
|
React.createElement("div", {
|
|
187
175
|
className: "show-metadata-wrapper"
|
|
188
176
|
},
|
|
@@ -206,18 +194,7 @@ function PageSelector(_ref3) {
|
|
|
206
194
|
className: "slider round"
|
|
207
195
|
})),
|
|
208
196
|
/*#__PURE__*/
|
|
209
|
-
React.createElement("label",
|
|
210
|
-
className: "ps-top-bar-label"
|
|
211
|
-
}, "Metadata")), updatedBy !== undefined && updatedBy !== null &&
|
|
212
|
-
/*#__PURE__*/
|
|
213
|
-
React.createElement("div", {
|
|
214
|
-
className: "ps-semaphore-below-metadata"
|
|
215
|
-
},
|
|
216
|
-
/*#__PURE__*/
|
|
217
|
-
React.createElement(UpdatedBySemaphore, {
|
|
218
|
-
updatedBy: updatedBy,
|
|
219
|
-
selectionKey: selectionKey
|
|
220
|
-
})))),
|
|
197
|
+
React.createElement("label", null, "Metadata"))),
|
|
221
198
|
/*#__PURE__*/
|
|
222
199
|
React.createElement("div", {
|
|
223
200
|
className: "pages"
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
transition: width .5s;
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
+
.page-selector--opened {}
|
|
8
|
+
|
|
7
9
|
.pages {
|
|
8
10
|
list-style: none;
|
|
9
11
|
display: flex;
|
|
@@ -103,132 +105,6 @@
|
|
|
103
105
|
z-index: 100;
|
|
104
106
|
}
|
|
105
107
|
|
|
106
|
-
.page-selector-top-controls {
|
|
107
|
-
display: flex;
|
|
108
|
-
flex-direction: column;
|
|
109
|
-
align-items: stretch;
|
|
110
|
-
width: 100%;
|
|
111
|
-
gap: 0.5rem;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/* Same typography as “Metadata” label (plain label next to switch) */
|
|
115
|
-
.ps-top-bar-label {
|
|
116
|
-
font-family: inherit;
|
|
117
|
-
font-size: 1rem;
|
|
118
|
-
font-weight: 400;
|
|
119
|
-
line-height: 1.5;
|
|
120
|
-
color: inherit;
|
|
121
|
-
cursor: default;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
.ps-semaphore-below-metadata {
|
|
125
|
-
display: flex;
|
|
126
|
-
justify-content: flex-start;
|
|
127
|
-
align-items: center;
|
|
128
|
-
width: 100%;
|
|
129
|
-
padding-top: 0.15rem;
|
|
130
|
-
padding-left: 0;
|
|
131
|
-
box-sizing: border-box;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/* Same slot as .switch (60px) + .mr-2 (1rem) — lines up with Metadata toggle row */
|
|
135
|
-
.ps-semaphore-toggle-column {
|
|
136
|
-
width: 60px;
|
|
137
|
-
margin-right: 1rem;
|
|
138
|
-
display: flex;
|
|
139
|
-
justify-content: center;
|
|
140
|
-
align-items: center;
|
|
141
|
-
flex-shrink: 0;
|
|
142
|
-
box-sizing: border-box;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/* Plain text + discs to the right — no box */
|
|
146
|
-
.ps-updated-by-semaphore {
|
|
147
|
-
display: flex;
|
|
148
|
-
flex-direction: row;
|
|
149
|
-
align-items: center;
|
|
150
|
-
justify-content: flex-start;
|
|
151
|
-
gap: 0.5rem;
|
|
152
|
-
padding: 0;
|
|
153
|
-
margin: 0;
|
|
154
|
-
border: none;
|
|
155
|
-
background: none;
|
|
156
|
-
box-shadow: none;
|
|
157
|
-
flex-shrink: 0;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
.ps-updated-by-semaphore__label {
|
|
161
|
-
text-align: left;
|
|
162
|
-
margin: 0;
|
|
163
|
-
white-space: nowrap;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
.ps-semaphore-lamps {
|
|
167
|
-
display: flex;
|
|
168
|
-
flex-direction: row;
|
|
169
|
-
align-items: center;
|
|
170
|
-
justify-content: center;
|
|
171
|
-
gap: 6px;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/* Same diameter as Metadata toggle knob (.slider:before: 26×26) */
|
|
175
|
-
.ps-semaphore-lamp {
|
|
176
|
-
box-sizing: border-box;
|
|
177
|
-
display: inline-block;
|
|
178
|
-
vertical-align: middle;
|
|
179
|
-
width: 26px;
|
|
180
|
-
height: 26px;
|
|
181
|
-
border-radius: 50%;
|
|
182
|
-
border: 2px solid rgba(0, 0, 0, 0.1);
|
|
183
|
-
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.2);
|
|
184
|
-
transition: opacity 0.2s ease, box-shadow 0.2s ease, transform 0.15s ease, background 0.2s ease, border-color 0.2s ease;
|
|
185
|
-
flex-shrink: 0;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/* Inactive: still a faint tint of the lamp’s hue */
|
|
189
|
-
.ps-semaphore-lamp:not(.ps-semaphore-lit) {
|
|
190
|
-
opacity: 0.72;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
.ps-semaphore-lamp.ps-semaphore-lit {
|
|
194
|
-
opacity: 1;
|
|
195
|
-
transform: scale(1.02);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/* Inactive red: soft rose / dusty red */
|
|
199
|
-
.ps-semaphore-red {
|
|
200
|
-
background: linear-gradient(165deg, #f0d4d4 0%, #d9a8a8 45%, #c08080 100%);
|
|
201
|
-
border-color: rgba(180, 90, 90, 0.35);
|
|
202
|
-
box-shadow:
|
|
203
|
-
inset 0 2px 5px rgba(255, 255, 255, 0.35),
|
|
204
|
-
inset 0 -2px 6px rgba(160, 60, 60, 0.2);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
.ps-semaphore-red.ps-semaphore-lit {
|
|
208
|
-
background: linear-gradient(180deg, #ff5252 0%, #d50000 55%, #b71c1c 100%);
|
|
209
|
-
border-color: rgba(255, 200, 200, 0.85);
|
|
210
|
-
box-shadow:
|
|
211
|
-
0 0 10px rgba(213, 0, 0, 0.88),
|
|
212
|
-
inset 0 -2px 5px rgba(0, 0, 0, 0.18);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/* Inactive green: soft mint / dusty green */
|
|
216
|
-
.ps-semaphore-green {
|
|
217
|
-
background: linear-gradient(165deg, #dff2df 0%, #b8dcb8 45%, #92c592 100%);
|
|
218
|
-
border-color: rgba(80, 140, 80, 0.35);
|
|
219
|
-
box-shadow:
|
|
220
|
-
inset 0 2px 5px rgba(255, 255, 255, 0.4),
|
|
221
|
-
inset 0 -2px 6px rgba(60, 120, 60, 0.18);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
.ps-semaphore-green.ps-semaphore-lit {
|
|
225
|
-
background: linear-gradient(180deg, #b9f6ca 0%, #00e676 40%, #00c853 100%);
|
|
226
|
-
border-color: rgba(200, 255, 220, 0.9);
|
|
227
|
-
box-shadow:
|
|
228
|
-
0 0 10px rgba(0, 200, 83, 0.88),
|
|
229
|
-
inset 0 -2px 5px rgba(0, 0, 0, 0.14);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
108
|
.top-buttons button {
|
|
233
109
|
margin-bottom: 1rem;
|
|
234
110
|
width: 100%;
|