@spinnaker/titus 0.0.0-2025.1-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/CHANGELOG.md +2661 -0
- package/LICENSE.txt +203 -0
- package/dist/domain/IJobDisruptionBudget.d.ts +35 -0
- package/dist/domain/ITitusCredentials.d.ts +5 -0
- package/dist/domain/ITitusInstance.d.ts +28 -0
- package/dist/domain/ITitusScalingPolicy.d.ts +4 -0
- package/dist/domain/ITitusServerGroup.d.ts +52 -0
- package/dist/domain/ITitusServiceJobProcesses.d.ts +3 -0
- package/dist/domain/index.d.ts +5 -0
- package/dist/help/titus.help.d.ts +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +12828 -0
- package/dist/index.js.map +1 -0
- package/dist/instance/details/TitusInstanceDetails.d.ts +25 -0
- package/dist/instance/details/TitusInstanceDns.d.ts +8 -0
- package/dist/instance/details/TitusInstanceInformation.d.ts +7 -0
- package/dist/instance/details/index.d.ts +4 -0
- package/dist/instance/details/titusInstanceDetailsUtils.d.ts +14 -0
- package/dist/pipeline/stages/cloneServerGroup/cloneServerGroupExecutionDetails.controller.d.ts +2 -0
- package/dist/pipeline/stages/cloneServerGroup/titusCloneServerGroupStage.d.ts +2 -0
- package/dist/pipeline/stages/destroyAsg/titusDestroyAsgStage.d.ts +2 -0
- package/dist/pipeline/stages/disableAsg/titusDisableAsgStage.d.ts +2 -0
- package/dist/pipeline/stages/disableCluster/titusDisableClusterStage.d.ts +2 -0
- package/dist/pipeline/stages/enableAsg/titusEnableAsgStage.d.ts +2 -0
- package/dist/pipeline/stages/findAmi/titusFindAmiStage.d.ts +2 -0
- package/dist/pipeline/stages/resizeAsg/titusResizeAsgStage.d.ts +2 -0
- package/dist/pipeline/stages/runJob/RunJobExecutionDetails.d.ts +16 -0
- package/dist/pipeline/stages/runJob/TitusRunJobStageConfig.d.ts +25 -0
- package/dist/pipeline/stages/runJob/TitusSecurityGroupPicker.d.ts +34 -0
- package/dist/pipeline/stages/runJob/titusRunJobStage.d.ts +1 -0
- package/dist/pipeline/stages/scaleDownCluster/titusScaleDownClusterStage.d.ts +2 -0
- package/dist/pipeline/stages/shrinkCluster/titusShrinkClusterStage.d.ts +2 -0
- package/dist/reactShims/index.d.ts +1 -0
- package/dist/reactShims/titus.react.injector.d.ts +11 -0
- package/dist/reactShims/titus.react.module.d.ts +1 -0
- package/dist/securityGroup/securityGroup.read.service.d.ts +2 -0
- package/dist/serverGroup/configure/ServerGroupCommandBuilder.d.ts +2 -0
- package/dist/serverGroup/configure/serverGroup.configure.titus.module.d.ts +2 -0
- package/dist/serverGroup/configure/serverGroupConfiguration.service.d.ts +89 -0
- package/dist/serverGroup/configure/wizard/TitusCloneServerGroupModal.d.ts +31 -0
- package/dist/serverGroup/configure/wizard/pages/ServerGroupBasicSettings.d.ts +28 -0
- package/dist/serverGroup/configure/wizard/pages/ServerGroupParameters.d.ts +15 -0
- package/dist/serverGroup/configure/wizard/pages/ServerGroupResources.d.ts +11 -0
- package/dist/serverGroup/configure/wizard/pages/TitusMapLayout.d.ts +4 -0
- package/dist/serverGroup/configure/wizard/pages/disruptionBudget/JobDisruptionBudget.d.ts +40 -0
- package/dist/serverGroup/configure/wizard/pages/disruptionBudget/PolicyOptions.d.ts +2 -0
- package/dist/serverGroup/configure/wizard/pages/disruptionBudget/RateOptions.d.ts +2 -0
- package/dist/serverGroup/configure/wizard/pages/disruptionBudget/WindowPicker.d.ts +23 -0
- package/dist/serverGroup/configure/wizard/pages/index.d.ts +4 -0
- package/dist/serverGroup/details/TitusCapacityDetailsSection.d.ts +11 -0
- package/dist/serverGroup/details/TitusLaunchConfigSection.d.ts +9 -0
- package/dist/serverGroup/details/TitusPackageDetailsSection.d.ts +6 -0
- package/dist/serverGroup/details/TitusSecurityGroups.d.ts +17 -0
- package/dist/serverGroup/details/capacityDetailsSection.component.d.ts +1 -0
- package/dist/serverGroup/details/disruptionBudget/DisruptionBudgetSection.d.ts +19 -0
- package/dist/serverGroup/details/disruptionBudget/EditDisruptionBudgetModal.d.ts +14 -0
- package/dist/serverGroup/details/index.d.ts +5 -0
- package/dist/serverGroup/details/launchConfigSection.component.d.ts +1 -0
- package/dist/serverGroup/details/resize/TitusResizeServerGroupModal.d.ts +8 -0
- package/dist/serverGroup/details/resize/useTaskMonitor.d.ts +25 -0
- package/dist/serverGroup/details/rollback/rollbackServerGroup.controller.d.ts +2 -0
- package/dist/serverGroup/details/scalingActivity/TitusScalingActivitiesModal.d.ts +7 -0
- package/dist/serverGroup/details/scalingPolicy/CreateScalingPolicyButton.d.ts +21 -0
- package/dist/serverGroup/details/scalingPolicy/TitusCustomScalingPolicy.d.ts +7 -0
- package/dist/serverGroup/details/scalingPolicy/createScalingPolicyButton.component.d.ts +1 -0
- package/dist/serverGroup/details/scalingPolicy/index.d.ts +3 -0
- package/dist/serverGroup/details/scalingPolicy/scalingPolicy.module.d.ts +1 -0
- package/dist/serverGroup/details/scalingPolicy/targetTracking/TitusTargetTrackingChart.d.ts +9 -0
- package/dist/serverGroup/details/scalingPolicy/targetTracking/UpsertTargetTrackingModal.d.ts +10 -0
- package/dist/serverGroup/details/scalingPolicy/titusCustomScalingPolicy.component.d.ts +1 -0
- package/dist/serverGroup/details/scalingPolicy/upsert/TitusScalingPolicyCommandBuilderService.d.ts +10 -0
- package/dist/serverGroup/details/scalingPolicy/upsert/UpsertScalingPolicyModal.d.ts +10 -0
- package/dist/serverGroup/details/sections/ITitusServerGroupDetailsSectionProps.d.ts +5 -0
- package/dist/serverGroup/details/serverGroupDetails.titus.controller.d.ts +2 -0
- package/dist/serverGroup/details/serviceJobProcesses/ServiceJobProcesses.d.ts +3 -0
- package/dist/serverGroup/details/serviceJobProcesses/ServiceJobProcessesSection.d.ts +7 -0
- package/dist/serverGroup/details/titusPackageDetailsSection.component.d.ts +1 -0
- package/dist/serverGroup/details/titusSecurityGroups.component.d.ts +1 -0
- package/dist/serverGroup/serverGroup.transformer.d.ts +2 -0
- package/dist/titus.module.d.ts +5 -0
- package/dist/titus.settings.d.ts +14 -0
- package/dist/validation/ApplicationNameValidator.d.ts +1 -0
- package/package.json +52 -0
- package/src/domain/IJobDisruptionBudget.ts +19 -0
- package/src/domain/ITitusCredentials.ts +6 -0
- package/src/domain/ITitusInstance.ts +30 -0
- package/src/domain/ITitusScalingPolicy.ts +5 -0
- package/src/domain/ITitusServerGroup.ts +56 -0
- package/src/domain/ITitusServiceJobProcesses.ts +3 -0
- package/src/domain/index.ts +5 -0
- package/src/help/titus.help.ts +99 -0
- package/src/index.ts +6 -0
- package/src/instance/details/TitusInstanceDetails.tsx +234 -0
- package/src/instance/details/TitusInstanceDns.tsx +40 -0
- package/src/instance/details/TitusInstanceInformation.tsx +42 -0
- package/src/instance/details/index.ts +4 -0
- package/src/instance/details/titusInstanceDetailsUtils.spec.ts +124 -0
- package/src/instance/details/titusInstanceDetailsUtils.ts +181 -0
- package/src/logo/titus.logo.less +5 -0
- package/src/logo/titus.logo.png +0 -0
- package/src/logo/titus.logo.svg +7 -0
- package/src/pipeline/stages/cloneServerGroup/cloneServerGroupExecutionDetails.controller.js +66 -0
- package/src/pipeline/stages/cloneServerGroup/cloneServerGroupExecutionDetails.html +46 -0
- package/src/pipeline/stages/cloneServerGroup/cloneServerGroupStage.html +106 -0
- package/src/pipeline/stages/cloneServerGroup/cloneServerGroupStepLabel.html +1 -0
- package/src/pipeline/stages/cloneServerGroup/titusCloneServerGroupStage.js +104 -0
- package/src/pipeline/stages/destroyAsg/destroyAsgStage.html +9 -0
- package/src/pipeline/stages/destroyAsg/destroyAsgStepLabel.html +1 -0
- package/src/pipeline/stages/destroyAsg/titusDestroyAsgStage.js +65 -0
- package/src/pipeline/stages/disableAsg/disableAsgStage.html +11 -0
- package/src/pipeline/stages/disableAsg/disableAsgStepLabel.html +1 -0
- package/src/pipeline/stages/disableAsg/titusDisableAsgStage.js +69 -0
- package/src/pipeline/stages/disableCluster/disableClusterStage.html +26 -0
- package/src/pipeline/stages/disableCluster/titusDisableClusterStage.js +85 -0
- package/src/pipeline/stages/enableAsg/enableAsgStage.html +11 -0
- package/src/pipeline/stages/enableAsg/enableAsgStepLabel.html +1 -0
- package/src/pipeline/stages/enableAsg/titusEnableAsgStage.js +73 -0
- package/src/pipeline/stages/findAmi/findAmiStage.html +24 -0
- package/src/pipeline/stages/findAmi/titusFindAmiStage.js +79 -0
- package/src/pipeline/stages/resizeAsg/resizeAsgStage.html +99 -0
- package/src/pipeline/stages/resizeAsg/resizeAsgStepLabel.html +1 -0
- package/src/pipeline/stages/resizeAsg/titusResizeAsgStage.js +125 -0
- package/src/pipeline/stages/runJob/RunJobExecutionDetails.tsx +165 -0
- package/src/pipeline/stages/runJob/TitusRunJobStageConfig.tsx +466 -0
- package/src/pipeline/stages/runJob/TitusSecurityGroupPicker.tsx +170 -0
- package/src/pipeline/stages/runJob/titusRunJobStage.ts +30 -0
- package/src/pipeline/stages/scaleDownCluster/scaleDownClusterStage.html +35 -0
- package/src/pipeline/stages/scaleDownCluster/titusScaleDownClusterStage.js +79 -0
- package/src/pipeline/stages/shrinkCluster/shrinkClusterStage.html +34 -0
- package/src/pipeline/stages/shrinkCluster/titusShrinkClusterStage.js +73 -0
- package/src/reactShims/index.ts +1 -0
- package/src/reactShims/titus.react.injector.ts +17 -0
- package/src/reactShims/titus.react.module.ts +10 -0
- package/src/securityGroup/securityGroup.read.service.js +15 -0
- package/src/serverGroup/configure/ServerGroupCommandBuilder.js +247 -0
- package/src/serverGroup/configure/serverGroup.configure.titus.module.js +9 -0
- package/src/serverGroup/configure/serverGroupCommandBuilder.spec.js +63 -0
- package/src/serverGroup/configure/serverGroupConfiguration.service.ts +410 -0
- package/src/serverGroup/configure/wizard/TitusCloneServerGroupModal.tsx +293 -0
- package/src/serverGroup/configure/wizard/pages/ServerGroupBasicSettings.tsx +339 -0
- package/src/serverGroup/configure/wizard/pages/ServerGroupParameters.less +5 -0
- package/src/serverGroup/configure/wizard/pages/ServerGroupParameters.tsx +217 -0
- package/src/serverGroup/configure/wizard/pages/ServerGroupResources.tsx +200 -0
- package/src/serverGroup/configure/wizard/pages/TitusMapLayout.less +3 -0
- package/src/serverGroup/configure/wizard/pages/TitusMapLayout.tsx +29 -0
- package/src/serverGroup/configure/wizard/pages/disruptionBudget/JobDisruptionBudget.tsx +285 -0
- package/src/serverGroup/configure/wizard/pages/disruptionBudget/PolicyOptions.tsx +112 -0
- package/src/serverGroup/configure/wizard/pages/disruptionBudget/RateOptions.tsx +89 -0
- package/src/serverGroup/configure/wizard/pages/disruptionBudget/WindowPicker.tsx +202 -0
- package/src/serverGroup/configure/wizard/pages/index.ts +4 -0
- package/src/serverGroup/details/TitusCapacityDetailsSection.tsx +66 -0
- package/src/serverGroup/details/TitusLaunchConfigSection.tsx +35 -0
- package/src/serverGroup/details/TitusPackageDetailsSection.tsx +40 -0
- package/src/serverGroup/details/TitusSecurityGroups.tsx +107 -0
- package/src/serverGroup/details/capacityDetailsSection.component.ts +12 -0
- package/src/serverGroup/details/disruptionBudget/DisruptionBudgetSection.tsx +226 -0
- package/src/serverGroup/details/disruptionBudget/EditDisruptionBudgetModal.tsx +92 -0
- package/src/serverGroup/details/index.ts +5 -0
- package/src/serverGroup/details/launchConfigSection.component.ts +12 -0
- package/src/serverGroup/details/resize/TitusResizeServerGroupModal.tsx +302 -0
- package/src/serverGroup/details/resize/useTaskMonitor.ts +30 -0
- package/src/serverGroup/details/rollback/rollbackServerGroup.controller.js +149 -0
- package/src/serverGroup/details/rollback/rollbackServerGroup.html +133 -0
- package/src/serverGroup/details/scalingActivity/TitusScalingActivitiesModal.tsx +81 -0
- package/src/serverGroup/details/scalingPolicy/CreateScalingPolicyButton.tsx +102 -0
- package/src/serverGroup/details/scalingPolicy/TitusCustomScalingPolicy.tsx +13 -0
- package/src/serverGroup/details/scalingPolicy/createScalingPolicyButton.component.ts +15 -0
- package/src/serverGroup/details/scalingPolicy/index.js +3 -0
- package/src/serverGroup/details/scalingPolicy/scalingPolicy.module.ts +7 -0
- package/src/serverGroup/details/scalingPolicy/targetTracking/TitusTargetTrackingChart.tsx +57 -0
- package/src/serverGroup/details/scalingPolicy/targetTracking/UpsertTargetTrackingModal.tsx +82 -0
- package/src/serverGroup/details/scalingPolicy/titusCustomScalingPolicy.component.ts +17 -0
- package/src/serverGroup/details/scalingPolicy/upsert/TitusScalingPolicyCommandBuilderService.ts +115 -0
- package/src/serverGroup/details/scalingPolicy/upsert/UpsertScalingPolicyModal.tsx +157 -0
- package/src/serverGroup/details/sections/ITitusServerGroupDetailsSectionProps.ts +6 -0
- package/src/serverGroup/details/serverGroupDetails.html +191 -0
- package/src/serverGroup/details/serverGroupDetails.titus.controller.js +457 -0
- package/src/serverGroup/details/serviceJobProcesses/ServiceJobProcesses.ts +12 -0
- package/src/serverGroup/details/serviceJobProcesses/ServiceJobProcessesSection.tsx +136 -0
- package/src/serverGroup/details/titusPackageDetailsSection.component.ts +12 -0
- package/src/serverGroup/details/titusSecurityGroups.component.ts +12 -0
- package/src/serverGroup/serverGroup.transformer.js +90 -0
- package/src/titus.module.ts +95 -0
- package/src/titus.settings.ts +22 -0
- package/src/validation/ApplicationNameValidator.ts +43 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import type { IAmazonHealth } from '@spinnaker/amazon';
|
|
4
|
+
import { InstanceStatus } from '@spinnaker/amazon';
|
|
5
|
+
import type {
|
|
6
|
+
Action,
|
|
7
|
+
Application,
|
|
8
|
+
IAccountDetails,
|
|
9
|
+
IInstanceDetailsProps,
|
|
10
|
+
IMoniker,
|
|
11
|
+
IOverridableProps,
|
|
12
|
+
} from '@spinnaker/core';
|
|
13
|
+
import {
|
|
14
|
+
AccountService,
|
|
15
|
+
CollapsibleSection,
|
|
16
|
+
ConsoleOutputLink,
|
|
17
|
+
InstanceActions,
|
|
18
|
+
InstanceDetailsHeader,
|
|
19
|
+
InstanceDetailsPane,
|
|
20
|
+
InstanceInsights,
|
|
21
|
+
InstanceLinks,
|
|
22
|
+
InstanceReader,
|
|
23
|
+
overridableComponent,
|
|
24
|
+
RecentHistoryService,
|
|
25
|
+
SETTINGS,
|
|
26
|
+
Spinner,
|
|
27
|
+
useData,
|
|
28
|
+
} from '@spinnaker/core';
|
|
29
|
+
|
|
30
|
+
import { TitusInstanceDns } from './TitusInstanceDns';
|
|
31
|
+
import { TitusInstanceInformation } from './TitusInstanceInformation';
|
|
32
|
+
import type { ITitusInstance, ITitusServerGroup, ITitusServerGroupView } from '../../domain';
|
|
33
|
+
import { TitusSecurityGroupsDetailsSection } from '../../serverGroup/details/TitusSecurityGroups';
|
|
34
|
+
import { buildTaskActions, extractHealthMetrics } from './titusInstanceDetailsUtils';
|
|
35
|
+
|
|
36
|
+
export interface ITitusInstanceDetailsProps extends IInstanceDetailsProps {
|
|
37
|
+
instance: { instanceId: string };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface ITitusInstanceDetailsContentProps {
|
|
41
|
+
account: IAccountDetails;
|
|
42
|
+
actions: Action[];
|
|
43
|
+
app: Application;
|
|
44
|
+
baseIpAddress: string;
|
|
45
|
+
environment: string;
|
|
46
|
+
healthMetrics: IAmazonHealth[];
|
|
47
|
+
instance: ITitusInstance;
|
|
48
|
+
instanceId: string;
|
|
49
|
+
instancePort: string;
|
|
50
|
+
loading: boolean;
|
|
51
|
+
moniker: IMoniker;
|
|
52
|
+
serverGroup: ITitusServerGroup;
|
|
53
|
+
region: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const TitusInstanceDetailsContent = ({
|
|
57
|
+
account,
|
|
58
|
+
actions,
|
|
59
|
+
app,
|
|
60
|
+
baseIpAddress,
|
|
61
|
+
environment,
|
|
62
|
+
healthMetrics,
|
|
63
|
+
instance,
|
|
64
|
+
instanceId,
|
|
65
|
+
instancePort,
|
|
66
|
+
loading,
|
|
67
|
+
moniker,
|
|
68
|
+
serverGroup,
|
|
69
|
+
region,
|
|
70
|
+
}: ITitusInstanceDetailsContentProps) => {
|
|
71
|
+
const defaultSshLink = `ssh -t ${account?.bastionHost} 'titus-ssh -region ${region} ${instanceId}'`;
|
|
72
|
+
return (
|
|
73
|
+
<div className="details-panel">
|
|
74
|
+
<div className="header">
|
|
75
|
+
<InstanceDetailsHeader
|
|
76
|
+
healthState={instance.healthState}
|
|
77
|
+
instanceId={instanceId}
|
|
78
|
+
loading={loading}
|
|
79
|
+
sshLink={defaultSshLink}
|
|
80
|
+
standalone={app.isStandalone}
|
|
81
|
+
/>
|
|
82
|
+
<div className="actions">
|
|
83
|
+
<InstanceActions actions={actions} />
|
|
84
|
+
{Boolean(instance?.insightActions?.length) && (
|
|
85
|
+
<InstanceInsights analytics={true} insights={instance.insightActions} instance={instance} />
|
|
86
|
+
)}
|
|
87
|
+
</div>
|
|
88
|
+
</div>
|
|
89
|
+
<div className="content">
|
|
90
|
+
<TitusInstanceInformation instance={instance} titusUiEndpoint={instance.titusUiEndpoint} />
|
|
91
|
+
<InstanceStatus
|
|
92
|
+
healthMetrics={healthMetrics}
|
|
93
|
+
healthState={instance.healthState}
|
|
94
|
+
metricTypes={['TargetGroup']}
|
|
95
|
+
privateIpAddress={instance.privateIpAddress}
|
|
96
|
+
/>
|
|
97
|
+
<TitusInstanceDns
|
|
98
|
+
containerIp={instance.placement?.containerIp}
|
|
99
|
+
host={instance.placement?.host}
|
|
100
|
+
instancePort={instancePort}
|
|
101
|
+
ipv6Address={instance.ipv6Address}
|
|
102
|
+
/>
|
|
103
|
+
<div className="collapsible-section">
|
|
104
|
+
<TitusSecurityGroupsDetailsSection app={app} serverGroup={serverGroup as ITitusServerGroupView} />
|
|
105
|
+
</div>
|
|
106
|
+
<CollapsibleSection heading="Console Output">
|
|
107
|
+
<ConsoleOutputLink instance={instance} />
|
|
108
|
+
</CollapsibleSection>
|
|
109
|
+
<InstanceLinks
|
|
110
|
+
address={baseIpAddress}
|
|
111
|
+
application={app}
|
|
112
|
+
instance={instance}
|
|
113
|
+
environment={environment}
|
|
114
|
+
moniker={moniker}
|
|
115
|
+
/>
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const OverridableTitusInstanceDetailsContent = overridableComponent<
|
|
122
|
+
ITitusInstanceDetailsContentProps & IOverridableProps,
|
|
123
|
+
typeof TitusInstanceDetailsContent
|
|
124
|
+
>(TitusInstanceDetailsContent, 'titus.instance.details.content');
|
|
125
|
+
|
|
126
|
+
export const TitusInstanceDetails = ({ app, environment, instance, moniker }: ITitusInstanceDetailsProps) => {
|
|
127
|
+
const { instanceId } = instance;
|
|
128
|
+
const serverGroup = app.serverGroups.data.find((sg: ITitusServerGroup) =>
|
|
129
|
+
sg.instances.some((possibleMatch) => possibleMatch.id === instanceId),
|
|
130
|
+
);
|
|
131
|
+
const { account, region } = serverGroup;
|
|
132
|
+
|
|
133
|
+
const retrieveInstance = () => {
|
|
134
|
+
RecentHistoryService.addExtraDataToLatest('instances', {
|
|
135
|
+
account,
|
|
136
|
+
region,
|
|
137
|
+
serverGroup: serverGroup.name,
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
return Promise.all([
|
|
141
|
+
InstanceReader.getInstanceDetails(account, region, instanceId).then((instance) => ({
|
|
142
|
+
...instance,
|
|
143
|
+
account,
|
|
144
|
+
region,
|
|
145
|
+
})),
|
|
146
|
+
AccountService.getAccountDetails(account),
|
|
147
|
+
]);
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const addTitusUiEndpoint = (result: [ITitusInstance, IAccountDetails]) => {
|
|
151
|
+
const [instance, account] = result;
|
|
152
|
+
const regionDetails = (account?.regions || []).find((r) => r.name === region);
|
|
153
|
+
|
|
154
|
+
return [{ titusUiEndpoint: regionDetails?.endpoint, ...instance }, account];
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const {
|
|
158
|
+
result: [currentInstance, currentAccount],
|
|
159
|
+
status,
|
|
160
|
+
} = useData(
|
|
161
|
+
() => {
|
|
162
|
+
if (app.isStandalone) {
|
|
163
|
+
return retrieveInstance().then((result) => addTitusUiEndpoint(result as [ITitusInstance, IAccountDetails]));
|
|
164
|
+
} else {
|
|
165
|
+
return app.serverGroups
|
|
166
|
+
.ready()
|
|
167
|
+
.then(retrieveInstance)
|
|
168
|
+
.then((result: [ITitusInstance, IAccountDetails]) => addTitusUiEndpoint(result));
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
[{} as ITitusInstance, {} as IAccountDetails],
|
|
172
|
+
[instanceId, serverGroup],
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
const taskActions = buildTaskActions(currentInstance, app);
|
|
176
|
+
const healthMetrics = extractHealthMetrics(
|
|
177
|
+
currentInstance.health as IAmazonHealth[],
|
|
178
|
+
app.loadBalancers.data,
|
|
179
|
+
currentAccount.awsAccount,
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
const isLoading = status === 'PENDING';
|
|
183
|
+
const instancePort = app.attributes?.instancePort || SETTINGS.defaultInstancePort || '80';
|
|
184
|
+
const baseIpAddress = currentInstance.placement?.containerIp || currentInstance?.placement?.host;
|
|
185
|
+
|
|
186
|
+
if (isLoading) {
|
|
187
|
+
return (
|
|
188
|
+
<InstanceDetailsPane>
|
|
189
|
+
<div className="horizontal center middle">
|
|
190
|
+
<Spinner size="small" />
|
|
191
|
+
</div>
|
|
192
|
+
</InstanceDetailsPane>
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (!currentInstance?.id) {
|
|
197
|
+
return (
|
|
198
|
+
<div className="details-panel">
|
|
199
|
+
<div className="header">
|
|
200
|
+
<InstanceDetailsPane>
|
|
201
|
+
<div className="header-text horizontal middle">
|
|
202
|
+
<h3 className="horizontal middle space-between flex-1">{instance.instanceId}</h3>
|
|
203
|
+
</div>
|
|
204
|
+
</InstanceDetailsPane>
|
|
205
|
+
</div>
|
|
206
|
+
<div className="content">
|
|
207
|
+
<div className="content-section">
|
|
208
|
+
<div className="content-body text-center">
|
|
209
|
+
<h3>Instance not found.</h3>
|
|
210
|
+
</div>
|
|
211
|
+
</div>
|
|
212
|
+
</div>
|
|
213
|
+
</div>
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return (
|
|
218
|
+
<OverridableTitusInstanceDetailsContent
|
|
219
|
+
account={currentAccount}
|
|
220
|
+
actions={taskActions}
|
|
221
|
+
app={app}
|
|
222
|
+
baseIpAddress={baseIpAddress}
|
|
223
|
+
environment={environment}
|
|
224
|
+
healthMetrics={healthMetrics}
|
|
225
|
+
instance={currentInstance as ITitusInstance}
|
|
226
|
+
instanceId={instance.instanceId}
|
|
227
|
+
instancePort={instancePort}
|
|
228
|
+
moniker={moniker}
|
|
229
|
+
loading={isLoading}
|
|
230
|
+
serverGroup={serverGroup}
|
|
231
|
+
region={region}
|
|
232
|
+
/>
|
|
233
|
+
);
|
|
234
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
CollapsibleSection,
|
|
4
|
+
CopyToClipboard,
|
|
5
|
+
LabeledValue,
|
|
6
|
+
LabeledValueList,
|
|
7
|
+
LinkWithClipboard,
|
|
8
|
+
} from '@spinnaker/core';
|
|
9
|
+
|
|
10
|
+
export interface ITitusInstanceDnsProps {
|
|
11
|
+
containerIp: string;
|
|
12
|
+
host: string;
|
|
13
|
+
instancePort: string;
|
|
14
|
+
ipv6Address: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const TitusInstanceDns = ({ containerIp, host, instancePort, ipv6Address }: ITitusInstanceDnsProps) => (
|
|
18
|
+
<CollapsibleSection heading="DNS" defaultExpanded={true}>
|
|
19
|
+
<LabeledValueList className="dl-horizontal dl-narrow">
|
|
20
|
+
{containerIp && (
|
|
21
|
+
<LabeledValue
|
|
22
|
+
label="Container IP"
|
|
23
|
+
value={
|
|
24
|
+
<>
|
|
25
|
+
{containerIp}
|
|
26
|
+
<CopyToClipboard text={containerIp} toolTip="Copy container IP to clipboard" />
|
|
27
|
+
</>
|
|
28
|
+
}
|
|
29
|
+
/>
|
|
30
|
+
)}
|
|
31
|
+
{ipv6Address && (
|
|
32
|
+
<LabeledValue
|
|
33
|
+
label="Container IPv6"
|
|
34
|
+
value={<LinkWithClipboard text={ipv6Address} url={`http://${ipv6Address}:${instancePort}`} />}
|
|
35
|
+
/>
|
|
36
|
+
)}
|
|
37
|
+
<LabeledValue label="Host IP" value={host} />
|
|
38
|
+
</LabeledValueList>
|
|
39
|
+
</CollapsibleSection>
|
|
40
|
+
);
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { InstanceInformation } from '@spinnaker/amazon';
|
|
4
|
+
import { CollapsibleSection, LabeledValue, LinkWithClipboard } from '@spinnaker/core';
|
|
5
|
+
|
|
6
|
+
import type { ITitusInstance } from '../../domain';
|
|
7
|
+
|
|
8
|
+
export interface ITitusInstanceInformationProps {
|
|
9
|
+
instance: ITitusInstance;
|
|
10
|
+
titusUiEndpoint: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const TitusInstanceInformation = ({ instance, titusUiEndpoint }: ITitusInstanceInformationProps) => {
|
|
14
|
+
const { id, jobId } = instance;
|
|
15
|
+
return (
|
|
16
|
+
<CollapsibleSection heading="Instance Information" defaultExpanded={true}>
|
|
17
|
+
<dl className="dl-horizontal dl-narrow">
|
|
18
|
+
<InstanceInformation
|
|
19
|
+
account={instance.account}
|
|
20
|
+
availabilityZone={instance.availabilityZone}
|
|
21
|
+
instanceType={instance.instanceType}
|
|
22
|
+
launchTime={instance.launchTime}
|
|
23
|
+
provider={instance.provider}
|
|
24
|
+
region={instance.region}
|
|
25
|
+
serverGroup={instance.serverGroup}
|
|
26
|
+
/>
|
|
27
|
+
<LabeledValue
|
|
28
|
+
label="Job Id"
|
|
29
|
+
value={
|
|
30
|
+
<a href={`${titusUiEndpoint}jobs/${jobId}`} target="_blank">
|
|
31
|
+
{jobId}
|
|
32
|
+
</a>
|
|
33
|
+
}
|
|
34
|
+
/>
|
|
35
|
+
<LabeledValue
|
|
36
|
+
label="Instance Id"
|
|
37
|
+
value={<LinkWithClipboard text={id} url={`${titusUiEndpoint}jobs/${jobId}/tasks/${id}`} />}
|
|
38
|
+
/>
|
|
39
|
+
</dl>
|
|
40
|
+
</CollapsibleSection>
|
|
41
|
+
);
|
|
42
|
+
};
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
IAmazonApplicationLoadBalancer,
|
|
3
|
+
IAmazonHealth,
|
|
4
|
+
IAmazonTargetGroupHealth,
|
|
5
|
+
ITargetGroup,
|
|
6
|
+
} from '@spinnaker/amazon';
|
|
7
|
+
import type { Application } from '@spinnaker/core';
|
|
8
|
+
import { mockHealth, mockInstance, mockLoadBalancer, mockLoadBalancerHealth } from '@spinnaker/mocks';
|
|
9
|
+
import {
|
|
10
|
+
applyTargetGroupInfoToHealthMetric,
|
|
11
|
+
buildTaskActions,
|
|
12
|
+
extractHealthMetrics,
|
|
13
|
+
} from './titusInstanceDetailsUtils';
|
|
14
|
+
|
|
15
|
+
const targetGroup1 = {
|
|
16
|
+
account: 'test',
|
|
17
|
+
name: 'tg1',
|
|
18
|
+
healthCheckPort: '8080',
|
|
19
|
+
healthCheckProtocol: 'https',
|
|
20
|
+
healthCheckPath: '/healthcheck',
|
|
21
|
+
};
|
|
22
|
+
const targetGroup2 = {
|
|
23
|
+
...targetGroup1,
|
|
24
|
+
name: 'tg2',
|
|
25
|
+
port: '7001',
|
|
26
|
+
healthCheckPort: 'traffic-port',
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const metricTg1 = {
|
|
30
|
+
instanceId: '100.000.000.00',
|
|
31
|
+
name: 'tg1',
|
|
32
|
+
targetGroupName: 'tg1',
|
|
33
|
+
healthState: 'Up',
|
|
34
|
+
state: 'healthy',
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const metricTg2 = {
|
|
38
|
+
...metricTg1,
|
|
39
|
+
name: 'test-tg',
|
|
40
|
+
targetGroupName: 'test-tg',
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const metricTg3 = {
|
|
44
|
+
...metricTg1,
|
|
45
|
+
name: 'tg2',
|
|
46
|
+
targetGroupName: 'tg2',
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const tgHealth = {
|
|
50
|
+
state: 'Up',
|
|
51
|
+
targetGroups: [metricTg1, metricTg2],
|
|
52
|
+
type: 'TargetGroup',
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
describe('applyTargetGroupInfoToHealthMetric', () => {
|
|
56
|
+
const metricGroups = [metricTg1, metricTg2, metricTg3] as IAmazonTargetGroupHealth[];
|
|
57
|
+
const targetGroups = [targetGroup1, targetGroup2] as ITargetGroup[];
|
|
58
|
+
|
|
59
|
+
it('should apply healthcheck info to health metrics', () => {
|
|
60
|
+
const [result1, result2, result3] = applyTargetGroupInfoToHealthMetric(metricGroups, targetGroups, 'test');
|
|
61
|
+
|
|
62
|
+
// Uses given healthcheck port
|
|
63
|
+
expect(result1.healthCheckPath).toEqual(':8080/healthcheck');
|
|
64
|
+
expect(result1.healthCheckProtocol).toEqual('https');
|
|
65
|
+
|
|
66
|
+
// Target group is not found
|
|
67
|
+
expect(result2.healthCheckPath).toBeUndefined();
|
|
68
|
+
expect(result2.healthCheckProtocol).toBeUndefined();
|
|
69
|
+
|
|
70
|
+
// Uses traffic port
|
|
71
|
+
expect(result3.healthCheckPath).toEqual(':7001/healthcheck');
|
|
72
|
+
expect(result3.healthCheckProtocol).toEqual('https');
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
describe('extractHealthMetrics', () => {
|
|
77
|
+
it('should extract unknown health states', () => {
|
|
78
|
+
const lb = { ...mockLoadBalancer, targetGroups: [targetGroup1] } as IAmazonApplicationLoadBalancer;
|
|
79
|
+
const health1 = [mockHealth, mockLoadBalancerHealth, { ...mockHealth, state: 'Unknown' }] as IAmazonHealth[];
|
|
80
|
+
const health2 = [mockHealth, mockLoadBalancerHealth] as IAmazonHealth[];
|
|
81
|
+
|
|
82
|
+
const result1 = extractHealthMetrics(health1, [lb], 'test');
|
|
83
|
+
expect(result1.length).toEqual(2);
|
|
84
|
+
|
|
85
|
+
const result2 = extractHealthMetrics(health2, [lb], 'test');
|
|
86
|
+
expect(result2.length).toEqual(2);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('should supplement TargetGroup health info', () => {
|
|
90
|
+
const lb = { ...mockLoadBalancer, targetGroups: [targetGroup1, targetGroup2] } as IAmazonApplicationLoadBalancer;
|
|
91
|
+
|
|
92
|
+
const health = [mockHealth, tgHealth] as IAmazonHealth[];
|
|
93
|
+
|
|
94
|
+
const result = extractHealthMetrics(health, [lb], 'test');
|
|
95
|
+
expect(result.length).toEqual(2);
|
|
96
|
+
|
|
97
|
+
const tgs = result[1].targetGroups;
|
|
98
|
+
expect(tgs[0].healthCheckPath).toEqual(':8080/healthcheck');
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe('buildTaskActions', () => {
|
|
103
|
+
it('should render required actions', () => {
|
|
104
|
+
// Instance has Discovery health
|
|
105
|
+
const actions1 = buildTaskActions(mockInstance, {} as Application);
|
|
106
|
+
expect(actions1.length).toEqual(3);
|
|
107
|
+
expect(actions1[2].label).toEqual('Disable in Discovery');
|
|
108
|
+
|
|
109
|
+
const actions2 = buildTaskActions(
|
|
110
|
+
{ ...mockInstance, health: [{ ...mockHealth, state: 'OutOfService' }] },
|
|
111
|
+
{} as Application,
|
|
112
|
+
);
|
|
113
|
+
expect(actions2.length).toEqual(3);
|
|
114
|
+
expect(actions2[2].label).toEqual('Enable in Discovery');
|
|
115
|
+
|
|
116
|
+
// Instance does not have Discovery health
|
|
117
|
+
const actions3 = buildTaskActions({ ...mockInstance, health: [tgHealth as IAmazonHealth] }, {} as Application);
|
|
118
|
+
expect(actions3.length).toEqual(2);
|
|
119
|
+
|
|
120
|
+
// Instance has no health
|
|
121
|
+
const actions4 = buildTaskActions({ ...mockInstance, health: [] }, {} as Application);
|
|
122
|
+
expect(actions4.length).toEqual(2);
|
|
123
|
+
});
|
|
124
|
+
});
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
IAmazonApplicationLoadBalancer,
|
|
3
|
+
IAmazonHealth,
|
|
4
|
+
IAmazonNetworkLoadBalancer,
|
|
5
|
+
IAmazonTargetGroupHealth,
|
|
6
|
+
ITargetGroup,
|
|
7
|
+
} from '@spinnaker/amazon';
|
|
8
|
+
import { getAllTargetGroups } from '@spinnaker/amazon';
|
|
9
|
+
import type { Action, Application, IInstance, IJob } from '@spinnaker/core';
|
|
10
|
+
import { ConfirmationModalService, InstanceWriter, ReactInjector } from '@spinnaker/core';
|
|
11
|
+
|
|
12
|
+
export const applyTargetGroupInfoToHealthMetric = (
|
|
13
|
+
metricGroups: IAmazonTargetGroupHealth[],
|
|
14
|
+
targetGroups: ITargetGroup[],
|
|
15
|
+
account: string,
|
|
16
|
+
) => {
|
|
17
|
+
return metricGroups.map((tg) => {
|
|
18
|
+
const group = targetGroups.find(
|
|
19
|
+
(g) => (g.name === tg.name || g.name === tg.targetGroupName) && g.account === account,
|
|
20
|
+
);
|
|
21
|
+
const useTrafficPort = group?.healthCheckPort === 'traffic-port' || !group?.healthCheckPort;
|
|
22
|
+
return {
|
|
23
|
+
...tg,
|
|
24
|
+
name: group?.name,
|
|
25
|
+
healthCheckPath: group
|
|
26
|
+
? `:${useTrafficPort ? group?.port : group.healthCheckPort}${group?.healthCheckPath || ''}`
|
|
27
|
+
: undefined,
|
|
28
|
+
healthCheckProtocol: group?.healthCheckProtocol?.toLowerCase(),
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const extractHealthMetrics = (
|
|
34
|
+
health: IAmazonHealth[],
|
|
35
|
+
loadBalancers: IAmazonApplicationLoadBalancer[] | IAmazonNetworkLoadBalancer[],
|
|
36
|
+
account: string,
|
|
37
|
+
): IAmazonHealth[] => {
|
|
38
|
+
const displayableMetrics = (health || []).filter((m) => m.state !== 'Unknown');
|
|
39
|
+
const allTargetGroups = getAllTargetGroups(loadBalancers);
|
|
40
|
+
|
|
41
|
+
return displayableMetrics.map((metric) => {
|
|
42
|
+
if (metric.type === 'TargetGroup') {
|
|
43
|
+
const augmentedGroups = applyTargetGroupInfoToHealthMetric(metric.targetGroups, allTargetGroups, account);
|
|
44
|
+
return { ...metric, targetGroups: augmentedGroups } as IAmazonHealth;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return metric;
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const terminateInstance = (instance: IInstance, app: Application) => {
|
|
52
|
+
return () => {
|
|
53
|
+
const taskMonitorConfig = {
|
|
54
|
+
application: app,
|
|
55
|
+
title: `Terminating ${instance.id}`,
|
|
56
|
+
onTaskComplete: () => {
|
|
57
|
+
if (ReactInjector.$state.includes('**.instanceDetails', { id: instance.id })) {
|
|
58
|
+
ReactInjector.$state.go('^');
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const submitMethod = () => {
|
|
64
|
+
const params: IJob = { cloudProvider: 'titus' };
|
|
65
|
+
if (instance.serverGroup) {
|
|
66
|
+
params.serverGroupName = instance.serverGroup;
|
|
67
|
+
}
|
|
68
|
+
return InstanceWriter.terminateInstance(instance, app, params);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
ConfirmationModalService.confirm({
|
|
72
|
+
header: `Really terminate ${instance.id}?`,
|
|
73
|
+
buttonText: `Terminate ${instance.id}`,
|
|
74
|
+
account: instance.account,
|
|
75
|
+
taskMonitorConfig,
|
|
76
|
+
submitMethod,
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const terminateInstanceAndShrinkServerGroup = (instance: IInstance, app: Application) => {
|
|
82
|
+
return () => {
|
|
83
|
+
const taskMonitorConfig = {
|
|
84
|
+
application: app,
|
|
85
|
+
title: `Terminating ${instance.id} and shrinking server group`,
|
|
86
|
+
onTaskComplete: () => {
|
|
87
|
+
if (ReactInjector.$state.includes('**.instanceDetails', { instanceId: instance.id })) {
|
|
88
|
+
ReactInjector.$state.go('^');
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const submitMethod = () => {
|
|
94
|
+
return InstanceWriter.terminateInstancesAndShrinkServerGroups(
|
|
95
|
+
[
|
|
96
|
+
{
|
|
97
|
+
cloudProvider: instance.cloudProvider,
|
|
98
|
+
instanceIds: [instance.id],
|
|
99
|
+
account: instance.account,
|
|
100
|
+
region: instance.region,
|
|
101
|
+
serverGroup: instance.serverGroup,
|
|
102
|
+
instances: [instance],
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
app,
|
|
106
|
+
);
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
ConfirmationModalService.confirm({
|
|
110
|
+
header: `Really terminate ${instance.id} and shrink ${instance.serverGroup}?`,
|
|
111
|
+
buttonText: `Terminate ${instance.id} and shrink ${instance.serverGroup}`,
|
|
112
|
+
account: instance.account,
|
|
113
|
+
taskMonitorConfig,
|
|
114
|
+
submitMethod,
|
|
115
|
+
});
|
|
116
|
+
};
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const enableInstanceInDiscovery = (instance: IInstance, app: Application) => {
|
|
120
|
+
return () => {
|
|
121
|
+
const taskMonitorConfig = {
|
|
122
|
+
application: app,
|
|
123
|
+
title: `Enabling ${instance.id} in discovery`,
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const submitMethod = () => InstanceWriter.enableInstanceInDiscovery(instance, app);
|
|
127
|
+
|
|
128
|
+
ConfirmationModalService.confirm({
|
|
129
|
+
header: `Really enable ${instance.id} in discovery?`,
|
|
130
|
+
buttonText: `Enable ${instance.id}`,
|
|
131
|
+
account: instance.account,
|
|
132
|
+
taskMonitorConfig,
|
|
133
|
+
submitMethod,
|
|
134
|
+
});
|
|
135
|
+
};
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const disableInstanceInDiscovery = (instance: IInstance, app: Application) => {
|
|
139
|
+
return () => {
|
|
140
|
+
const taskMonitorConfig = {
|
|
141
|
+
application: app,
|
|
142
|
+
title: `Disabling ${instance.id} in discovery`,
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const submitMethod = () => InstanceWriter.disableInstanceInDiscovery(instance, app);
|
|
146
|
+
|
|
147
|
+
ConfirmationModalService.confirm({
|
|
148
|
+
header: `Really disable ${instance.id} in discovery?`,
|
|
149
|
+
buttonText: `Disable ${instance.id}`,
|
|
150
|
+
account: instance.account,
|
|
151
|
+
taskMonitorConfig,
|
|
152
|
+
submitMethod,
|
|
153
|
+
});
|
|
154
|
+
};
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
export const buildTaskActions = (instance: IInstance, app: Application): Action[] => {
|
|
158
|
+
const taskActions = [
|
|
159
|
+
{ label: 'Terminate', triggerAction: terminateInstance(instance, app) },
|
|
160
|
+
{ label: 'Terminate and Shrink Server Group', triggerAction: terminateInstanceAndShrinkServerGroup(instance, app) },
|
|
161
|
+
];
|
|
162
|
+
|
|
163
|
+
const discoveryHealth = (instance.health || []).filter((h) => h.type === 'Discovery');
|
|
164
|
+
|
|
165
|
+
if (discoveryHealth.length && discoveryHealth[0].state === 'OutOfService') {
|
|
166
|
+
taskActions.push({
|
|
167
|
+
label: 'Enable in Discovery',
|
|
168
|
+
triggerAction: enableInstanceInDiscovery(instance, app),
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const hasHealthState = (discoveryHealth || []).some((h) => h.state === 'Up' || h.state === 'Down');
|
|
173
|
+
if (hasHealthState) {
|
|
174
|
+
taskActions.push({
|
|
175
|
+
label: 'Disable in Discovery',
|
|
176
|
+
triggerAction: disableInstanceInDiscovery(instance, app),
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return taskActions;
|
|
181
|
+
};
|
|
Binary file
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
2
|
+
<svg width="47px" height="40px" viewBox="0 0 47 40" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
3
|
+
<g transform="translate(1.000000, 1.000000)">
|
|
4
|
+
<path d="M30.8746,26.4746 C27.6746,26.4746 25.0746,23.8746 25.0746,20.6746 C25.0746,17.4746 27.6746,14.8746 30.8746,14.8746 C34.0746,14.8746 36.6746,17.4746 36.6746,20.6746 C36.5746,23.8746 34.0746,26.4746 30.8746,26.4746 M14.2746,26.4746 C11.0746,26.4746 8.4746,23.8746 8.4746,20.6746 C8.4746,17.4746 11.0746,14.8746 14.2746,14.8746 C17.4746,14.8746 20.0746,17.4746 20.0746,20.6746 C20.0746,23.8746 17.4746,26.4746 14.2746,26.4746 M38.6746,18.0746 L38.6746,2.1746 L37.5746,2.1746 L37.5746,7.5746 L34.8746,7.5746 C32.4746,3.1746 27.8746,0.1746 22.5746,0.1746 C17.2746,0.1746 12.6746,3.1746 10.2746,7.5746 L7.0746,7.5746 L7.0746,2.1746 L5.9746,2.1746 L5.9746,17.9746 C2.7746,17.9746 0.1746,20.5746 0.1746,23.7746 C0.1746,26.9746 2.7746,29.5746 5.9746,29.5746 C6.1746,29.5746 6.3746,29.4746 6.4746,29.4746 L6.4746,37.6746 L38.4746,37.6746 L38.4746,29.5746 C41.6746,29.5746 44.2746,26.9746 44.2746,23.7746 C44.3746,20.5746 41.7746,18.0746 38.6746,18.0746" id="Fill-1" fill="#000000"></path>
|
|
5
|
+
<path d="M30.8746,26.4746 C27.6746,26.4746 25.0746,23.8746 25.0746,20.6746 C25.0746,17.4746 27.6746,14.8746 30.8746,14.8746 C34.0746,14.8746 36.6746,17.4746 36.6746,20.6746 C36.5746,23.8746 34.0746,26.4746 30.8746,26.4746 L30.8746,26.4746 Z M14.2746,26.4746 C11.0746,26.4746 8.4746,23.8746 8.4746,20.6746 C8.4746,17.4746 11.0746,14.8746 14.2746,14.8746 C17.4746,14.8746 20.0746,17.4746 20.0746,20.6746 C20.0746,23.8746 17.4746,26.4746 14.2746,26.4746 L14.2746,26.4746 Z M38.6746,18.0746 L38.6746,2.1746 L37.5746,2.1746 L37.5746,7.5746 L34.8746,7.5746 C32.4746,3.1746 27.8746,0.1746 22.5746,0.1746 C17.2746,0.1746 12.6746,3.1746 10.2746,7.5746 L7.0746,7.5746 L7.0746,2.1746 L5.9746,2.1746 L5.9746,17.9746 C2.7746,17.9746 0.1746,20.5746 0.1746,23.7746 C0.1746,26.9746 2.7746,29.5746 5.9746,29.5746 C6.1746,29.5746 6.3746,29.4746 6.4746,29.4746 L6.4746,37.6746 L38.4746,37.6746 L38.4746,29.5746 C41.6746,29.5746 44.2746,26.9746 44.2746,23.7746 C44.3746,20.5746 41.7746,18.0746 38.6746,18.0746 L38.6746,18.0746 Z" id="Stroke-3" stroke="#000000" stroke-width="2.349"></path>
|
|
6
|
+
</g>
|
|
7
|
+
</svg>
|