querysub 0.694.0 → 0.696.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
|
@@ -595,19 +595,6 @@ export class ServiceDetailPage extends qreact.Component {
|
|
|
595
595
|
Old instances shut down in {formatTime(scheduledDeploy.switchTime + scheduledDeploy.overlapTime - now)} ({formatDateTimeDetailed(scheduledDeploy.switchTime + scheduledDeploy.overlapTime)})
|
|
596
596
|
</div>
|
|
597
597
|
<div className={css.hbox(8)}>
|
|
598
|
-
<button
|
|
599
|
-
className={css.pad2(12, 8).button.bord2(0, 0, 20).hsl(0, 70, 90)}
|
|
600
|
-
onClick={() => {
|
|
601
|
-
this.runControllerAction(async () => {
|
|
602
|
-
let cancelled = await controller.cancelScheduledDeploy.promise(selectedServiceId);
|
|
603
|
-
// Keep the cancelled changes in the editor, so they aren't lost (Discard Changes drops them)
|
|
604
|
-
Querysub.commit(() => {
|
|
605
|
-
this.state.editorState = cancelled;
|
|
606
|
-
});
|
|
607
|
-
});
|
|
608
|
-
}}>
|
|
609
|
-
Cancel Scheduled Deploy
|
|
610
|
-
</button>
|
|
611
598
|
<button
|
|
612
599
|
className={css.pad2(12, 8).button.bord2(45, 80, 35).hsl(45, 85, 82)}
|
|
613
600
|
disabled={this.state.isDeploying}
|
|
@@ -106,22 +106,59 @@ export function confirmNoOverlapDeploy(actionLabel: string, onConfirm: () => voi
|
|
|
106
106
|
});
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
+
const CONFIRM_LIST_MAX_HEIGHT = 220;
|
|
110
|
+
|
|
111
|
+
/** Deploying every outdated service restarts all of them at once, which is most of the cluster — worth naming what is about to restart before it happens. */
|
|
112
|
+
class DeployAllConfirmModal extends qreact.Component<{ titles: string[]; latestRef: string; onConfirm: () => void }> {
|
|
113
|
+
render() {
|
|
114
|
+
let count = this.props.titles.length;
|
|
115
|
+
return <div className={css.vbox(14).maxWidth(560)}>
|
|
116
|
+
<div className={css.fontSize(18).boldStyle}>Deploy {count} service{count === 1 && "" || "s"}?</div>
|
|
117
|
+
<div>
|
|
118
|
+
Each one restarts onto {this.props.latestRef.slice(0, 6)}. The old instances keep running for {formatTime(DEFAULT_OVERLAP_TIME)} before shutting down, so there is somewhere for connections to go while clients move across.
|
|
119
|
+
</div>
|
|
120
|
+
<div className={css.vbox(2).fillWidth.maxHeight(CONFIRM_LIST_MAX_HEIGHT).overflowAuto}>
|
|
121
|
+
{this.props.titles.map(title => <div>{title}</div>)}
|
|
122
|
+
</div>
|
|
123
|
+
<div className={css.hbox(10)}>
|
|
124
|
+
<button
|
|
125
|
+
className={buttonStyle.hsl(120, 70, 90)}
|
|
126
|
+
onClick={() => {
|
|
127
|
+
closeAllModals();
|
|
128
|
+
this.props.onConfirm();
|
|
129
|
+
}}
|
|
130
|
+
>
|
|
131
|
+
Deploy & Restart All ({count})
|
|
132
|
+
</button>
|
|
133
|
+
<button className={buttonStyle.hsl(0, 0, 90)} onClick={() => closeAllModals()}>
|
|
134
|
+
Cancel
|
|
135
|
+
</button>
|
|
136
|
+
</div>
|
|
137
|
+
</div>;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
export function confirmDeployAll(config: { titles: string[]; latestRef: string; onConfirm: () => void }) {
|
|
141
|
+
showFullscreenModal({
|
|
142
|
+
content: <DeployAllConfirmModal titles={config.titles} latestRef={config.latestRef} onConfirm={config.onConfirm} />,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
109
146
|
export class UpdateButtons extends qreact.Component<{
|
|
110
147
|
services: ServiceConfig[];
|
|
111
148
|
}> {
|
|
112
149
|
state = t.state({
|
|
113
150
|
isDeploying: t.type(false),
|
|
114
151
|
});
|
|
115
|
-
// 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.
|
|
116
|
-
private deployAll(outdatedServices: ServiceConfig[], latestRef: string
|
|
152
|
+
// 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.
|
|
153
|
+
private deployAll(outdatedServices: ServiceConfig[], latestRef: string) {
|
|
117
154
|
this.state.isDeploying = true;
|
|
118
155
|
// Props are synchronized state, so everything the async work needs is cloned into plain locals HERE, in the synced part
|
|
119
156
|
let toDeploy = outdatedServices.map(service => {
|
|
120
157
|
let updated = deepCloneJSON(service);
|
|
121
158
|
updated.parameters.gitRef = latestRef;
|
|
122
159
|
updated.parameters.releaseTime = Date.now();
|
|
123
|
-
// Always set, never inherited: the overlap belongs to the deploy being made, and leaving the previous deploy's value in place means one no-overlap deploy silently makes every later deploy a no-overlap one.
|
|
124
|
-
updated.parameters.overlapTime =
|
|
160
|
+
// Always set, never inherited: the overlap belongs to the deploy being made, and leaving the previous deploy's value in place means one no-overlap deploy silently makes every later deploy a no-overlap one.
|
|
161
|
+
updated.parameters.overlapTime = DEFAULT_OVERLAP_TIME;
|
|
125
162
|
return updated;
|
|
126
163
|
});
|
|
127
164
|
let controller = MachineServiceController(SocketFunction.browserNodeId());
|
|
@@ -190,9 +227,13 @@ export class UpdateButtons extends qreact.Component<{
|
|
|
190
227
|
<button
|
|
191
228
|
className={buttonStyle.hsl(120, 70, 90)}
|
|
192
229
|
disabled={this.state.isDeploying}
|
|
193
|
-
title="
|
|
230
|
+
title="Asks first, then deploys; the old instances keep running for their configured overlap before shutting down"
|
|
194
231
|
onClick={() => {
|
|
195
|
-
|
|
232
|
+
confirmDeployAll({
|
|
233
|
+
titles: outdatedServices.map(service => service.info.title),
|
|
234
|
+
latestRef: gitInfo.latestRef,
|
|
235
|
+
onConfirm: () => this.deployAll(outdatedServices, gitInfo.latestRef),
|
|
236
|
+
});
|
|
196
237
|
}}
|
|
197
238
|
>
|
|
198
239
|
<div>
|
|
@@ -207,20 +248,6 @@ export class UpdateButtons extends qreact.Component<{
|
|
|
207
248
|
<RenderGitRefInfo gitRef={ref} />
|
|
208
249
|
</div>)}
|
|
209
250
|
</button>
|
|
210
|
-
<button
|
|
211
|
-
className={buttonStyle.hsl(0, 85, 70)}
|
|
212
|
-
disabled={this.state.isDeploying}
|
|
213
|
-
title="Deploys now AND shuts the old instances down as soon as the new ones are up (overlap of 0)"
|
|
214
|
-
onClick={() => {
|
|
215
|
-
confirmNoOverlapDeploy(`Deploy All (${outdatedServices.length}), No Overlap`, () => {
|
|
216
|
-
this.deployAll(outdatedServices, gitInfo.latestRef, true);
|
|
217
|
-
});
|
|
218
|
-
}}
|
|
219
|
-
>
|
|
220
|
-
<div>
|
|
221
|
-
{bigEmoji("⚡")} <span>{this.state.isDeploying && "⏳ Deploying..." || `Deploy All (${outdatedServices.length}), No Overlap`}</span>
|
|
222
|
-
</div>
|
|
223
|
-
</button>
|
|
224
251
|
</>}
|
|
225
252
|
</>;
|
|
226
253
|
}
|
|
@@ -415,20 +415,6 @@ export class MachineServiceControllerBase {
|
|
|
415
415
|
void this.notifyMachines([], getConfigMachineIds(normalizeServiceConfig(serviceConfig)));
|
|
416
416
|
}
|
|
417
417
|
|
|
418
|
-
/** Cancels parameters that are scheduled to deploy (releaseTime in the future), reverting to what is currently live. Returns the cancelled config, so the caller can keep the edits (ex, back in the editor). */
|
|
419
|
-
public async cancelScheduledDeploy(serviceId: string): Promise<ServiceConfig> {
|
|
420
|
-
let record = await serviceConfigs.get(serviceId);
|
|
421
|
-
if (!record) {
|
|
422
|
-
throw new Error(`Service ${serviceId} does not exist`);
|
|
423
|
-
}
|
|
424
|
-
normalizeServiceConfig(record);
|
|
425
|
-
if (!record.parameters.releaseTime || Date.now() >= record.parameters.releaseTime || !record.oldParameters) {
|
|
426
|
-
throw new Error(`Service ${serviceId} has no scheduled deploy to cancel (it may have already gone live)`);
|
|
427
|
-
}
|
|
428
|
-
await serviceConfigs.set(serviceId, { ...record, parameters: record.oldParameters, oldParameters: undefined });
|
|
429
|
-
void this.notifyMachines(getConfigMachineIds(record), []);
|
|
430
|
-
return stripReleaseState(record);
|
|
431
|
-
}
|
|
432
418
|
public async getServiceConfigType(): Promise<string> {
|
|
433
419
|
return extractType(module, "ServiceConfig");
|
|
434
420
|
}
|
|
@@ -657,7 +643,6 @@ export const MachineServiceController = getSyncedController(
|
|
|
657
643
|
setMachineConfig: {},
|
|
658
644
|
addServiceConfig: {},
|
|
659
645
|
setServiceConfigs: {},
|
|
660
|
-
cancelScheduledDeploy: {},
|
|
661
646
|
getServiceConfigType: {},
|
|
662
647
|
deleteServiceConfig: {},
|
|
663
648
|
getGitInfo: {},
|
|
@@ -682,7 +667,6 @@ export const MachineServiceController = getSyncedController(
|
|
|
682
667
|
setMachineConfig: ["MachineConfig", "MachineConfigList"],
|
|
683
668
|
addServiceConfig: ["ServiceConfig", "ServiceConfigList"],
|
|
684
669
|
setServiceConfigs: ["ServiceConfig"],
|
|
685
|
-
cancelScheduledDeploy: ["ServiceConfig"],
|
|
686
670
|
deleteServiceConfig: ["ServiceConfig", "ServiceConfigList"],
|
|
687
671
|
commitPushService: ["gitInfo", "ServiceConfig"],
|
|
688
672
|
commitPushAndPublishQuerysub: ["gitInfo", "ServiceConfig"],
|