-
Notifications
You must be signed in to change notification settings - Fork 167
/
widget-configuration.tsx
141 lines (125 loc) · 4.46 KB
/
widget-configuration.tsx
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import "./widget-configuration.scss";
import * as React from "react";
import * as SDK from "azure-devops-extension-sdk";
import * as Dashboard from "azure-devops-extension-api/Dashboard";
import { TextField } from "azure-devops-ui/TextField";
import { getPipelineDefinition } from "../widget-catalog/utility";
import { Icon } from "azure-devops-ui/Icon";
import { Checkbox } from "azure-devops-ui/Checkbox";
import { showRootComponent } from "../../Common";
interface ISampleWidgetConfigState {
pipelineId: string;
pipelineErrorMessage?: string;
blink: boolean;
}
class SampleWidgetConfig
extends React.Component<{}, ISampleWidgetConfigState>
implements Dashboard.IWidgetConfiguration
{
private widgetConfigurationContext?: Dashboard.IWidgetConfigurationContext;
private settings: ISampleWidgetSettings = {} as ISampleWidgetSettings;
componentDidMount() {
SDK.init().then(() => {
SDK.register("sample-widget.config", this);
SDK.resize(400, 200);
});
}
render(): JSX.Element {
return (
this.state && (
<div className="content">
<div className="config-field">
<label className="config-field-title">Pipeline ID</label>
<TextField
value={this.state.pipelineId}
onChange={(_e, newValue) => {
this.updateSettingsAndNotify({ pipelineId: +newValue });
this.setState({ pipelineId: newValue });
}}
/>
{this.state.pipelineErrorMessage && (
<div className="error-message">
<Icon className="error-icon" iconName="Error" />
{this.state.pipelineErrorMessage}
</div>
)}
</div>
<div className="config-field">
<Checkbox
label="Blink"
checked={this.state.blink}
onChange={(_e, newValue) => {
this.updateSettingsAndNotify({ blink: newValue });
this.setState({ blink: newValue });
}}
/>
</div>
</div>
)
);
}
// Called in 'onChange' handlers when any field is updated.
private async updateSettingsAndNotify(
partialSettings: Partial<ISampleWidgetSettings>
) {
this.settings = { ...this.settings, ...partialSettings };
// lights up the Save button, and tells the widget about live updates.
const customSettings = this.serializeWidgetSettings(this.settings);
await this.widgetConfigurationContext?.notify(
Dashboard.ConfigurationEvent.ConfigurationChange,
Dashboard.ConfigurationEvent.Args(customSettings)
);
}
private serializeWidgetSettings(
settings: ISampleWidgetSettings
): Dashboard.CustomSettings {
return {
data: JSON.stringify(settings),
version: { major: 1, minor: 0, patch: 0 },
};
}
private async setStateFromWidgetSettings(
widgetSettings: Dashboard.WidgetSettings
) {
const deserialized: ISampleWidgetSettings | null = JSON.parse(
widgetSettings.customSettings.data
);
if (deserialized) {
this.settings = deserialized;
}
this.setState({
pipelineId: deserialized?.pipelineId.toString() ?? "",
blink: deserialized?.blink ?? false,
});
}
private async validateSettings(): Promise<boolean> {
let pipelineIdIsValid = false;
try {
const pipelineDef = await getPipelineDefinition(this.settings.pipelineId);
pipelineIdIsValid = !!this.settings.pipelineId && !!pipelineDef;
} catch {}
this.setState({
pipelineErrorMessage: pipelineIdIsValid
? ""
: "A valid pipeline ID is required",
});
return pipelineIdIsValid;
}
async load(widgetSettings: Dashboard.WidgetSettings, widgetConfigurationContext: Dashboard.IWidgetConfigurationContext ): Promise<Dashboard.WidgetStatus> {
// capture context so we can notify in updateStateAndNotify
this.widgetConfigurationContext = widgetConfigurationContext;
await this.setStateFromWidgetSettings(widgetSettings);
return Dashboard.WidgetStatusHelper.Success();
}
async onSave(): Promise<Dashboard.SaveStatus> {
// ensure new settings values are valid; set error state for the UI at the same time
if (!(await this.validateSettings())) {
return Dashboard.WidgetConfigurationSave.Invalid();
}
// persist new settings
return Dashboard.WidgetConfigurationSave.Valid(
this.serializeWidgetSettings(this.settings)
);
}
}
showRootComponent(<SampleWidgetConfig />);