itsm-widget 1.0.1
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/ANGULAR-INSTALLATION.md +372 -0
- package/API-SERVICE.md +334 -0
- package/INSTALLATION.md +467 -0
- package/README.md +361 -0
- package/dist/assets/icons/add-ticket-icon.png +0 -0
- package/dist/itsm-widget.min.css +1 -0
- package/dist/itsm-widget.min.js +2 -0
- package/dist/itsm-widget.min.js.LICENSE.txt +1 -0
- package/package.json +68 -0
package/INSTALLATION.md
ADDED
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
# Hướng dẫn Cài đặt ITSM Widget
|
|
2
|
+
|
|
3
|
+
ITSM Widget là **standalone JavaScript plugin**, không phụ thuộc vào framework nào. Có thể tích hợp vào:
|
|
4
|
+
|
|
5
|
+
- ✅ **MVC/ASP.NET** (.NET Framework, .NET Core)
|
|
6
|
+
- ✅ **Angular** (bất kỳ version nào)
|
|
7
|
+
- ✅ **React** (bất kỳ version nào)
|
|
8
|
+
- ✅ **Vue.js** (bất kỳ version nào)
|
|
9
|
+
- ✅ **Vanilla HTML/JavaScript**
|
|
10
|
+
- ✅ **Blazor** (.NET)
|
|
11
|
+
- ✅ **JSP/Servlet** (Java)
|
|
12
|
+
- ✅ **PHP**
|
|
13
|
+
- ✅ Bất kỳ web project nào
|
|
14
|
+
|
|
15
|
+
## 📦 Cài đặt
|
|
16
|
+
|
|
17
|
+
### Bước 1: Build Widget
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install
|
|
21
|
+
npm run build
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Sau khi build, bạn sẽ có 2 file trong thư mục `dist/`:
|
|
25
|
+
- `itsm-widget.min.js` - JavaScript file (minified)
|
|
26
|
+
- `itsm-widget.min.css` - CSS file (minified)
|
|
27
|
+
|
|
28
|
+
### Bước 2: Copy files vào project của bạn
|
|
29
|
+
|
|
30
|
+
Copy 2 file trên vào project của bạn (thường là trong `wwwroot`, `assets`, `public`, `static`, v.v.)
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 🔧 Tích hợp vào các Platform
|
|
35
|
+
|
|
36
|
+
### 1. MVC / ASP.NET
|
|
37
|
+
|
|
38
|
+
#### ASP.NET Core MVC
|
|
39
|
+
|
|
40
|
+
**1. Copy files vào `wwwroot/lib/itsm-widget/`:**
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
wwwroot/
|
|
44
|
+
lib/
|
|
45
|
+
itsm-widget/
|
|
46
|
+
itsm-widget.min.js
|
|
47
|
+
itsm-widget.min.css
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**2. Thêm vào `_Layout.cshtml` hoặc `_ViewImports.cshtml`:**
|
|
51
|
+
|
|
52
|
+
```html
|
|
53
|
+
<!-- Trong <head> -->
|
|
54
|
+
<link rel="stylesheet" href="~/lib/itsm-widget/itsm-widget.min.css">
|
|
55
|
+
|
|
56
|
+
<!-- Trước </body> -->
|
|
57
|
+
<script src="~/lib/itsm-widget/itsm-widget.min.js"></script>
|
|
58
|
+
<script>
|
|
59
|
+
// Khởi tạo widget khi page load
|
|
60
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
61
|
+
const widget = new ITSMWidget({
|
|
62
|
+
apiBaseUrl: '@Configuration["ITSM:ApiBaseUrl"]',
|
|
63
|
+
apiKey: '@Configuration["ITSM:ApiKey"]',
|
|
64
|
+
tenant: '@Configuration["ITSM:Tenant"]',
|
|
65
|
+
iconColor: '#007bff',
|
|
66
|
+
requesterName: '@User.Identity.Name', // Optional
|
|
67
|
+
site: '@Configuration["ITSM:Site"]', // Optional
|
|
68
|
+
onSuccess: function(response) {
|
|
69
|
+
console.log('Request submitted:', response);
|
|
70
|
+
// Có thể hiển thị notification tại đây
|
|
71
|
+
alert('Yêu cầu đã được gửi thành công! ID: ' + response.request.id);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Lưu instance để cleanup sau này
|
|
76
|
+
window.itsmWidgetInstance = widget;
|
|
77
|
+
});
|
|
78
|
+
</script>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**3. Thêm config vào `appsettings.json`:**
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
{
|
|
85
|
+
"ITSM": {
|
|
86
|
+
"ApiBaseUrl": "https://your-api-domain.com",
|
|
87
|
+
"ApiKey": "your-api-key",
|
|
88
|
+
"Tenant": "your-tenant-name",
|
|
89
|
+
"Site": "Your Site Name"
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
#### ASP.NET Framework MVC
|
|
95
|
+
|
|
96
|
+
**1. Copy files vào `Content/js/` và `Content/css/`:**
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
Content/
|
|
100
|
+
css/
|
|
101
|
+
itsm-widget.min.css
|
|
102
|
+
js/
|
|
103
|
+
itsm-widget.min.js
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**2. Thêm vào `_Layout.cshtml`:**
|
|
107
|
+
|
|
108
|
+
```html
|
|
109
|
+
@Styles.Render("~/Content/css/itsm-widget.min.css")
|
|
110
|
+
@Scripts.Render("~/Content/js/itsm-widget.min.js")
|
|
111
|
+
<script>
|
|
112
|
+
$(document).ready(function() {
|
|
113
|
+
var widget = new ITSMWidget({
|
|
114
|
+
apiBaseUrl: '@ConfigurationManager.AppSettings["ITSM:ApiBaseUrl"]',
|
|
115
|
+
apiKey: '@ConfigurationManager.AppSettings["ITSM:ApiKey"]',
|
|
116
|
+
tenant: '@ConfigurationManager.AppSettings["ITSM:Tenant"]',
|
|
117
|
+
onSuccess: function(response) {
|
|
118
|
+
alert('Yêu cầu đã được gửi thành công!');
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
</script>
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**3. Thêm config vào `Web.config`:**
|
|
126
|
+
|
|
127
|
+
```xml
|
|
128
|
+
<appSettings>
|
|
129
|
+
<add key="ITSM:ApiBaseUrl" value="https://your-api-domain.com" />
|
|
130
|
+
<add key="ITSM:ApiKey" value="your-api-key" />
|
|
131
|
+
<add key="ITSM:Tenant" value="your-tenant-name" />
|
|
132
|
+
<add key="ITSM:Site" value="Your Site Name" />
|
|
133
|
+
</appSettings>
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
### 2. Angular (bất kỳ version)
|
|
139
|
+
|
|
140
|
+
Xem README.md phần "Cách 2: Sử dụng với Angular 10"
|
|
141
|
+
|
|
142
|
+
**Tóm tắt:**
|
|
143
|
+
1. Copy files vào `src/assets/`
|
|
144
|
+
2. Thêm vào `angular.json`:
|
|
145
|
+
```json
|
|
146
|
+
"scripts": ["src/assets/itsm-widget.min.js"],
|
|
147
|
+
"styles": ["src/assets/itsm-widget.min.css"]
|
|
148
|
+
```
|
|
149
|
+
3. Khởi tạo trong component:
|
|
150
|
+
```typescript
|
|
151
|
+
declare var ITSMWidget: any;
|
|
152
|
+
|
|
153
|
+
ngOnInit() {
|
|
154
|
+
const widget = new ITSMWidget({...});
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
### 3. React
|
|
161
|
+
|
|
162
|
+
**1. Copy files vào `public/`:**
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
public/
|
|
166
|
+
js/
|
|
167
|
+
itsm-widget.min.js
|
|
168
|
+
css/
|
|
169
|
+
itsm-widget.min.css
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**2. Thêm vào `public/index.html`:**
|
|
173
|
+
|
|
174
|
+
```html
|
|
175
|
+
<link rel="stylesheet" href="%PUBLIC_URL%/css/itsm-widget.min.css">
|
|
176
|
+
<script src="%PUBLIC_URL%/js/itsm-widget.min.js"></script>
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**3. Khởi tạo trong component (ví dụ: `App.js`):**
|
|
180
|
+
|
|
181
|
+
```javascript
|
|
182
|
+
import { useEffect } from 'react';
|
|
183
|
+
|
|
184
|
+
function App() {
|
|
185
|
+
useEffect(() => {
|
|
186
|
+
if (window.ITSMWidget) {
|
|
187
|
+
const widget = new window.ITSMWidget({
|
|
188
|
+
apiBaseUrl: process.env.REACT_APP_ITSM_API_URL,
|
|
189
|
+
apiKey: process.env.REACT_APP_ITSM_API_KEY,
|
|
190
|
+
tenant: process.env.REACT_APP_ITSM_TENANT,
|
|
191
|
+
onSuccess: (response) => {
|
|
192
|
+
console.log('Request submitted:', response);
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
window.itsmWidgetInstance = widget;
|
|
197
|
+
|
|
198
|
+
return () => {
|
|
199
|
+
// Cleanup khi component unmount
|
|
200
|
+
if (window.itsmWidgetInstance) {
|
|
201
|
+
window.itsmWidgetInstance.destroy();
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
}, []);
|
|
206
|
+
|
|
207
|
+
return (
|
|
208
|
+
<div className="App">
|
|
209
|
+
{/* Your app content */}
|
|
210
|
+
</div>
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export default App;
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**4. Thêm vào `.env`:**
|
|
218
|
+
|
|
219
|
+
```
|
|
220
|
+
REACT_APP_ITSM_API_URL=https://your-api-domain.com
|
|
221
|
+
REACT_APP_ITSM_API_KEY=your-api-key
|
|
222
|
+
REACT_APP_ITSM_TENANT=your-tenant-name
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
### 4. Vue.js
|
|
228
|
+
|
|
229
|
+
**1. Copy files vào `public/`:**
|
|
230
|
+
|
|
231
|
+
```
|
|
232
|
+
public/
|
|
233
|
+
js/
|
|
234
|
+
itsm-widget.min.js
|
|
235
|
+
css/
|
|
236
|
+
itsm-widget.min.css
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
**2. Thêm vào `public/index.html`:**
|
|
240
|
+
|
|
241
|
+
```html
|
|
242
|
+
<link rel="stylesheet" href="<%= BASE_URL %>css/itsm-widget.min.css">
|
|
243
|
+
<script src="<%= BASE_URL %>js/itsm-widget.min.js"></script>
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
**3. Khởi tạo trong `main.js` hoặc component:**
|
|
247
|
+
|
|
248
|
+
```javascript
|
|
249
|
+
// main.js
|
|
250
|
+
import { createApp } from 'vue';
|
|
251
|
+
|
|
252
|
+
const app = createApp(App);
|
|
253
|
+
|
|
254
|
+
// Khởi tạo widget sau khi app mount
|
|
255
|
+
app.mount('#app');
|
|
256
|
+
|
|
257
|
+
if (window.ITSMWidget) {
|
|
258
|
+
const widget = new window.ITSMWidget({
|
|
259
|
+
apiBaseUrl: process.env.VUE_APP_ITSM_API_URL,
|
|
260
|
+
apiKey: process.env.VUE_APP_ITSM_API_KEY,
|
|
261
|
+
tenant: process.env.VUE_APP_ITSM_TENANT,
|
|
262
|
+
onSuccess: (response) => {
|
|
263
|
+
console.log('Request submitted:', response);
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
window.itsmWidgetInstance = widget;
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
### 5. Vanilla HTML/JavaScript
|
|
274
|
+
|
|
275
|
+
**1. Copy files vào project:**
|
|
276
|
+
|
|
277
|
+
```
|
|
278
|
+
project/
|
|
279
|
+
css/
|
|
280
|
+
itsm-widget.min.css
|
|
281
|
+
js/
|
|
282
|
+
itsm-widget.min.js
|
|
283
|
+
index.html
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
**2. Thêm vào `index.html`:**
|
|
287
|
+
|
|
288
|
+
```html
|
|
289
|
+
<!DOCTYPE html>
|
|
290
|
+
<html lang="vi">
|
|
291
|
+
<head>
|
|
292
|
+
<meta charset="UTF-8">
|
|
293
|
+
<title>My App</title>
|
|
294
|
+
<link rel="stylesheet" href="css/itsm-widget.min.css">
|
|
295
|
+
</head>
|
|
296
|
+
<body>
|
|
297
|
+
<!-- Your content -->
|
|
298
|
+
|
|
299
|
+
<script src="js/itsm-widget.min.js"></script>
|
|
300
|
+
<script>
|
|
301
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
302
|
+
const widget = new ITSMWidget({
|
|
303
|
+
apiBaseUrl: 'https://your-api-domain.com',
|
|
304
|
+
apiKey: 'your-api-key',
|
|
305
|
+
tenant: 'your-tenant-name',
|
|
306
|
+
iconColor: '#007bff',
|
|
307
|
+
onSuccess: function(response) {
|
|
308
|
+
console.log('Request submitted:', response);
|
|
309
|
+
alert('Yêu cầu đã được gửi thành công!');
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
window.itsmWidgetInstance = widget;
|
|
314
|
+
});
|
|
315
|
+
</script>
|
|
316
|
+
</body>
|
|
317
|
+
</html>
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
### 6. Blazor (.NET)
|
|
323
|
+
|
|
324
|
+
**1. Copy files vào `wwwroot/js/` và `wwwroot/css/`:**
|
|
325
|
+
|
|
326
|
+
```
|
|
327
|
+
wwwroot/
|
|
328
|
+
css/
|
|
329
|
+
itsm-widget.min.css
|
|
330
|
+
js/
|
|
331
|
+
itsm-widget.min.js
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
**2. Thêm vào `Pages/_Host.cshtml` hoặc `App.razor`:**
|
|
335
|
+
|
|
336
|
+
```html
|
|
337
|
+
<link href="css/itsm-widget.min.css" rel="stylesheet" />
|
|
338
|
+
<script src="js/itsm-widget.min.js"></script>
|
|
339
|
+
<script>
|
|
340
|
+
window.initITSMWidget = function(apiBaseUrl, apiKey, tenant) {
|
|
341
|
+
if (window.ITSMWidget) {
|
|
342
|
+
return new window.ITSMWidget({
|
|
343
|
+
apiBaseUrl: apiBaseUrl,
|
|
344
|
+
apiKey: apiKey,
|
|
345
|
+
tenant: tenant,
|
|
346
|
+
onSuccess: function(response) {
|
|
347
|
+
console.log('Request submitted:', response);
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
return null;
|
|
352
|
+
};
|
|
353
|
+
</script>
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
**3. Khởi tạo trong Blazor component:**
|
|
357
|
+
|
|
358
|
+
```csharp
|
|
359
|
+
@inject IJSRuntime JSRuntime
|
|
360
|
+
|
|
361
|
+
@code {
|
|
362
|
+
private IJSObjectReference? widgetInstance;
|
|
363
|
+
|
|
364
|
+
protected override async Task OnAfterRenderAsync(bool firstRender)
|
|
365
|
+
{
|
|
366
|
+
if (firstRender)
|
|
367
|
+
{
|
|
368
|
+
var module = await JSRuntime.InvokeAsync<IJSObjectReference>(
|
|
369
|
+
"initITSMWidget",
|
|
370
|
+
"https://your-api-domain.com",
|
|
371
|
+
"your-api-key",
|
|
372
|
+
"your-tenant-name"
|
|
373
|
+
);
|
|
374
|
+
|
|
375
|
+
widgetInstance = module;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
### 7. PHP
|
|
384
|
+
|
|
385
|
+
**1. Copy files vào project:**
|
|
386
|
+
|
|
387
|
+
```
|
|
388
|
+
project/
|
|
389
|
+
assets/
|
|
390
|
+
css/
|
|
391
|
+
itsm-widget.min.css
|
|
392
|
+
js/
|
|
393
|
+
itsm-widget.min.js
|
|
394
|
+
index.php
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
**2. Thêm vào template PHP:**
|
|
398
|
+
|
|
399
|
+
```php
|
|
400
|
+
<!DOCTYPE html>
|
|
401
|
+
<html lang="vi">
|
|
402
|
+
<head>
|
|
403
|
+
<meta charset="UTF-8">
|
|
404
|
+
<title>My App</title>
|
|
405
|
+
<link rel="stylesheet" href="assets/css/itsm-widget.min.css">
|
|
406
|
+
</head>
|
|
407
|
+
<body>
|
|
408
|
+
<!-- Your content -->
|
|
409
|
+
|
|
410
|
+
<script src="assets/js/itsm-widget.min.js"></script>
|
|
411
|
+
<script>
|
|
412
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
413
|
+
const widget = new ITSMWidget({
|
|
414
|
+
apiBaseUrl: '<?php echo getenv('ITSM_API_URL'); ?>',
|
|
415
|
+
apiKey: '<?php echo getenv('ITSM_API_KEY'); ?>',
|
|
416
|
+
tenant: '<?php echo getenv('ITSM_TENANT'); ?>',
|
|
417
|
+
requesterName: '<?php echo htmlspecialchars($_SESSION['username'] ?? ''); ?>',
|
|
418
|
+
onSuccess: function(response) {
|
|
419
|
+
console.log('Request submitted:', response);
|
|
420
|
+
alert('Yêu cầu đã được gửi thành công!');
|
|
421
|
+
}
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
window.itsmWidgetInstance = widget;
|
|
425
|
+
});
|
|
426
|
+
</script>
|
|
427
|
+
</body>
|
|
428
|
+
</html>
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
---
|
|
432
|
+
|
|
433
|
+
## 📝 Configuration Options
|
|
434
|
+
|
|
435
|
+
Xem [README.md](./README.md#options) để xem đầy đủ các options có thể cấu hình.
|
|
436
|
+
|
|
437
|
+
## 🎨 Styling
|
|
438
|
+
|
|
439
|
+
Widget sử dụng **native HTML/CSS**, không cần bất kỳ thư viện hay framework nào.
|
|
440
|
+
|
|
441
|
+
Bạn có thể override CSS để match với theme của project:
|
|
442
|
+
|
|
443
|
+
```css
|
|
444
|
+
/* Override primary color */
|
|
445
|
+
.itsm-btn-primary {
|
|
446
|
+
background-color: #your-color !important;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/* Override modal width */
|
|
450
|
+
.itsm-modal-container {
|
|
451
|
+
max-width: 800px !important;
|
|
452
|
+
}
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
## ✅ Tương thích
|
|
456
|
+
|
|
457
|
+
- ✅ Tất cả modern browsers (Chrome, Firefox, Safari, Edge)
|
|
458
|
+
- ✅ IE 11+ (với polyfills)
|
|
459
|
+
- ✅ Mobile browsers (iOS Safari, Chrome Mobile)
|
|
460
|
+
- ✅ Không phụ thuộc jQuery
|
|
461
|
+
- ✅ Không phụ thuộc framework
|
|
462
|
+
- ✅ Works với CSP (Content Security Policy)
|
|
463
|
+
|
|
464
|
+
## 🐛 Troubleshooting
|
|
465
|
+
|
|
466
|
+
Xem [README.md](./README.md) hoặc [TEST.md](./TEST.md) để troubleshoot.
|
|
467
|
+
|