querysub 0.563.0 → 0.565.0
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.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "querysub",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.565.0",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"note1": "note on node-forge fork, see https://github.com/digitalbazaar/forge/issues/744 for details",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"node-forge": "https://github.com/sliftist/forge#e618181b469b07bdc70b968b0391beb8ef5fecd6",
|
|
72
72
|
"pako": "^2.1.0",
|
|
73
73
|
"peggy": "^5.0.6",
|
|
74
|
-
"sliftutils": "^1.7.
|
|
74
|
+
"sliftutils": "^1.7.43",
|
|
75
75
|
"socket-function": "^1.2.26",
|
|
76
76
|
"terser": "^5.31.0",
|
|
77
77
|
"typenode": "^6.6.1",
|
|
@@ -167,6 +167,12 @@ export class ProcessesView extends qreact.Component<{
|
|
|
167
167
|
serviceId?: string;
|
|
168
168
|
}> {
|
|
169
169
|
render() {
|
|
170
|
+
// Callers hand us one entry per service instance, so a machine running several instances arrives several times. Each machine's processes are listed once, whatever it is running.
|
|
171
|
+
let machines = new Map<string, { machineId: string; applyNodeId: string }>();
|
|
172
|
+
for (let machine of this.props.machines) {
|
|
173
|
+
if (machines.has(machine.machineId)) continue;
|
|
174
|
+
machines.set(machine.machineId, machine);
|
|
175
|
+
}
|
|
170
176
|
return <div className={css.vbox(14).fillWidth}>
|
|
171
177
|
<div className={css.hbox(10).alignItems("center")}>
|
|
172
178
|
<h3 className={css.flexGrow(1)}>Processes</h3>
|
|
@@ -176,7 +182,7 @@ export class ProcessesView extends qreact.Component<{
|
|
|
176
182
|
Invalidate
|
|
177
183
|
</Button>
|
|
178
184
|
</div>
|
|
179
|
-
{
|
|
185
|
+
{[...machines.values()].map(machine => <MachineProcesses
|
|
180
186
|
key={machine.machineId}
|
|
181
187
|
machineId={machine.machineId}
|
|
182
188
|
applyNodeId={machine.applyNodeId}
|
|
@@ -35,10 +35,6 @@ export class ServiceDetailPage extends qreact.Component {
|
|
|
35
35
|
expandedErrors: t.lookup({
|
|
36
36
|
expanded: t.type(false)
|
|
37
37
|
}),
|
|
38
|
-
// Milliseconds; 0 means no scheduled time picked yet (use Deploy Now instead)
|
|
39
|
-
switchTime: t.number(0),
|
|
40
|
-
// Seconds until the release goes live; 0 means use the default (DEFAULT_OVERLAP_TIME)
|
|
41
|
-
releaseDelayOverride: t.number(0),
|
|
42
38
|
// Seconds the old instances outlive the release; 0 means use the default (DEFAULT_OVERLAP_TIME). The no-overlap deploy buttons are how you deploy with an actual 0.
|
|
43
39
|
overlapOverride: t.number(0),
|
|
44
40
|
});
|
|
@@ -64,8 +60,6 @@ export class ServiceDetailPage extends qreact.Component {
|
|
|
64
60
|
await MachineServiceController(SocketFunction.browserNodeId()).setServiceConfigs.promise([deployConfig]);
|
|
65
61
|
Querysub.commit(() => {
|
|
66
62
|
this.state.editorState = stripReleaseState(deployConfig);
|
|
67
|
-
this.state.switchTime = 0;
|
|
68
|
-
this.state.releaseDelayOverride = 0;
|
|
69
63
|
this.state.overlapOverride = 0;
|
|
70
64
|
});
|
|
71
65
|
} finally {
|
|
@@ -93,16 +87,16 @@ export class ServiceDetailPage extends qreact.Component {
|
|
|
93
87
|
modal = showModal({
|
|
94
88
|
content: <div className={css.fixed.pos(0, 0).size("100vw", "100vh").hsla(0, 0, 0, 0.5).display("flex").alignItems("center").justifyContent("center")}>
|
|
95
89
|
<div className={css.vbox(12).pad2(20).hsl(0, 0, 12).colorhsl(0, 0, 90).bord2(0, 0, 40) + " keepModalsOpen"}>
|
|
96
|
-
<div className={css.boldStyle.fontSize(16)}
|
|
90
|
+
<div className={css.boldStyle.fontSize(16)}>🚀 Deploy?</div>
|
|
97
91
|
<div>{deployConfig.parameters.overlapTime
|
|
98
|
-
? `This config
|
|
99
|
-
: "This config
|
|
92
|
+
? `This config goes live now. The old instances keep running for ${formatTime(deployConfig.parameters.overlapTime)} before shutting down.`
|
|
93
|
+
: "This config goes live now. The old instances are shut down as soon as the new ones are up, so anything still connected to them is dropped."}</div>
|
|
100
94
|
<div className={css.hbox(10)}>
|
|
101
95
|
<Button hue={0} onClick={() => {
|
|
102
96
|
modal && modal.close();
|
|
103
97
|
deployConfig.parameters.releaseTime = Date.now();
|
|
104
98
|
this.deployConfig(deployConfig);
|
|
105
|
-
}}
|
|
99
|
+
}}>🚀 Deploy</Button>
|
|
106
100
|
<Button onClick={() => modal && modal.close()}>Cancel</Button>
|
|
107
101
|
</div>
|
|
108
102
|
</div>
|
|
@@ -642,70 +636,39 @@ export class ServiceDetailPage extends qreact.Component {
|
|
|
642
636
|
<span title={`${configCompareKey(config)} !== ${configCompareKey(deployedConfig)}`}>Only the title / notes changed, so this saves immediately</span>
|
|
643
637
|
</div>;
|
|
644
638
|
}
|
|
645
|
-
let releaseDelaySeconds = this.state.releaseDelayOverride || Math.round(DEFAULT_OVERLAP_TIME / timeInSecond);
|
|
646
|
-
let releaseDelay = releaseDelaySeconds * timeInSecond;
|
|
647
639
|
let overlapSeconds = this.state.overlapOverride || Math.round(DEFAULT_OVERLAP_TIME / timeInSecond);
|
|
648
640
|
let overlap = overlapSeconds * timeInSecond;
|
|
649
|
-
|
|
650
|
-
const makeDeployConfig = (
|
|
641
|
+
// A deploy always goes live now. The overlap is what keeps the service up: the old instances keep running for it, so connections have somewhere to go while clients move across.
|
|
642
|
+
const makeDeployConfig = (overlapTime = overlap) => {
|
|
651
643
|
let deployConfig = deepCloneJSON(config);
|
|
652
|
-
deployConfig.parameters.releaseTime =
|
|
644
|
+
deployConfig.parameters.releaseTime = Date.now();
|
|
653
645
|
deployConfig.parameters.overlapTime = overlapTime;
|
|
654
646
|
return deployConfig;
|
|
655
647
|
};
|
|
656
|
-
// The switch time is inferred from the release delay, unless one is explicitly set
|
|
657
|
-
let effectiveSwitchTime = scheduledTime || now + releaseDelay;
|
|
658
648
|
return <div className={css.vbox(10).pad2(12).fillWidth.bord2(45, 70, 45).hsl(45, 60, 95)}>
|
|
659
649
|
<div className={css.boldStyle.fontSize(15)}>
|
|
660
650
|
✏️ Edited (only in this browser, until deployed)
|
|
661
651
|
</div>
|
|
662
652
|
<ParametersDiff base={liveParameters} next={config.parameters} />
|
|
663
|
-
<div className={css.hbox(12).wrap}>
|
|
653
|
+
<div className={css.hbox(12).wrap.alignItems("center")}>
|
|
664
654
|
<button
|
|
665
655
|
className={css.pad2(12, 8).button.bord2(0, 0, 20).hsl(120, 70, 85).fontWeight("bold")}
|
|
666
656
|
disabled={this.state.isDeploying}
|
|
657
|
+
title="Deploys now; the old instances keep running for the overlap before shutting down"
|
|
667
658
|
onClick={() => {
|
|
668
|
-
this.
|
|
659
|
+
this.confirmForceDeployNow(makeDeployConfig());
|
|
669
660
|
}}>
|
|
670
|
-
{this.state.isDeploying && "⏳
|
|
661
|
+
{this.state.isDeploying && "⏳ Deploying..." || "🚀 Deploy"}
|
|
671
662
|
</button>
|
|
672
663
|
<button
|
|
673
|
-
className={css.pad2(12, 8).button.bord2(0,
|
|
664
|
+
className={css.pad2(12, 8).button.bord2(0, 90, 30).hsl(0, 85, 65).colorhsl(0, 0, 100).fontWeight("bold")}
|
|
674
665
|
disabled={this.state.isDeploying}
|
|
675
|
-
title="Deploys
|
|
666
|
+
title="Deploys now AND shuts the old instances down as soon as the new ones are up (overlap of 0)"
|
|
676
667
|
onClick={() => {
|
|
677
|
-
this.
|
|
668
|
+
this.confirmForceDeployNow(makeDeployConfig(0));
|
|
678
669
|
}}>
|
|
679
670
|
Deploy, No Overlap
|
|
680
671
|
</button>
|
|
681
|
-
<div className={css.opacity(scheduledTime && 1 || 0.5)}>
|
|
682
|
-
<InputLabel
|
|
683
|
-
label="Switch at"
|
|
684
|
-
isDatetime
|
|
685
|
-
value={effectiveSwitchTime}
|
|
686
|
-
onChangeValue={value => {
|
|
687
|
-
this.state.switchTime = Number(value) || 0;
|
|
688
|
-
}}
|
|
689
|
-
/>
|
|
690
|
-
</div>
|
|
691
|
-
<span>(in {formatTime(effectiveSwitchTime - now)})</span>
|
|
692
|
-
{!!scheduledTime && <button
|
|
693
|
-
className={css.pad2(12, 8).button.bord2(0, 0, 20).hsl(0, 0, 90)}
|
|
694
|
-
onClick={() => {
|
|
695
|
-
this.state.switchTime = 0;
|
|
696
|
-
}}>
|
|
697
|
-
↺ Reset to delay-based time
|
|
698
|
-
</button>}
|
|
699
|
-
<div className={css.opacity(scheduledTime && 0.5 || 1)}>
|
|
700
|
-
<InputLabel
|
|
701
|
-
label="Release in (seconds)"
|
|
702
|
-
integer
|
|
703
|
-
value={releaseDelaySeconds}
|
|
704
|
-
onChangeValue={value => {
|
|
705
|
-
this.state.releaseDelayOverride = Number(value) || 0;
|
|
706
|
-
}}
|
|
707
|
-
/>
|
|
708
|
-
</div>
|
|
709
672
|
<InputLabel
|
|
710
673
|
label="Overlap (seconds)"
|
|
711
674
|
integer
|
|
@@ -715,29 +678,6 @@ export class ServiceDetailPage extends qreact.Component {
|
|
|
715
678
|
}}
|
|
716
679
|
/>
|
|
717
680
|
</div>
|
|
718
|
-
{!!scheduledTime && scheduledTime <= now && <span className={css.colorhsl(0, 85, 45).fontWeight("bold")}>
|
|
719
|
-
⚠️ The switch time is in the past — deploying switches immediately
|
|
720
|
-
</span>}
|
|
721
|
-
<div className={css.hbox(8)}>
|
|
722
|
-
<button
|
|
723
|
-
className={css.pad2(12, 8).button.bord2(45, 80, 35).hsl(45, 85, 82)}
|
|
724
|
-
disabled={this.state.isDeploying}
|
|
725
|
-
title="Deploys immediately; the old instances keep running for their configured overlap before shutting down"
|
|
726
|
-
onClick={() => {
|
|
727
|
-
this.confirmForceDeployNow(makeDeployConfig(Date.now()));
|
|
728
|
-
}}>
|
|
729
|
-
⚡ Force Deploy Now
|
|
730
|
-
</button>
|
|
731
|
-
<button
|
|
732
|
-
className={css.pad2(12, 8).button.bord2(0, 90, 30).hsl(0, 85, 65).colorhsl(0, 0, 100).fontWeight("bold")}
|
|
733
|
-
disabled={this.state.isDeploying}
|
|
734
|
-
title="Deploys immediately AND shuts down the old instances immediately (overlap of 0)"
|
|
735
|
-
onClick={() => {
|
|
736
|
-
this.confirmForceDeployNow(makeDeployConfig(Date.now(), 0));
|
|
737
|
-
}}>
|
|
738
|
-
⚡ Force Deploy Now, No Overlap
|
|
739
|
-
</button>
|
|
740
|
-
</div>
|
|
741
681
|
</div>;
|
|
742
682
|
})()}
|
|
743
683
|
|
|
@@ -77,21 +77,16 @@ export class UpdateButtons extends qreact.Component<{
|
|
|
77
77
|
state = t.state({
|
|
78
78
|
isDeploying: t.type(false),
|
|
79
79
|
});
|
|
80
|
-
// Deploys all outdated services to latestRef
|
|
81
|
-
private deployAll(outdatedServices: ServiceConfig[], latestRef: string,
|
|
80
|
+
// Deploys all outdated services to latestRef, always immediately. The overlap is what keeps the service up - the old instances keep running for it, so connections have somewhere to go while clients move across. noOverlap kills them at once instead.
|
|
81
|
+
private deployAll(outdatedServices: ServiceConfig[], latestRef: string, noOverlap: boolean) {
|
|
82
82
|
this.state.isDeploying = true;
|
|
83
83
|
// Props are synchronized state, so everything the async work needs is cloned into plain locals HERE, in the synced part
|
|
84
84
|
let toDeploy = outdatedServices.map(service => {
|
|
85
85
|
let updated = deepCloneJSON(service);
|
|
86
86
|
updated.parameters.gitRef = latestRef;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
updated.parameters.
|
|
90
|
-
} else {
|
|
91
|
-
updated.parameters.releaseTime = Date.now();
|
|
92
|
-
if (mode === "nowNoOverlap") {
|
|
93
|
-
updated.parameters.overlapTime = 0;
|
|
94
|
-
}
|
|
87
|
+
updated.parameters.releaseTime = Date.now();
|
|
88
|
+
if (noOverlap) {
|
|
89
|
+
updated.parameters.overlapTime = 0;
|
|
95
90
|
}
|
|
96
91
|
return updated;
|
|
97
92
|
});
|
|
@@ -112,14 +107,14 @@ export class UpdateButtons extends qreact.Component<{
|
|
|
112
107
|
content: <div className={css.vbox(12).pad2(20)}>
|
|
113
108
|
<div className={css.boldStyle.fontSize(16)}>⚡ Deploy all {outdatedServices.length} services now?</div>
|
|
114
109
|
<div>{noOverlap
|
|
115
|
-
? "
|
|
116
|
-
: "
|
|
110
|
+
? "The old instances are shut down as soon as the new ones are up (overlap of 0), so anything still connected to them is dropped."
|
|
111
|
+
: "The old instances keep running for their configured overlap before shutting down, so connections have somewhere to go while clients move across."}</div>
|
|
117
112
|
<div className={css.hbox(10)}>
|
|
118
113
|
<button
|
|
119
114
|
className={css.pad2(12, 8).button + (noOverlap && css.bord2(0, 90, 30).hsl(0, 85, 65).colorhsl(0, 0, 100).fontWeight("bold") || css.bord2(45, 80, 35).hsl(45, 85, 82))}
|
|
120
115
|
onClick={() => {
|
|
121
116
|
modal && modal.close();
|
|
122
|
-
this.deployAll(outdatedServices, latestRef, noOverlap
|
|
117
|
+
this.deployAll(outdatedServices, latestRef, noOverlap);
|
|
123
118
|
}}>
|
|
124
119
|
⚡ Deploy Now
|
|
125
120
|
</button>
|
|
@@ -188,8 +183,9 @@ export class UpdateButtons extends qreact.Component<{
|
|
|
188
183
|
<button
|
|
189
184
|
className={buttonStyle.hsl(120, 70, 90)}
|
|
190
185
|
disabled={this.state.isDeploying}
|
|
186
|
+
title="Deploys now; the old instances keep running for their configured overlap before shutting down"
|
|
191
187
|
onClick={() => {
|
|
192
|
-
this.
|
|
188
|
+
this.confirmDeployAllNow(outdatedServices, gitInfo.latestRef, false);
|
|
193
189
|
}}
|
|
194
190
|
>
|
|
195
191
|
<div>
|
|
@@ -204,28 +200,16 @@ export class UpdateButtons extends qreact.Component<{
|
|
|
204
200
|
<RenderGitRefInfo gitRef={ref} />
|
|
205
201
|
</div>)}
|
|
206
202
|
</button>
|
|
207
|
-
<button
|
|
208
|
-
className={buttonStyle.hsl(45, 85, 82)}
|
|
209
|
-
disabled={this.state.isDeploying}
|
|
210
|
-
title="Deploys immediately; the old instances keep running for their configured overlap before shutting down"
|
|
211
|
-
onClick={() => {
|
|
212
|
-
this.confirmDeployAllNow(outdatedServices, gitInfo.latestRef, false);
|
|
213
|
-
}}
|
|
214
|
-
>
|
|
215
|
-
<div>
|
|
216
|
-
{bigEmoji("⚡")} <span>{this.state.isDeploying && "⏳ Deploying..." || `Deploy All (${outdatedServices.length}) Now (no delay)`}</span>
|
|
217
|
-
</div>
|
|
218
|
-
</button>
|
|
219
203
|
<button
|
|
220
204
|
className={buttonStyle.hsl(0, 85, 70)}
|
|
221
205
|
disabled={this.state.isDeploying}
|
|
222
|
-
title="Deploys
|
|
206
|
+
title="Deploys now AND shuts the old instances down as soon as the new ones are up (overlap of 0)"
|
|
223
207
|
onClick={() => {
|
|
224
208
|
this.confirmDeployAllNow(outdatedServices, gitInfo.latestRef, true);
|
|
225
209
|
}}
|
|
226
210
|
>
|
|
227
211
|
<div>
|
|
228
|
-
{bigEmoji("⚡")} <span>{this.state.isDeploying && "⏳ Deploying..." || `Deploy All (${outdatedServices.length})
|
|
212
|
+
{bigEmoji("⚡")} <span>{this.state.isDeploying && "⏳ Deploying..." || `Deploy All (${outdatedServices.length}), No Overlap`}</span>
|
|
229
213
|
</div>
|
|
230
214
|
</button>
|
|
231
215
|
</>}
|