Compare commits

...

1762 Commits

Author SHA1 Message Date
Julien Fontanet
f85f6eab9e 5.0.5 2016-07-04 19:04:36 +02:00
Julien Fontanet
b6dc8b507d fix(SortedTable): total number of items when collection is a map 2016-07-04 19:03:31 +02:00
ABHAMON Ronan
831308ee05 feat(pool/patches): can patches hosts (#1203)
Fixes #1149
2016-07-04 18:52:39 +02:00
Fabrice Marsaud
eb5bcb759f feat(home): can display pools (#1202)
Fixes #1140
2016-07-04 16:28:41 +02:00
ABHAMON Ronan
8286570811 feat(xo-line-charts): supports sum of stats series (#1197)
Fixes #1158
2016-07-04 16:27:26 +02:00
Pierre Donias
10b511f0ed fix(form/SizeInput): props.defaultValue instead of props.value (#1206) 2016-07-04 15:56:57 +02:00
Julien Fontanet
751e335bc0 5.0.4 2016-07-01 17:53:47 +02:00
Pierre Donias
cb107521f2 feat(migration): smart VIFs-networks mapping (#1195) 2016-07-01 17:10:57 +02:00
Olivier Lambert
e56af57b74 fix(card): minor style change 2016-07-01 17:09:10 +02:00
ABHAMON Ronan
a2a1cbab6e feat(sorted-table): display selected items number (#1200)
Fixes #1133
2016-07-01 17:07:57 +02:00
Pierre Donias
306a021a8d fix(new-vm): make radio buttons controlled (#1199)
Fixes #1198
2016-07-01 16:11:19 +02:00
Julien Fontanet
d8c414af2f fix(getEventValue): returns value prop for radios 2016-07-01 15:47:46 +02:00
Julien Fontanet
ec4c76b2e0 feat(selectors): filter() can be chained after pick() 2016-07-01 15:47:46 +02:00
ABHAMON Ronan
e23b8a6891 feat(dashboard/overview): display missing patches (#1191)
Fixes #1148
2016-07-01 15:28:07 +02:00
Olivier Lambert
34006bcbf6 fix(health): forget to check edition 2016-07-01 14:47:43 +02:00
ABHAMON Ronan
ed9aeabf6a chore(dashboard/health): use Card (#1194) 2016-07-01 11:20:32 +02:00
Fabrice Marsaud
799fc5089f feat(settings/remotes): add button to test a remote (#1192)
Fixes #1075.
2016-07-01 09:25:57 +02:00
Julien Fontanet
683d510aa6 5.0.3 2016-06-30 15:12:26 +02:00
Pierre Donias
ebd7e58f61 feat(home): bulk VM migration (#1187)
Fixes #1146
2016-06-30 15:04:21 +02:00
Fabrice Marsaud
9a498b54ac fix(menu): only display one icon for updates when collapsed (#1190)
Fixes #1188
2016-06-30 15:03:26 +02:00
ABHAMON Ronan
2687f45e6e fix(settings/plugins): set config value to undefined if value is null (#1189) 2016-06-30 14:31:43 +02:00
ABHAMON Ronan
f79a17fcec feat(json-schema-input): generate uiSchema JSON schema (#1182) 2016-06-30 13:52:20 +02:00
ABHAMON Ronan
8fd377d1e2 feat(dashboard/dataviz): parallel coordinates graph (#1174)
Fixes #1157
2016-06-30 11:36:29 +02:00
Olivier Lambert
fda06fbd29 feat(VM/network): VIFs management (#1186)
Fixes #1176
2016-06-30 11:28:25 +02:00
Fabrice Marsaud
cee4378e6d feat(xoa-updates): reload after upgrading (#1183)
Fixes #1131.
2016-06-30 11:26:03 +02:00
Fabrice Marsaud
ab6d342886 fix(VM/network): fix broken propTypes import (#1184) 2016-06-29 17:59:39 +02:00
Fabrice Marsaud
9954c08993 fix(xoa-updates): fix env test (#1181) 2016-06-29 12:16:25 +02:00
Julien Fontanet
3ae80aeab3 feat(link): expose Link and BlockLink components 2016-06-29 11:57:42 +02:00
Julien Fontanet
2a3534f659 chore(utils): do not re-export propTypes 2016-06-29 11:57:42 +02:00
Julien Fontanet
fc39de0d5a chore(sign-in): remove because unused 2016-06-29 11:57:41 +02:00
Julien Fontanet
64e4b79d41 chore(utils/createSimpleMatcher): remove because not used 2016-06-29 11:57:41 +02:00
Fabrice Marsaud
53887da3da feat(VM/network): VIF creation (#1173)
Fixes #1138.
2016-06-28 17:47:44 +02:00
ABHAMON Ronan
7c60d68f56 fix(xo-line-chart): set precision on LoadLineChart (#1175)
Fixes #1167
2016-06-28 17:17:46 +02:00
Julien Fontanet
2ac1b991b1 feat(BaseComponent#_linkedState): only allocate when necessary 2016-06-28 15:56:53 +02:00
Julien Fontanet
8257714cdb feat(get-event-value): works with checkbox/radio/select 2016-06-28 15:56:53 +02:00
Julien Fontanet
1b8bacbf5a chore(utils/autobind): remove in favor of ES7 class properties syntax 2016-06-28 15:56:52 +02:00
Julien Fontanet
1d5b84389d chore(utils): do not re-export invoke 2016-06-28 15:56:51 +02:00
Julien Fontanet
f7dcf52977 chore(utils/If): remove because does not work 2016-06-28 15:03:34 +02:00
Julien Fontanet
e26dd5147a feat(BaseComponent#linkState): creates a callback associated to a state entry 2016-06-28 14:56:51 +02:00
Julien Fontanet
bb8f96c2e2 5.0.2 2016-06-28 14:38:13 +02:00
Julien Fontanet
95d4cc9055 chore(README): master → stable 2016-06-28 14:37:14 +02:00
Julien Fontanet
cb84a85f8b chore(package): make package publishable 2016-06-28 14:36:32 +02:00
Pierre Donias
0a8aa2ecf5 feat(user): better UI and password edition (#1165)
Fixes #1127
2016-06-28 14:32:02 +02:00
Julien Fontanet
5941321e84 fix(intl/locales): Spanish is es, not sp 2016-06-28 14:15:11 +02:00
Julien Fontanet
8cf62280f4 feat(intl/locales/sp): initial file 2016-06-28 14:13:21 +02:00
Olivier Lambert
4cea142b57 fix(tasks): improve the task view (#1166)
Fixes #1147
2016-06-28 12:31:25 +02:00
Fabrice Marsaud
64d9245bc4 fix(settings/users): correctly set default permission value (#1170)
Fixes #1159
2016-06-28 11:49:04 +02:00
Fabrice Marsaud
2d78c0c4c3 fix(backup/restore): ignore incorrectly formatted files (#1163)
Fixes #1164
2016-06-28 11:19:54 +02:00
Pierre Donias
aa585e2d25 fix(home): always use advanced migration modal (#1137) 2016-06-27 16:15:52 +02:00
Julien Fontanet
325ab17dcc chore(xo): prefix local function call with _ 2016-06-27 16:04:54 +02:00
Pierre Donias
443ea44bcd fix(new/vm): default custom cloud config (#1125) 2016-06-27 15:21:20 +02:00
Pierre Donias
07958d8efa fix(vms/new): gracefully handle missing objects (#1124) 2016-06-27 15:20:05 +02:00
Olivier Lambert
f19affe599 fix: better SR predicate (#1122) 2016-06-27 15:15:46 +02:00
Julien Fontanet
f7b7c27b6c fix(host/storage): use long clicks for SR name edition 2016-06-25 09:10:22 +02:00
Julien Fontanet
c7af5b384c fix(xo/editSr): use camel case param
Fixes #1116
2016-06-25 09:09:12 +02:00
Olivier Lambert
436a9dfc14 5.0.1 2016-06-25 07:09:43 +02:00
Olivier Lambert
1d6d8ccb28 fix(ACLs): are available from Enterprise (#1117) 2016-06-25 01:09:06 +02:00
Julien Fontanet
7d0862ecfd fix(disclaimer): only from sources (#1119) 2016-06-25 01:08:18 +02:00
Julien Fontanet
7de059919b Merge branch 'v5.x' into next-release 2016-06-24 18:22:54 +02:00
Julien Fontanet
dfd1fb86cb chore(tab-button): inline props 2016-06-24 14:05:15 +02:00
ABHAMON Ronan
847a92433f fix(host/storage): use TabButtonLink instead of Link (#1113) 2016-06-24 14:04:02 +02:00
Pierre Donias
53af4df47b feat(vms/new): fixes and multiple VMs creation (#1098) 2016-06-24 14:02:24 +02:00
Olivier Lambert
09db7c999e fix(he i18n): fix missing space 2016-06-24 14:01:50 +02:00
Denis Kalitviansky
1b4c958aba feat(i18n): Hebrew (#1112) 2016-06-24 13:44:05 +02:00
Fabrice Marsaud
9368d5df01 fix(backup/edit) (#1110) 2016-06-24 13:42:46 +02:00
Olivier Lambert
f3b5026190 fix(ACLs): update views to behave with missing objects (#1111) 2016-06-24 12:53:18 +02:00
ricardovilarinho
19dcd81639 feat(i18n): more Portugese (#1106) 2016-06-24 12:46:37 +02:00
Julien Fontanet
d38c171151 fix(home): add missing key prop 2016-06-24 11:53:32 +02:00
Julien Fontanet
af3049925f fix(SingleLineRow): behave with falsy children 2016-06-24 11:46:39 +02:00
Julien Fontanet
a79825d18c feat(menu): add some entries to non-admins 2016-06-24 11:20:22 +02:00
Olivier Lambert
c4b456b470 fix(home): broken OpenSource modal due to bad intl import 2016-06-24 11:15:09 +02:00
Julien Fontanet
ccdf28767a fix(build): various issues
- missing assets with npm run build
- some files had source maps even though it did not make sense
2016-06-24 11:05:14 +02:00
ABHAMON Ronan
2561f7d793 fix(home/storage): "add a storage" link style & label (#1109) 2016-06-24 10:52:36 +02:00
Fabrice Marsaud
57bd8c1a49 fix(settings/users): permission when creating user (#1108) 2016-06-24 09:58:38 +02:00
Julien Fontanet
8387e4ae04 chore(intl): remove unused messages 2016-06-23 20:03:41 +02:00
Julien Fontanet
5c02935017 fix(user): correctly select current lang 2016-06-23 20:01:56 +02:00
Julien Fontanet
726ffb9b1b feat(store): save lang in cookie 2016-06-23 19:59:18 +02:00
Olivier Lambert
5dcc3f4076 fix(i18n): various mistakes 2016-06-23 19:27:35 +02:00
Fabrice Marsaud
4639d7872f feat(backup/restore): translation (#1105) 2016-06-23 17:52:26 +02:00
Pierre Donias
71cb6af8c4 fix(intl): confirmOK, confirmCancel and alertOk (#1104) 2016-06-23 17:46:28 +02:00
Fabrice Marsaud
52060301bd feat(logs): use SortedTable (#1099) 2016-06-23 17:43:14 +02:00
Olivier Lambert
dfa3e6d8e4 feat(changelog): adding changelog file and changes for 5.0.0 2016-06-23 17:41:42 +02:00
ABHAMON Ronan
f38f3fe5c9 fix(self): message if no resource sets (#1100) 2016-06-23 17:13:47 +02:00
Fabrice Marsaud
24bf031270 feat(menu): add updater status icon (#1103) 2016-06-23 17:11:25 +02:00
ABHAMON Ronan
eeadd72e1f feat(host/storage): add button redirect to new/sr page (#1097) 2016-06-23 16:45:36 +02:00
ricardovilarinho
e4139bab04 Initial work on portuguese translation (#1102) 2016-06-23 16:34:50 +02:00
Fabrice Marsaud
7c7205849b feat(backup/restore): display number of backups per VM (#1101) 2016-06-23 16:24:36 +02:00
ABHAMON Ronan
03b2b13f14 feat(dashboard/stats): add weekly charts (#1093) 2016-06-23 15:53:44 +02:00
Olivier Lambert
8caf9f7fde feat(locales): add i18n PT and HE files 2016-06-23 15:50:19 +02:00
Julien Fontanet
5b8a5ac6b6 fix(create-locale): remove trailing comma 2016-06-23 15:43:34 +02:00
Julien Fontanet
4429bed1cf fix(intl/messages): xenToolsStatusValue description 2016-06-23 15:25:12 +02:00
Julien Fontanet
b9beda3484 fix(intl): export messages 2016-06-23 15:21:31 +02:00
Julien Fontanet
354c9bc927 feat(create-locale): tool to scaffold a new locale 2016-06-23 15:06:28 +02:00
Julien Fontanet
a2d88f7fbf chore(intl): split messages data 2016-06-23 15:05:53 +02:00
Olivier Lambert
83cad000e7 feat(job new): i18n 2016-06-23 12:30:29 +02:00
Fabrice Marsaud
1b78791aa9 feat(groups,users): UI improvements (#1094) 2016-06-23 12:20:17 +02:00
Olivier Lambert
2b05fbf6a0 feat(pool network): i18n 2016-06-23 12:17:59 +02:00
Olivier Lambert
7b677cddaf feat(jobs): xoa plans for jobs feature 2016-06-23 11:03:03 +02:00
Olivier Lambert
18a8fcaa70 feat(newSr,pool,updates): i18n 2016-06-23 10:46:27 +02:00
ABHAMON Ronan
dd1bc757d5 fix(SortedTable): better pagination/filter alignment (#1095) 2016-06-23 10:44:35 +02:00
Olivier Lambert
27ca0fdfcc fix(home): broken link for new VM button 2016-06-22 17:46:30 +02:00
Olivier Lambert
578de05a40 feat(logs): i18n 2016-06-22 17:38:31 +02:00
Olivier Lambert
cd3e1d6bd4 feat(job): i18n 2016-06-22 17:23:37 +02:00
Julien Fontanet
de160bb51b feat(xo): make all calls wait for authentication 2016-06-22 17:12:56 +02:00
ABHAMON Ronan
14417e14c0 fix(vm/snapshots): use ButtonGroup with action buttons (#1096) 2016-06-22 17:02:32 +02:00
Olivier Lambert
f2d8b4e444 feat(dashboard): i18n 2016-06-22 16:55:47 +02:00
Olivier Lambert
b7c41fee28 feat(restore backup): i18n 2016-06-22 16:35:15 +02:00
Olivier Lambert
4f0678d6a2 fix(new backup): forgotten i18n for reset word 2016-06-22 15:41:25 +02:00
Olivier Lambert
880c624935 feat(xoa-upgrade): i18n 2016-06-22 15:22:17 +02:00
Olivier Lambert
0fa0902262 feat(about): i18n 2016-06-22 15:12:07 +02:00
Fabrice Marsaud
a2ab3ccaee feat(jobs/scheduling) (#1032) 2016-06-22 14:51:37 +02:00
Fabrice Marsaud
77a0d1c2ff feat(settings/acls): use SortedTable (#1090) 2016-06-22 14:26:30 +02:00
Olivier Lambert
7fdb022819 feat(backup restore): more explicit restore operation 2016-06-22 12:02:04 +02:00
Fabrice Marsaud
878a630b69 feat(backup/restore): better UI (#1081) 2016-06-22 11:41:50 +02:00
Pierre Donias
fbcfc69983 feat(host,pool): network management (#1084) 2016-06-22 10:01:51 +02:00
Olivier Lambert
a1bd327524 feat(about): hide xo version numbers for non admin users. Fix #877 2016-06-21 17:42:38 +02:00
Olivier Lambert
e62829debd fix(new-vm): using 'state' and not 'this' for SSH cloudConfig 2016-06-21 16:51:00 +02:00
Julien Fontanet
d9d669964f fix(xo/attachDiskToVm): camel casing and params order 2016-06-21 15:36:02 +02:00
Julien Fontanet
ced17b632a fix(editable/Text): do not add all props to the input element 2016-06-21 14:55:16 +02:00
Olivier Lambert
0aada62a5a feat(host,vm): use SortedTable for VM and host logs 2016-06-21 14:01:49 +02:00
Julien Fontanet
2fece7a8fe perf(selectors/createGetObjectMessages): better input dependency 2016-06-21 13:52:07 +02:00
Julien Fontanet
6680373c76 fix(VM/Logs): use correct selector creator 2016-06-21 13:52:07 +02:00
Olivier Lambert
68ae43fd72 feat(vm): add ISO disk drive selector in VM disk view 2016-06-21 13:40:47 +02:00
Julien Fontanet
6b6f452d06 feat(VM/Advanced): can edit number of current CPUs 2016-06-21 12:13:20 +02:00
Greenkeeper
7153ff17e8 chore(package): update modular-css to version 0.22.1 (#1087)
https://greenkeeper.io/
2016-06-21 09:16:12 +02:00
Pierre Donias
0fde5a1b3d fix(new-vm): network instead of $network (#1085) 2016-06-20 17:17:08 +02:00
Julien Fontanet
b17fbdd19b fix(SortedTable): correctly pass a selector to createFilter. 2016-06-20 17:05:23 +02:00
Julien Fontanet
61ae522486 chore(xo): remove test function plop 2016-06-20 17:05:23 +02:00
Olivier Lambert
bd414ae9f2 fix(new-vm): send VDI id for ISO, stringify device for VDI 2016-06-20 15:36:59 +02:00
Olivier Lambert
7579db5876 feat(host): use SortedTable for patches (#1083) 2016-06-20 14:21:20 +02:00
Julien Fontanet
994ce8dab2 fix(log-error): add missing file 2016-06-20 13:12:46 +02:00
Julien Fontanet
e8a84dce7d chore(xo/purgePluginConfiguration): remove unused try/catch. 2016-06-20 13:11:24 +02:00
Julien Fontanet
fdca9eda90 fix(xo): display next connection attempt as warning 2016-06-20 13:11:24 +02:00
Julien Fontanet
e007009a00 feat(xo): logs all call errors 2016-06-20 13:11:24 +02:00
Julien Fontanet
1d5cc209dd feat(log-error): properly display an error in the console 2016-06-20 13:11:24 +02:00
Pierre Donias
09b18e1563 fix(vms/new): Display VDIs instead of SRs in ISO/DVD selector (#1082) 2016-06-20 09:53:00 +02:00
Fabrice Marsaud
363db0edea Create or attach disk and a VM, and change boot order with Drag&Drop (#1067)
* feat(vm): add & attach disks, boot order

* chore(vm): fix issues and use correct selectors predicates for SR/disks
2016-06-17 18:53:06 +02:00
Olivier Lambert
e500240a35 feat(visualizations): add a coming soon message 2016-06-17 17:48:46 +02:00
Pierre Donias
6694977b87 fix(form/Select): set a minimum width (#1080) 2016-06-17 15:23:45 +02:00
Pierre Donias
b173dc1f28 fix(Page): fix height (#1079) 2016-06-17 14:56:05 +02:00
Pierre Donias
aa91f5649f fix(vms/new): text field to set the cloud configuration (#1077) 2016-06-17 11:59:06 +02:00
ABHAMON Ronan
74efd563ab feat(xo-week-heatmap) (#1064) 2016-06-17 11:27:15 +02:00
Pierre Donias
b0b389fb4d fix(dashboard/overview): lint (#1078) 2016-06-17 11:26:32 +02:00
Pierre Donias
e2d9131a07 feat(react-novnc): support clipboard (#1076) 2016-06-16 17:43:23 +02:00
Olivier Lambert
3b1c8216b9 feat(home): more info density on large screens 2016-06-16 17:00:03 +02:00
Julien Fontanet
7f259a43cf fix(home): handle disappearing filter during life 2016-06-16 15:28:32 +02:00
Julien Fontanet
874a504df3 feat(home): can display hosts 2016-06-16 15:09:08 +02:00
Julien Fontanet
6a4c6318e3 fix(form/Toggle): controlled/uncontrolled issues 2016-06-16 11:06:14 +02:00
Julien Fontanet
09bf2b87dc feat(form/Toggle): move into its own module 2016-06-16 11:05:36 +02:00
Olivier Lambert
9c5c9838ae chose(vm,host): use value for toggle 2016-06-16 10:47:15 +02:00
Olivier Lambert
3924033d9a feat(settings): read-only for server connection (#1074) 2016-06-15 18:00:31 +02:00
ABHAMON Ronan
d81e45e456 feat(IsoDevice) (#1071) 2016-06-15 17:42:15 +02:00
Pierre Donias
631a762b56 feat(host/tab-storage): each row of the table is a link to the storage (#1073) 2016-06-15 17:10:35 +02:00
Julien Fontanet
a9cf79942f feat(form/Toggle): can be used as a controlled component 2016-06-15 17:03:06 +02:00
Julien Fontanet
bd31476933 fix(Tooltip): fix import 2016-06-15 17:00:51 +02:00
Julien Fontanet
9b9e4c2ffa fix(select-objects): remove unused import 2016-06-15 16:44:48 +02:00
Julien Fontanet
ec93daac7e feat(Tooltip): accept a className prop 2016-06-15 16:08:03 +02:00
Julien Fontanet
3431b2dfb1 fix(Tooltip): stricter propTypes for children prop 2016-06-15 16:05:45 +02:00
Julien Fontanet
4270abaf1c feat(Tooltip): children prop is optional 2016-06-15 16:05:45 +02:00
Julien Fontanet
0bd288afbd feat(Tooltip): support a tagName prop 2016-06-15 16:05:45 +02:00
Julien Fontanet
b72d5d50a1 feat(select-objects/SelectTag): accept an objects prop 2016-06-15 16:05:45 +02:00
Pierre Donias
d51889c233 feat(utils/BlockLink): Ctrl-click or middle mouse click to open in new tab (#1070) 2016-06-15 14:29:29 +02:00
Olivier Lambert
332b093ee9 feat(copyVM): include Edition check 2016-06-15 13:10:53 +02:00
Pierre Donias
8be332208f feat(xo): copyVm() (#1069) 2016-06-15 11:51:35 +02:00
ABHAMON Ronan
85d1188628 feat(react-novnc): can send Ctrl+Alt+Del (#1068) 2016-06-15 11:28:44 +02:00
Julien Fontanet
56896996c3 feat(selectors/createGetObjectsOfType): type can be a selector 2016-06-15 10:32:21 +02:00
Julien Fontanet
896374e069 feat(selectors/createSortForType): type can be a selector 2016-06-15 10:32:21 +02:00
Julien Fontanet
ac36505fb2 fix(home): remove extranous space in filter 2016-06-15 10:32:21 +02:00
Julien Fontanet
d36df1a8ae chore(home): move VmItem in its own module 2016-06-15 10:32:21 +02:00
ABHAMON Ronan
edd939c069 feat(react-novnc): auto reconnect (#1065) 2016-06-15 10:04:41 +02:00
Olivier Lambert
f80225ba54 feat(updates): current version in updater view 2016-06-14 18:48:39 +02:00
Olivier Lambert
3ccd87b369 fix(self): use formatSize for human readable disk and RAM available 2016-06-14 18:08:32 +02:00
ABHAMON Ronan
59d3dd9255 feat(vm): VM export (#1066) 2016-06-14 17:27:57 +02:00
Pierre Donias
392f08059d feat(vms/new): VM creation page (#1058) 2016-06-14 17:05:10 +02:00
Julien Fontanet
0d5c9a2bba feat(home): connect pools/hosts/tags selects 2016-06-14 16:39:10 +02:00
Julien Fontanet
f27de8015b feat(complex-matcher): -addPropertyClause, +getPropertyClausesStrings, +setPropertyClause 2016-06-14 16:39:10 +02:00
Julien Fontanet
3b7bdee814 fix(complex-matcher/parse): do not fail on empty input 2016-06-14 16:39:10 +02:00
Julien Fontanet
397ed9d581 feat(complex-matcher): $ char is allowed in raw strings 2016-06-14 16:39:10 +02:00
Julien Fontanet
a098880669 fix(selectors/createGetTags): make it work for real :) 2016-06-14 16:39:10 +02:00
Julien Fontanet
047d4cb650 fix(select-objects/SelectTags): fix label 2016-06-14 16:39:10 +02:00
Julien Fontanet
736904c579 feat(select-objects): can be used as controlled inputs 2016-06-14 16:39:10 +02:00
Olivier Lambert
e883c668b5 feat(XOA): VM import / backups (#1063) 2016-06-14 15:29:47 +02:00
Julien Fontanet
14181aa8a7 fix(selectors): fix pool ordering 2016-06-14 11:53:08 +02:00
Olivier Lambert
0b1ba99afa feat(XOA): Free edition(#1062) 2016-06-14 10:44:44 +02:00
Olivier Lambert
88a6215939 feat(health): use SortedTable (#1057) 2016-06-13 12:08:58 +02:00
Greenkeeper
d5ebd33038 chore(package): update globby to version 5.0.0 (#1056)
https://greenkeeper.io/
2016-06-13 09:47:34 +02:00
ABHAMON Ronan
b2ac214c0f feat(form/Select): advanced virtualized select implementation (#1052) 2016-06-13 09:44:38 +02:00
Olivier Lambert
3dee41a511 feat(tasks): better task view. (#1055)
* feat(tasks): better task view
2016-06-10 17:26:30 +02:00
ABHAMON Ronan
934818c07d feat(backup/new): disaster recovery accept an SR (#1054)
Fixes #955
2016-06-10 15:49:21 +02:00
Pierre Donias
4dc614a58e fix(ActionButton): oneOfType expects an array (#1053) 2016-06-10 15:42:02 +02:00
Greenkeeper
35ea095b75 chore(package): update chartist-plugin-legend to version 0.3.1 (#1051)
https://greenkeeper.io/
2016-06-10 12:59:01 +02:00
Olivier Lambert
ae1a4c73b3 fix(issue template): use the word "current" instead of "actual" 2016-06-09 22:21:50 +02:00
ABHAMON Ronan
b58dbe89be feat(vms/import) (#1045) 2016-06-09 17:58:12 +02:00
ABHAMON Ronan
1b4551b622 fix(SortedTable): select first page when changing filter (#1050) 2016-06-09 16:57:30 +02:00
Fabrice Marsaud
72a8f819d3 fix(backup/overview): fix display pending jobs (#1049) 2016-06-09 15:01:27 +02:00
ABHAMON Ronan
df8e16379c fix(select-objects): remove option margin when no containers (#1047) 2016-06-09 14:15:06 +02:00
Julien Fontanet
7dbbc7e25c fix(invoke): fix optim when called without args 2016-06-09 13:36:07 +02:00
Julien Fontanet
1eaae70adb feat(editable/Text): support validation related props 2016-06-09 13:36:07 +02:00
Julien Fontanet
d4a61782c4 chore(menu): menu prefix for icons is optional 2016-06-09 13:35:12 +02:00
Fabrice Marsaud
0e39c6f895 fix(SelectRemote) (#1046) 2016-06-09 12:26:31 +02:00
Fabrice Marsaud
fcc3ede485 fix(settings/remotes): use file type instead of local (#1044) 2016-06-09 10:45:18 +02:00
Fabrice Marsaud
f001e7e713 xo-remote-parser 0.2 2016-06-09 10:28:13 +02:00
Olivier Lambert
3fb8fae821 feat(selectHost): display hostname directly. Continue to group per pools 2016-06-09 10:13:37 +02:00
Fabrice Marsaud
349f3185c5 feat(settings/remotes): edition (#1040) 2016-06-08 17:24:41 +02:00
Olivier Lambert
b457b8409f feat: most of the views now have a header (#1042) 2016-06-08 17:07:43 +02:00
Olivier Lambert
c61e5e1ac8 feat(health): use sorted Table for alarms (#1041) 2016-06-08 15:42:39 +02:00
ABHAMON Ronan
9e60f9d9fd feat(SortedTable): add filter (#1039) 2016-06-08 14:48:34 +02:00
ABHAMON Ronan
a95d40078f feat(SortedTable): pagination can be injected in a container (#1038) 2016-06-08 10:11:18 +02:00
Julien Fontanet
515798bd9f feat(selectors): filter objects by permissions 2016-06-07 16:45:32 +02:00
Julien Fontanet
20b28135a3 chore(store): do not connect to XOA updaters in Sources plan 2016-06-07 15:57:46 +02:00
Julien Fontanet
33d2b8bbeb chore(dev-tools): move into store 2016-06-07 15:57:46 +02:00
Julien Fontanet
7c2059af2b fix(xoa-updater/blockXoaAccess): typo 2016-06-07 15:57:46 +02:00
ABHAMON Ronan
1e0f57bd1a feat(SortedTable): support pagination (#1036) 2016-06-07 14:07:29 +02:00
Olivier Lambert
9484f1dbe6 fix(new sr): wrong URL for srs view 2016-06-07 10:29:06 +02:00
Julien Fontanet
658766c9e4 fix(home): fix variable name 2016-06-07 10:22:25 +02:00
Julien Fontanet
9e47d9acf1 chore(migrate-vm-modal): move into xo 2016-06-06 15:37:04 +02:00
Julien Fontanet
5a1247c021 chore(selectors): getAreObjectsFecthed() → areObjectsFetched() 2016-06-06 15:30:50 +02:00
Julien Fontanet
a8b7972f3c chore: use Container instead of .container-fluid 2016-06-06 14:31:26 +02:00
Fabrice Marsaud
836c2127f7 chore(backup/restore): refactor using render-xo-item (#1023) 2016-06-06 14:28:24 +02:00
Olivier Lambert
6cef200aed feat(menu,about): set content depending on XOA plan (#1033) 2016-06-06 14:21:02 +02:00
Julien Fontanet
c9c80b1d62 fix(xoa-updater): fix import lodash/forEach 2016-06-06 13:45:55 +02:00
Julien Fontanet
04328bc2d1 fix(new/sr): fix import lodash/trim 2016-06-06 13:45:39 +02:00
Julien Fontanet
d909d0eeeb fix(package): update xo-remote-parser to 0.2.1 2016-06-06 13:39:22 +02:00
Julien Fontanet
80f5e913ec chore(users) 2016-06-06 11:28:35 +02:00
Julien Fontanet
57eca31a9c feat(utils/addSubscriptions): decorator to inject subscriptions 2016-06-06 11:28:35 +02:00
Julien Fontanet
c645fc7ad1 feat(utils/connectStore): can handle an object of selectors 2016-06-06 11:28:35 +02:00
Julien Fontanet
78b524b2e8 chore: always user selector to access state 2016-06-06 11:28:35 +02:00
Fabrice Marsaud
1ff1b6931b feat(xoa-updater): initial integration (#952) 2016-06-06 11:23:57 +02:00
Olivier Lambert
29ac883616 feat(xo-app,home): add nice loading icon 2016-06-03 22:22:56 +02:00
Julien Fontanet
467a147603 fix(grid/Row): remove flex which broke columns collapse 2016-06-03 20:36:13 +02:00
Julien Fontanet
7b49b6304c fix(xo-app): fix body scrolling 2016-06-03 20:35:00 +02:00
Olivier Lambert
25991027b9 fix(home): links to import and restore 2016-06-03 19:48:45 +02:00
Olivier Lambert
fce83dfa66 chore(home): text outside links 2016-06-03 19:27:36 +02:00
Olivier Lambert
8603d5d468 feat(home): using card component 2016-06-03 19:15:52 +02:00
Julien Fontanet
bd17f85140 chore(home): do not use btn class on links 2016-06-03 17:56:00 +02:00
Julien Fontanet
037dddb945 fix(messages): fix a typo 2016-06-03 17:52:15 +02:00
Julien Fontanet
dd2151e611 fix(grid/Col): should always have a class 2016-06-03 17:51:56 +02:00
Julien Fontanet
a1e0cdadd6 fix(xo-app): do not set flex on the body container 2016-06-03 17:51:34 +02:00
Julien Fontanet
8d36efa66c chore(Col): do not set the size when full width 2016-06-03 17:35:41 +02:00
Julien Fontanet
b9a12a6dcc feat(Debug): can display promises 2016-06-03 17:24:56 +02:00
Olivier Lambert
08e4fe9990 feat(about): add about info (#1031) 2016-06-03 17:24:07 +02:00
ABHAMON Ronan
2333fec181 feat(SortedTable) (#1030) 2016-06-03 17:22:22 +02:00
Olivier Lambert
05676a78e3 feat(home): handle loading, no servers or no VMs (#1028) 2016-06-03 16:35:55 +02:00
Julien Fontanet
02aaae240c feat(CenterPanel): to use when no data for instance 2016-06-03 11:30:48 +02:00
Julien Fontanet
158924fe3c chore(xo-app): remove unnecessary style 2016-06-03 10:17:36 +02:00
Julien Fontanet
0341b926b9 chore(xo-app/page): move styles to CSS module 2016-06-03 10:12:03 +02:00
Julien Fontanet
69d1f93ea4 feat(xo-app): remove body padding 2016-06-03 10:11:03 +02:00
Julien Fontanet
423fb56ae0 fix(reducers): add missing change 2016-06-02 18:25:48 +02:00
Julien Fontanet
c5fc8d437f fix(selectors/getAreObjectsFetched): previous test was not good enough 2016-06-02 18:24:44 +02:00
Julien Fontanet
0811addf9c fix(selectors/getAreObjectsFetched): use the correct test 2016-06-02 18:18:31 +02:00
Julien Fontanet
e6f8108dc0 feat(selectors/getAreObjectsFetched) 2016-06-02 18:06:20 +02:00
Julien Fontanet
4aa4a8c75d feat(Servers): add spaces in creation form 2016-06-02 18:03:27 +02:00
Julien Fontanet
bbe0467d16 feat(Server): use editable/Password 2016-06-02 18:03:27 +02:00
Julien Fontanet
88ca69138b feat(Server): use ActionRowButton 2016-06-02 18:03:27 +02:00
Julien Fontanet
6a0d9c8805 feat(Users): use ActionButton as submit 2016-06-02 18:01:01 +02:00
Julien Fontanet
1a57f9f134 feat(Users): use ActionRowButton 2016-06-02 18:01:01 +02:00
Julien Fontanet
109aedd3ae feat(ActionButton): redirectOnSuccess can be a function 2016-06-02 18:01:01 +02:00
ABHAMON Ronan
bd9f9344e5 fix(backup jobs): edition (#1026) 2016-06-02 15:23:26 +02:00
ABHAMON Ronan
5190873e99 fix(json-schema-input): correctly handle optional array/object (#1027)
Fixes #1000.
2016-06-02 15:17:51 +02:00
Julien Fontanet
c5fe7eb0dd chore(Groups): remove unused import 2016-06-02 13:51:05 +02:00
Fabrice Marsaud
fef1b14d69 fix a xo fn 2016-06-02 13:48:05 +02:00
Julien Fontanet
472fc02533 feat(Groups): use editable/Text for name 2016-06-02 13:47:39 +02:00
Julien Fontanet
ed29524cf3 fix(xo): resolveIds handles non objects 2016-06-02 13:46:50 +02:00
Julien Fontanet
69f35436c2 feat(form/Password): enableGenerator defaults to false 2016-06-02 13:46:19 +02:00
Fabrice Marsaud
a0ca1cddb5 feat(ACLs) (#1011) 2016-06-02 13:19:35 +02:00
Greenkeeper
be4ffd8308 chore(package): update notifyjs to version 2.0.1 (#1025)
https://greenkeeper.io/
2016-06-02 12:04:35 +02:00
Julien Fontanet
8e246f08ee fix(xo subscriptions): fix running condition 2016-06-02 11:45:24 +02:00
Julien Fontanet
73eda65300 fix(xo subscriptions): wait for previous call to finish 2016-06-02 10:32:50 +02:00
Julien Fontanet
be4df02844 fix(README): fix XOA_PLAN example 2016-06-02 10:27:47 +02:00
Julien Fontanet
7de461319f feat(XOA_PLAN): environment var for different builds 2016-06-02 10:25:58 +02:00
Olivier Lambert
970fc16aab feat(vm): working VDI live migration 2016-06-01 18:35:09 +02:00
Olivier Lambert
5db2c5804d fix(backup): typo for button size 2016-06-01 17:41:05 +02:00
Olivier Lambert
6c2924a08a fix(backup): typo in button style 2016-06-01 17:41:05 +02:00
Pierre Donias
32511fe6a0 feat(editable/XoSelect) (#1020) 2016-06-01 17:22:39 +02:00
Olivier Lambert
94d5b0f083 chore(backup): use the appropriate components 2016-06-01 17:22:25 +02:00
Julien Fontanet
0e957b9566 fix(renderXoItemFromId): handle missing object 2016-06-01 17:01:53 +02:00
Julien Fontanet
ec93f21f0a fix(renderXoItemFromId): fix incorrect var name 2016-06-01 17:01:41 +02:00
Julien Fontanet
bbc4f3beb4 chore(xo): move subscription refreshes in related methods 2016-06-01 16:54:21 +02:00
Julien Fontanet
c271a25a51 feat(selectors/createFilter): if predicate is false, empty collection is returned 2016-06-01 16:35:09 +02:00
Julien Fontanet
c986bf0c46 chore(common): group multiple-files modules in dirs 2016-06-01 16:35:09 +02:00
ABHAMON Ronan
6f994b75e5 feat(backups): deletion & redirect after creation (#1019) 2016-06-01 16:30:40 +02:00
Olivier Lambert
a227039260 feat(vm): allow VDI remove, forget and disconnect 2016-06-01 14:37:00 +02:00
Pierre Donias
ee38c07a3f feat(form/SizeInput): new component for size input (#1017) 2016-06-01 11:15:05 +02:00
ABHAMON Ronan
9678ebd71e chore(select-objects): major refactoring (#1001) 2016-06-01 10:43:38 +02:00
Pierre Donias
82ce0d3461 feat(vm): redirect to home page when VM no longer exists (#1018)
feat(vm): redirect to home page when VM no longer exists
2016-05-31 18:39:03 +02:00
Olivier Lambert
8315c79ef7 feat(host): display the date for license expiry value 2016-05-31 17:25:35 +02:00
Olivier Lambert
69cb6d30b5 feat(VM): VDIs edition (#1015) 2016-05-31 12:27:16 +02:00
Julien Fontanet
f4beef514e fix(xo subscriptions): do not notify if no results yet 2016-05-31 09:16:52 +02:00
Olivier Lambert
f002677134 feat(vm,host): use copiable 2016-05-30 18:48:54 +02:00
Olivier Lambert
6270d2d3af feat(sr,host): add actions on PBDs (#1010) 2016-05-30 18:35:14 +02:00
Julien Fontanet
83625e4ba7 fix(editable/Number): ensure onChange gets a number 2016-05-30 18:21:42 +02:00
Julien Fontanet
d039112b5b feat(xo subscription): notify ASAP when data available 2016-05-30 17:14:24 +02:00
Julien Fontanet
d8481af288 feat(xo subscription): only notify on changes 2016-05-30 17:14:24 +02:00
Julien Fontanet
ea902c1073 fix(xo subscriptions): do not refresh if no subscribers 2016-05-30 17:14:24 +02:00
Julien Fontanet
db62c18a39 fix(xo subscriptions): avoid potential race condition
The subscription could still be active if all the subscriber
unsubscribed at the event reception.
2016-05-30 17:14:24 +02:00
Julien Fontanet
d004e2f759 feat(Copiable) 2016-05-30 17:14:24 +02:00
Julien Fontanet
1f7e457c64 fix(editable/Number): fix size when starting edition 2016-05-30 15:04:52 +02:00
Julien Fontanet
4eae9398d8 fix(editable): fix undo button 2016-05-30 14:58:11 +02:00
Olivier Lambert
4766121570 chore(migrate modal): remove useless message and i18n 2016-05-30 14:57:02 +02:00
Olivier Lambert
3180641e33 feat(sr): add usage and free space 2016-05-30 14:22:53 +02:00
Julien Fontanet
9273002905 ùchore(Tasks): remove unused import 2016-05-30 12:47:59 +02:00
Julien Fontanet
3fc9c5ec90 feat(Tasks): basic tasks list 2016-05-30 12:42:22 +02:00
Julien Fontanet
3266cea1d6 chore(package): update react-router to version 3.0.0-alpha.1 2016-05-30 12:41:52 +02:00
Julien Fontanet
97839c06dc chore(Menu): remove incorrect log 2016-05-30 11:58:32 +02:00
Olivier Lambert
304f290e42 feat(Menu): add tasks link (#1005) 2016-05-30 11:40:35 +02:00
Julien Fontanet
52a241f300 chore(ActionToggle): use btnStyle prop 2016-05-30 10:41:32 +02:00
Julien Fontanet
1c1ea0dcc4 chore(Menu): clean up resize handler code a bit 2016-05-30 10:41:32 +02:00
Julien Fontanet
d998b384e8 chore(ActionToggle): rewritten as stateless component 2016-05-30 10:41:32 +02:00
Olivier Lambert
9184afa6de feat(sr): add various actions (#1002)
* feat(sr,xojs): add SR actions

* naming fix

* typo

* remove SR

* working

* fix

* fix

* noop fixes
2016-05-27 19:07:44 +02:00
Pierre Donias
3e1b4d724f feat(xo/migrateVm): advanced dialog to select host (#993) 2016-05-27 18:21:42 +02:00
Fabrice Marsaud
5b6f50b25b feat(backups): restoration (#996) 2016-05-27 17:56:30 +02:00
Fabrice Marsaud
b757025359 feat(sr addition) (#971) 2016-05-27 17:06:08 +02:00
Olivier Lambert
52e97edbd5 feat(vm,home): add color for OS icons 2016-05-27 15:15:16 +02:00
Olivier Lambert
def88db128 feat(backup overview): i18n 2016-05-27 15:06:58 +02:00
Fabrice Marsaud
d04702e5d4 feat(backups/overview): add logs (#995) 2016-05-27 14:18:23 +02:00
Julien Fontanet
f6407771b5 feat(Icon): accepts className prop 2016-05-27 13:28:58 +02:00
Julien Fontanet
f6a6e125b6 fix(editable/Select): correctly set default value 2016-05-27 13:24:09 +02:00
Julien Fontanet
2303b8a89f feat(loading): center message 2016-05-27 13:16:10 +02:00
Julien Fontanet
93f286b6ac chore(package): remove unused react-router-redux 2016-05-27 13:16:10 +02:00
Julien Fontanet
75e5f931eb chore(store): clarify Xo connection 2016-05-27 13:16:09 +02:00
Olivier Lambert
b215e89572 fix(vm): use Number component instead of Text for vCPU max number edition 2016-05-27 10:18:18 +02:00
Julien Fontanet
07a7e8cf0a feat(selectors/createPager): n can be a selector as well 2016-05-27 10:04:17 +02:00
Olivier Lambert
52000edd7d feat(vm): handle correctly suspended VMs 2016-05-27 09:58:53 +02:00
ABHAMON Ronan
3e4c07c86f feat(self-service): dashboard and management (#992) 2016-05-26 18:20:09 +02:00
Olivier Lambert
92ce69c603 feat(meter): style (#994) 2016-05-26 17:06:01 +02:00
Olivier Lambert
a338e0a3f1 fix(tags): clashing component names tags/xo-tags/label 2016-05-26 13:50:56 +02:00
Fabrice Marsaud
143e09b65f feat(settings): remote management (#975) 2016-05-26 11:46:22 +02:00
Olivier Lambert
e5cc5abdc9 feat(theme) (#978) 2016-05-26 10:31:49 +02:00
Fabrice Marsaud
dfc96ebb99 feat(xo-app): Open Source disclaimer (#972) 2016-05-26 10:24:28 +02:00
Julien Fontanet
9397d0121d perf(select-objects/SelectVm): improve connectStore 2016-05-25 18:33:11 +02:00
Julien Fontanet
d8a1f3c73a feat(home): auto open pools/hosts selects 2016-05-25 13:07:15 +02:00
Julien Fontanet
a07cb425a4 fix(form/Range): uncontrolled therefore value → defaultValue 2016-05-25 13:07:15 +02:00
Julien Fontanet
a89b33dfdf chore(host): _isRunning is a property 2016-05-25 13:07:15 +02:00
Olivier Lambert
486d33448b feat(host): toggle and other improvements in advanced tab 2016-05-25 12:06:33 +02:00
Julien Fontanet
2299d397cb feat(messages): possibility to add props to the FormattedMessage 2016-05-25 11:04:53 +02:00
Julien Fontanet
0173c4709f fix(settings/server): password edition 2016-05-25 11:04:53 +02:00
Olivier Lambert
42fdf8b61f feat(form): boolean toggle (#985) 2016-05-25 11:04:21 +02:00
Greenkeeper
0253723652 chore(package): update ava to version 0.15.0 (#987)
https://greenkeeper.io/
2016-05-25 09:58:59 +02:00
Olivier Lambert
5ca51d3510 feat(vm): edition of number of CPUs (#984) 2016-05-24 18:00:06 +02:00
Julien Fontanet
466dc0127d fix(xo): subscriptions wait for sign in 2016-05-24 17:52:04 +02:00
Julien Fontanet
32f610485c fix(editable): anything can be used as children 2016-05-24 17:42:20 +02:00
Olivier Lambert
429e1b54ee feat(vm): edition in advanced tab (#983) 2016-05-24 16:51:50 +02:00
ABHAMON Ronan
268c037487 feat(select-objects): connected to store and accept an optional predicate (#981) 2016-05-24 15:45:28 +02:00
Julien Fontanet
c146f3105e fix(host/stats): remove unused import 2016-05-24 15:09:21 +02:00
Julien Fontanet
81e0c04722 feat(messages): a render function can be passed 2016-05-24 14:44:57 +02:00
Olivier Lambert
5d156695d2 feat(vm): memory limits (#980) 2016-05-24 12:55:35 +02:00
Julien Fontanet
f71438347c feat(selectors/createGetObjectsOfType): add groupBy() method 2016-05-24 12:41:17 +02:00
Pierre Donias
a3081d607f fix(Editable/Text): use value instead of children since children is not required (#982) 2016-05-24 12:06:38 +02:00
Julien Fontanet
ca81f445b9 fix(selectors/createTags): more complete stub 2016-05-24 11:56:24 +02:00
Olivier Lambert
1c22ce6d76 feat(home): add bold for select sort option (#979) 2016-05-24 11:07:05 +02:00
Pierre Donias
a0d482ba88 feat(Editable): Size component (#966) 2016-05-24 10:13:51 +02:00
Pierre Donias
0c050cc053 feat(SingleLineRow): columns are centered vertically (#973) 2016-05-24 10:12:17 +02:00
Olivier Lambert
9645d624f2 fix(messages): typo on number 2016-05-23 19:14:56 +02:00
Julien Fontanet
f29cb94d9f fix(selectors/createPicker): typo 2016-05-23 17:37:21 +02:00
Julien Fontanet
e239206626 feat(selectors): hide all objects to non admins 2016-05-23 17:25:28 +02:00
Julien Fontanet
35d1065eaf feat(menu): Sign out 2016-05-23 17:25:08 +02:00
Julien Fontanet
8384d6f9d7 fix(messages): vars must be explicitely marked as number 2016-05-23 17:20:25 +02:00
Julien Fontanet
5b3282ba51 perf: major rework of reducers and selectors (#976) 2016-05-23 16:29:23 +02:00
Olivier Lambert
bd1043f034 feat(home): add more bulk actions (#974) 2016-05-23 13:47:12 +02:00
Julien Fontanet
c847dcec15 fix(vm/general): remove test icon 2016-05-21 13:53:15 +02:00
Julien Fontanet
f66994f0b5 fix({host,vm}/console): better display when no stats available 2016-05-21 13:45:01 +02:00
Julien Fontanet
eba27f1823 fix(backup/new): use standard icon on save button 2016-05-21 13:45:01 +02:00
Julien Fontanet
ad1bbb2a00 fix(utils/osFamily): behaves if osName is undefined 2016-05-21 13:45:01 +02:00
Julien Fontanet
42506ab37d chore: rationalize whitespace usage 2016-05-21 13:45:01 +02:00
Julien Fontanet
6bae33826d chore(icons): always use Icon 2016-05-21 13:44:56 +02:00
Julien Fontanet
914c2b89c5 feat(icons): keep using Linux icon for CoreOS 2016-05-21 13:42:47 +02:00
Olivier Lambert
e79926cf29 fix(vm): check if vm.addresses exists 2016-05-21 13:09:40 +02:00
Olivier Lambert
1f15d2c736 fix(vm): i18n shorter button names 2016-05-21 13:03:37 +02:00
Olivier Lambert
fadd27fd23 fix(vm): better display when tools not present (#968) 2016-05-21 13:02:44 +02:00
Julien Fontanet
d5aeb8db55 feat(icons): add CoreOS 2016-05-21 12:02:23 +02:00
Pierre Donias
d5dbdd9986 fix(home): fix false icon attribute in Icon (#967) 2016-05-20 18:19:49 +02:00
Pierre Donias
352c977dc7 feat(home): add tick next to current sort criteria in dropdown (#965) 2016-05-20 16:55:04 +02:00
Julien Fontanet
bf008eba99 style(home): remove double line breaks 2016-05-20 16:29:54 +02:00
Pierre Donias
76b7777fff feat(Menu): collapses when window width is small (#963) 2016-05-20 16:28:12 +02:00
Julien Fontanet
9292d990da fix(home): behaves if filter is null 2016-05-20 15:15:47 +02:00
Julien Fontanet
87fe715823 fix(icons): add generic Linux icon 2016-05-20 12:31:11 +02:00
Julien Fontanet
25e32e0600 chore(icons): remove fixed width 2016-05-20 12:31:10 +02:00
Julien Fontanet
41c901a05c fix(complex-matcher/addPropertyClause): fix when enclause in a and 2016-05-20 11:44:04 +02:00
Julien Fontanet
fdaba2faf4 chore(home): pagination handling more standard 2016-05-20 11:44:04 +02:00
Julien Fontanet
0c73ad4f46 fix(complex-matcher): execute() requires node as context 2016-05-20 09:30:02 +02:00
Julien Fontanet
36c44bc3d4 feat(complex-matcher): addPropertyClause() 2016-05-19 18:13:51 +02:00
Julien Fontanet
d612598bd0 feat(complex-matcher): execute() and toString() expects current node as context 2016-05-19 18:13:51 +02:00
Julien Fontanet
2d75b6086f chore(complex-matcher/parse): refactor 2016-05-19 18:13:51 +02:00
Julien Fontanet
3345674604 chore(complex-matcher): expose node creators 2016-05-19 18:13:51 +02:00
Julien Fontanet
1eeaeeeca5 feat(benchmarks): complex matcher parsing 2016-05-19 18:13:51 +02:00
Olivier Lambert
b0bea8b3ba feat(vm/host): add links to host and pools 2016-05-19 18:10:00 +02:00
Olivier Lambert
0e3e5edd17 fix(host): wrong function name for log deletion 2016-05-19 16:47:57 +02:00
Olivier Lambert
ec1287a2f4 fix(multiple views): missing rows 2016-05-19 16:47:27 +02:00
Pierre Donias
9d2c857c59 feat(Text): placeholder prop (#961) 2016-05-19 14:34:25 +02:00
Pierre Donias
077f4f201c fix(grid): vertically center Col inside Row (#962) 2016-05-19 14:33:59 +02:00
Pierre Donias
9a2154a2ce feat(editable): editable Select (#959) 2016-05-19 12:58:43 +02:00
Olivier Lambert
f4c111c1c2 fix(home): a bit better responsive things 2016-05-18 17:18:53 +02:00
Pierre Donias
9483a06e8a feat(Text): Long click to edit with prop useLongClick (#957) 2016-05-18 13:31:15 +02:00
Olivier Lambert
df2a90dc1d fix(xo): wrong parameter name 2016-05-18 12:44:43 +02:00
Pierre Donias
246c190ccd fix(home): collapse-all button should not be hidden by action buttons. (#956) 2016-05-18 11:25:07 +02:00
Pierre Donias
4640817a14 feat(home): VMs migration (#953) 2016-05-18 10:59:24 +02:00
Pierre Donias
9c7690d39b fix(home): remove useless ref on VmItem (#954) 2016-05-17 17:46:29 +02:00
Pierre Donias
160805af05 feat(home): bulk actions (#948) 2016-05-17 16:16:03 +02:00
ABHAMON Ronan
39e85730f0 feat(plugins): new page to configure plugins (#946) 2016-05-17 15:42:10 +02:00
Olivier Lambert
da692e1a92 feat(home): sort by (#950) 2016-05-17 15:33:03 +02:00
Julien Fontanet
23bc60f1ac feat(selectors/createSort): any input can be a selector 2016-05-17 12:21:32 +02:00
Julien Fontanet
ce0f759509 chore(store/actions/createAction): do not add payload if undefined 2016-05-17 10:53:27 +02:00
Julien Fontanet
1793e5943a chore(store/actions/createAction): remove unused promises handling 2016-05-17 10:52:59 +02:00
Julien Fontanet
201b5db155 chore(BaseComponent): inline env test because it was not prune from the build 2016-05-17 10:12:45 +02:00
Olivier Lambert
c588ac6777 fix(backup): unknown schedule typo in translation 2016-05-16 18:23:35 +02:00
Julien Fontanet
28c01fd4e1 feat(messages): throw an error when a message is undefined 2016-05-16 18:19:27 +02:00
Julien Fontanet
0715e7a31f feat(ISSUE_TEMPLATE): copied from next-release 2016-05-16 16:33:20 +02:00
Julien Fontanet
b497c38e34 feat(ActionButton): prints handler errors 2016-05-16 15:55:55 +02:00
Julien Fontanet
8a08dce405 chore(sr/TabAdvanced): remove unused imports 2016-05-16 15:55:15 +02:00
Julien Fontanet
a620c348bf fix(Menu): always update to avoid issues with router and intl 2016-05-16 15:55:15 +02:00
Julien Fontanet
fe750b7270 chore(*/TabLogs): avoid creating function in render() 2016-05-16 15:55:15 +02:00
Julien Fontanet
4aa9d56dfc fix(home/TabGeneral): use key prop on correct component 2016-05-16 15:55:15 +02:00
Julien Fontanet
4b2ebf2a3a chore: use handlerParam prop everywhere 2016-05-16 15:55:15 +02:00
Julien Fontanet
6290446ea5 chore(dashboard/health): remove unused forEach import 2016-05-16 15:55:15 +02:00
Julien Fontanet
42f5d06960 chore(*/ActionBar): use param prop 2016-05-16 15:55:14 +02:00
Julien Fontanet
85e8006137 chore(dashboard/health): use ActionRowButton handlerParam prop 2016-05-16 15:55:14 +02:00
Julien Fontanet
7c29d4c644 fix(dashboard/health): adapt to modal/confirm changes 2016-05-16 15:55:14 +02:00
Julien Fontanet
7378bc852d feat(xo): deleteSr() 2016-05-16 15:55:14 +02:00
Julien Fontanet
67ed137cfa feat(xo): add confirm to convertVmToTemplate and deleteVm 2016-05-16 15:55:14 +02:00
Julien Fontanet
02e08e54a2 feat(TabButton): forward all props to ActionButton 2016-05-16 15:55:14 +02:00
Julien Fontanet
6b2dd24334 feat(modal/confirm): now expects an object param 2016-05-16 15:55:14 +02:00
Julien Fontanet
131d5becad feat(ActionBar): add param prop to inject as handlerParam 2016-05-16 15:55:14 +02:00
Julien Fontanet
157e0a83b1 feat(ActionButton): accept an handlerParam prop
It makes it easier to use without having to create new functions
everywhere (which can cause perf issues).
2016-05-16 15:55:14 +02:00
Julien Fontanet
d0d3abce3e chore(*/ActionBar): remove incorrect handlers prop 2016-05-16 15:55:14 +02:00
Julien Fontanet
b965c41a45 fix(ActionBar): do not keep recreating style prop 2016-05-16 15:55:14 +02:00
Julien Fontanet
42f824e034 fix(vm): do not show 0 snapshots 2016-05-16 15:55:14 +02:00
Olivier Lambert
2768d9d49d fix(pool patch): incorrect key for translation 2016-05-16 15:52:12 +02:00
Olivier Lambert
c9a86dcae3 feat(host): link to SRs 2016-05-16 15:40:57 +02:00
ABHAMON Ronan
e1d307ea2c feat(home): implement objects selection for filtering (#943) 2016-05-16 12:59:34 +02:00
Olivier Lambert
98ece12ae8 fix(home): number of VMs per page to 20 2016-05-16 10:40:34 +02:00
Olivier Lambert
4cf3db7c2a fix(vm disks): check if VBD has VDIs 2016-05-16 10:37:55 +02:00
Julien Fontanet
7c2f79d980 chore(Vm): move some logic in the tabs 2016-05-16 01:18:54 +02:00
Julien Fontanet
fe064f8b6a feat(utils/@checkPropsState): create an optimized shouldComponentUpdate() 2016-05-16 00:44:15 +02:00
Julien Fontanet
2bad2f6b80 perf(BaseComponent): do not use splat and spread params in constructor 2016-05-16 00:42:20 +02:00
Julien Fontanet
2ba9c5193f chore(Home): use VMS_PER_PAGE constant 2016-05-16 00:16:33 +02:00
Julien Fontanet
331695c10a fix(Tooltip): put tooltip above other components 2016-05-16 00:04:31 +02:00
Julien Fontanet
f299193f05 chore(Menu): cleanup and minor optimization 2016-05-16 00:03:55 +02:00
Julien Fontanet
de8130abc2 feat(selectors/_id): use id prop when no routeParams 2016-05-15 23:55:50 +02:00
Julien Fontanet
1cbde7f2e1 chore(XoApp): inherits from BaseComponent 2016-05-15 23:51:15 +02:00
Julien Fontanet
d1c796d9a7 chore(XoApp): unnecessary to validate children prop 2016-05-15 23:50:33 +02:00
Julien Fontanet
af43061353 chore(XoApp): remove unused connectStore() 2016-05-15 23:50:07 +02:00
Olivier Lambert
1b2ca8e69e 4.16.1 2016-05-14 11:18:16 +02:00
Olivier Lambert
a9e6679b08 fix(vm view): filter perms on all SR. Fix #945 2016-05-14 11:17:43 +02:00
Olivier Lambert
9408760122 chore(host,sr): style fixes 2016-05-14 11:02:26 +02:00
Olivier Lambert
c25e804d61 fix(home): use link for quick actions 2016-05-14 10:34:59 +02:00
Olivier Lambert
b18b2262eb vdi map 2016-05-14 00:12:56 +02:00
Olivier Lambert
570440dc7d host memory bar 2016-05-13 23:12:04 +02:00
Olivier Lambert
aef660fb2f feat(pool): sr view (#944) 2016-05-13 19:50:02 +02:00
Julien Fontanet
17671c7282 feat(selectors/createGetObjects): ignore missing objects 2016-05-13 17:38:38 +02:00
Julien Fontanet
8216ab44b4 feat(selectors): expose createSelector as its usually the name we want 2016-05-13 17:38:34 +02:00
Julien Fontanet
5902d43a94 fix(xo): fix internal createSubscription() 2016-05-13 17:20:12 +02:00
Pierre Donias
a6eb04d3f9 feat(home): VMs pagination (#940) 2016-05-13 17:15:45 +02:00
Julien Fontanet
a71780e860 chore(xo/subscribe): split into independant functions 2016-05-13 17:14:30 +02:00
Julien Fontanet
c2d815ef66 perf(selectors/objects): avoid creating empty objects 2016-05-13 17:11:34 +02:00
Julien Fontanet
bf4679aa9b perf(modal): do not create functions in render 2016-05-13 17:10:16 +02:00
Julien Fontanet
4dd74bbb16 perf(react-novnc): do not create functions in render 2016-05-13 17:10:13 +02:00
Julien Fontanet
10530146ca chore(selectors): remove unused vmContainers 2016-05-13 16:59:30 +02:00
Julien Fontanet
75d49da3d4 fix(home): correctly set filter in input field 2016-05-13 16:43:32 +02:00
Julien Fontanet
af026b0c52 perf(home): let VmItem fetch its container 2016-05-13 16:43:32 +02:00
Julien Fontanet
bcd4f70d0e perf(selectors/createGetObject): simplify 2016-05-13 16:43:32 +02:00
Olivier Lambert
54cc31d1a0 feat(pool): pool view (#933) 2016-05-13 15:26:26 +02:00
ABHAMON Ronan
3f0553861a feat(select-objects): split out XO select logic in low level components (#939) 2016-05-13 14:33:22 +02:00
Julien Fontanet
e1b3c51d2c fix(home): fix expand all button 2016-05-13 14:27:13 +02:00
Julien Fontanet
58a0e3fad6 fix(home): correctly set default filter 2016-05-13 14:26:54 +02:00
Julien Fontanet
6bb235650a chore(home): extract _saveFilter() 2016-05-13 12:07:50 +02:00
Julien Fontanet
0bf0bc4c33 chore(scheduling): remove an incorrect FIXME 2016-05-13 09:43:12 +02:00
Julien Fontanet
3085749e92 chore(Notification): minor optimizations 2016-05-12 21:12:03 +02:00
Julien Fontanet
de3abbf6b8 chore(host): minor optimizations 2016-05-12 21:08:12 +02:00
Julien Fontanet
925469689f chore(scheduling): implement components on top of BaseComponent 2016-05-12 20:50:06 +02:00
Julien Fontanet
631e58a585 chore(form): implement components on top of BaseComponents 2016-05-12 20:42:25 +02:00
Julien Fontanet
63571d06bf chore(editable/Text): implement on top of BaseComponent 2016-05-12 20:38:04 +02:00
Julien Fontanet
1979758fab chore(ActionButton): implement on top of BaseComponent 2016-05-12 20:35:51 +02:00
Julien Fontanet
6ef5a23000 chore(vm): minor optimizations 2016-05-12 20:35:48 +02:00
Julien Fontanet
ae4aa23d27 chore(Tags): clean & optimize 2016-05-12 20:29:46 +02:00
Julien Fontanet
710d1f13cd feat(BaseComponent): React component with reasonable defaults & debugging traces 2016-05-12 20:29:43 +02:00
Julien Fontanet
57a4d366d7 chore(shallow-equal): split out of selectors 2016-05-12 17:52:30 +02:00
Julien Fontanet
8060c66c08 feat(home): put the filter in the URL 2016-05-12 17:23:50 +02:00
Julien Fontanet
d5a58fbec2 perf(home): do not create functions in render 2016-05-12 16:15:53 +02:00
Julien Fontanet
059256de3e chore(home): simplify by treating no VMs case first 2016-05-12 15:50:54 +02:00
Julien Fontanet
2c52d4c867 feat(utils/firstDefined) 2016-05-12 15:50:54 +02:00
Julien Fontanet
d9bfde2e47 chore(selectors): use props.routeParams instead of props.params 2016-05-12 15:50:54 +02:00
ABHAMON Ronan
757acd8d92 fix(backups): remoteId vs remote param name(#938) 2016-05-12 14:52:31 +02:00
Pierre Donias
3e92252e2e fix(BlockLink): correctly behaves with links/buttons/inputs (#934) 2016-05-12 13:21:00 +02:00
ABHAMON Ronan
ce7aeb1a27 chore(Scheduler): use react-intl for month names translation (#935) 2016-05-12 13:13:43 +02:00
ABHAMON Ronan
236d2ad39a feat: backups overview (#932) 2016-05-12 13:04:15 +02:00
Julien Fontanet
63b37714b1 chore(page): use number for plain numeric styles 2016-05-12 11:53:06 +02:00
Julien Fontanet
dc81fd0622 chore(style): remove unused .xo-icon-action-row styles 2016-05-12 11:52:45 +02:00
Julien Fontanet
ccec2bf7ee chore(ActionRow): renamed to ActionRowButton 2nd pass 2016-05-12 11:51:48 +02:00
Julien Fontanet
c93b93331e chore(ActionRow): renamed to ActionRowButton 2016-05-12 11:31:43 +02:00
Julien Fontanet
1f194f1680 chore(ActionRow): reimplemented on top of ActionButton 2016-05-12 11:29:54 +02:00
Julien Fontanet
2251123c1d perf(invoke): minor optim when no param 2016-05-12 11:17:23 +02:00
Julien Fontanet
1bfe1c3370 chore(complex-matcher/parse): rename pattern to input 2016-05-12 11:17:23 +02:00
Olivier Lambert
0044eeb6d1 chore(health): use components and remove useless arrays 2016-05-12 09:52:55 +02:00
Olivier Lambert
669302d46b regain focus on the search field 2016-05-11 18:54:25 +02:00
Olivier Lambert
fce2f44197 feat(home): pre-existing filters (#931) 2016-05-11 18:06:45 +02:00
Pierre Donias
64db1df248 feat(user): new user page (#930) 2016-05-11 17:14:49 +02:00
Olivier Lambert
9109d55019 new VM button working on home view 2016-05-11 16:31:09 +02:00
Olivier Lambert
412e13ccd5 better header content style 2016-05-11 16:25:08 +02:00
Olivier Lambert
0c7e0528b6 better patches refresh when installing a patch 2016-05-11 15:49:13 +02:00
Pierre Donias
ccb22a2f40 chore(Page): remove unnecessary component Header (#928) 2016-05-11 15:48:40 +02:00
Pierre Donias
2f3e463aca feat: move tabs in header for host and VM views (#927)
Fixes #926
2016-05-11 15:13:12 +02:00
Olivier Lambert
c548e08aea react component usage for action buttons in rows 2016-05-11 15:02:19 +02:00
ABHAMON Ronan
150e0171f0 feat: initial VM backups view (#924) 2016-05-11 14:27:58 +02:00
Olivier Lambert
bfcaca7bc0 tab button for VM view 2016-05-11 12:17:30 +02:00
Olivier Lambert
fcb0482193 use TabButton component in host view 2016-05-11 12:02:50 +02:00
Olivier Lambert
714ea7c236 a bit better home responsive view 2016-05-11 11:29:15 +02:00
Pierre Donias
cc30799f0d feat: browser notifications (#921)
* Browser notifications.

* Browser notifications: XO logo in notification.

* Browser notifications: multiple enhancements.
2016-05-11 11:13:08 +02:00
Pierre Donias
df71259a10 style: removed incorrect JSX whitespaces (#925) 2016-05-11 10:36:55 +02:00
Olivier Lambert
9a0ae5d4b9 quick buttons for home view 2016-05-10 16:26:30 +02:00
Olivier Lambert
eea4648ada add docker icon for VM with docker XS plugin installed 2016-05-10 14:27:11 +02:00
Olivier Lambert
2883398c2a add modal for VM convert and delete 2016-05-10 14:17:47 +02:00
Olivier Lambert
84f6e14b89 display the number of snapshot in the expanded home VM view 2016-05-10 13:53:29 +02:00
Pierre Donias
30fb9ed65a feat(modal): alert() and confirm() methods (#918) 2016-05-10 12:00:48 +02:00
Olivier Lambert
a809f2d1f2 re add install all patches in host patch tab 2016-05-10 10:53:35 +02:00
Olivier Lambert
6b5a19983d missing translation in server view 2016-05-09 19:41:36 +02:00
Olivier Lambert
2471f447b3 add current status info for VMs 2016-05-09 17:18:44 +02:00
Julien Fontanet
413e944d7a fix(home): fix imports 2016-05-09 13:46:20 +02:00
Julien Fontanet
3b952819d6 feat(home): remember the last used filter 2016-05-09 13:41:06 +02:00
Greenkeeper
2445c10c1c chore(package): update modular-css to version 0.21.0 (#920)
https://greenkeeper.io/
2016-05-09 11:46:00 +02:00
Julien Fontanet
7e26593d04 feat(complex-matcher): quoted strings 2016-05-08 17:53:34 +02:00
Greenkeeper
73595c683b chore(package): update modular-css to version 0.20.0 (#919)
https://greenkeeper.io/
2016-05-08 10:02:02 +02:00
Julien Fontanet
570f56a4cc chore(complex-matcher): test parse() and toString() 2016-05-08 00:25:16 +02:00
Julien Fontanet
f9e940871e feat(home): add group/or syntax 2016-05-08 00:24:32 +02:00
Julien Fontanet
c2b724a54a chore(test): add AVA test runner 2016-05-08 00:21:58 +02:00
Olivier Lambert
f52db472ed clear search button 2016-05-07 17:52:17 +02:00
Julien Fontanet
324fe98a5b chore(complex-matcher): minor parser simplification 2016-05-07 17:32:25 +02:00
Julien Fontanet
2fd9833580 chore(complex-matcher): move into its own module 2016-05-07 17:25:44 +02:00
Olivier Lambert
0ab4827d6f default search value with a space and search autofocus 2016-05-07 17:19:42 +02:00
Julien Fontanet
f0bd7d7eee perf(home): debounce filter by 250ms 2016-05-07 17:02:55 +02:00
Olivier Lambert
8cd1209602 display OS icon if possible, even when we do not detect xen tools 2016-05-07 16:57:04 +02:00
Julien Fontanet
e2781adc81 feat(home): allow search on nested properties 2016-05-07 16:49:45 +02:00
Julien Fontanet
b91ac2fe89 feat(home): initial complex filter 2016-05-07 16:16:22 +02:00
Julien Fontanet
683a7a1851 perf(selectors/tags): sort the tags and wraps the selector 2016-05-07 13:11:28 +02:00
Olivier Lambert
8b05aa7b59 remove useless array 2016-05-07 13:00:41 +02:00
Olivier Lambert
883f839bfd action for servers 2016-05-07 12:55:22 +02:00
Julien Fontanet
90dc00ac6b perf: throttle object updates by 500ms 2016-05-07 12:51:41 +02:00
Julien Fontanet
9c1cecbb7d chore(dev-tools): disable for now
It's not used at the moment and it has an major perf impact.
2016-05-07 12:05:19 +02:00
Julien Fontanet
1fce11bfba chore(store): do not add useless enhancers 2016-05-07 12:05:19 +02:00
Olivier Lambert
fba3ebdf49 basic filtering in home view 2016-05-07 11:34:05 +02:00
Olivier Lambert
e9585e08a4 only count pending tasks 2016-05-07 00:50:37 +02:00
Olivier Lambert
24a89985fb remove useless icon in vm general tab 2016-05-06 22:20:18 +02:00
Olivier Lambert
33026e8281 more logical order display for the home view 2016-05-06 21:23:54 +02:00
Olivier Lambert
50d9b832a9 better tag component 2016-05-06 21:14:54 +02:00
Olivier Lambert
1df82c3380 do not display a filter if there isn't any object associated with it (ACLs or nothing to display) 2016-05-06 18:59:57 +02:00
Olivier Lambert
0a8db4ebbf object number for filters 2016-05-06 18:39:44 +02:00
Julien Fontanet
928b19aef4 chore(TabButton): move into its own module 2016-05-06 17:48:53 +02:00
Julien Fontanet
a7ec98cef6 chore(icons): move into its own stylesheet 2016-05-06 17:46:13 +02:00
Julien Fontanet
67326a1859 chore(button): remove unused module 2016-05-06 17:33:30 +02:00
Julien Fontanet
631a8a5edf fix(ActionButton): fixed width icon 2016-05-06 17:32:40 +02:00
Julien Fontanet
7e5e463ef2 feat(ActionButton): better feedback on async actions 2016-05-06 17:20:53 +02:00
Julien Fontanet
add65e41da chore(actions): move business code in xo 2016-05-06 17:20:48 +02:00
Julien Fontanet
351b4571cd chore(store): move into common 2016-05-06 17:18:56 +02:00
Julien Fontanet
793258a91f chore(dev-tools): move into common 2016-05-06 17:18:56 +02:00
Julien Fontanet
ed3e1933c3 fix(xo): names of VM clones and snapshots 2016-05-06 17:18:56 +02:00
Olivier Lambert
2f63b26458 use react boostrap button component 2016-05-06 16:56:52 +02:00
Olivier Lambert
f1d14da3dd UI improvements on home view 2016-05-06 16:03:49 +02:00
Pierre Donias
4a3d90bdf3 feat(notification): new module (#914)
* Notifications

* Notification: global notification fired by `notify(...)`

* Notification: Bootstrap colors.

* Notification: Simplified version. Usage example.
2016-05-06 14:27:59 +02:00
Olivier Lambert
f8f24fbc37 feat(home view): major rework 2016-05-06 14:26:30 +02:00
Pierre Donias
8f6c53e111 feat(Modal): new component (#916) 2016-05-06 14:04:38 +02:00
Pierre Donias
c23f55b1d4 feat(Wizard): new component (#896) 2016-05-06 13:41:05 +02:00
Olivier Lambert
88f94f5d6f improved XO title in menu collapse 2016-05-04 21:07:58 +02:00
Olivier Lambert
3e99a179b7 add tool tip for action bar 2016-05-04 11:56:13 +02:00
Olivier Lambert
c7271f94a5 remove xo call for vdi and sr set 2016-05-04 10:46:43 +02:00
Olivier Lambert
5c0ced942c fix tags 2016-05-03 18:41:55 +02:00
Julien Fontanet
d9b07e76f9 chore(package): update standard to version 7.0.0 2016-05-03 18:31:15 +02:00
Julien Fontanet
c75793df20 chore(package): use commit-msg hook instead of commit-msg
It avoids running the tests when there is nothing in the stage.
2016-05-03 18:28:08 +02:00
Julien Fontanet
1bee5121f0 chore(package): remove unused Babel config 2016-05-03 18:28:08 +02:00
Julien Fontanet
932e7eb374 chore(README): remove dependencies status 2016-05-03 18:28:08 +02:00
Julien Fontanet
abdbcfe42b chore(README): add Travis status in title 2016-05-03 18:28:08 +02:00
Julien Fontanet
a62e888732 chore(gitignore): remove unused config.json entry 2016-05-03 18:28:08 +02:00
Olivier Lambert
16b982b953 fix patches issues 2016-05-03 18:25:33 +02:00
Olivier Lambert
e92b87095b container for header 2016-05-03 17:37:42 +02:00
Olivier Lambert
e5f1aa689b flex shrink fix 2016-05-03 17:35:59 +02:00
Olivier Lambert
f39a05cd8d smaller header for VM and host view 2016-05-03 16:42:32 +02:00
Olivier Lambert
c5e22b785a replace xo.call 2016-05-03 15:24:39 +02:00
Olivier Lambert
11f93a125c add header for host view 2016-05-03 15:22:25 +02:00
Pierre Donias
38a9cb002d Menu and sticky header (#891)
Fixes #705
2016-05-03 14:13:11 +02:00
ABHAMON Ronan
cf1a38a004 Recursive forms implementation. (#894) 2016-05-03 12:09:22 +02:00
Olivier Lambert
d6e823d19d fix missingpatches call 2016-05-03 10:24:30 +02:00
Olivier Lambert
763a23d9d0 add recoveryStartVm method 2016-05-01 11:19:58 +02:00
Olivier Lambert
f266577f2f fix cloneVM method 2016-05-01 11:00:49 +02:00
Olivier Lambert
1bb5e73668 less choices in VM action bar, advanced actions are in advanced tab 2016-05-01 10:39:26 +02:00
Olivier Lambert
b07bc755f6 add label on tab for number of patches missing 2016-05-01 09:57:05 +02:00
Olivier Lambert
db4b39c54b upgrade on poolpatches 2016-04-29 18:53:43 +02:00
Julien Fontanet
ffd95261c3 4.16.0 2016-04-29 12:23:59 +02:00
Olivier Lambert
82f38040c1 changelog 2016-04-29 12:22:14 +02:00
Olivier Lambert
7bb4f9f8e3 update host 2016-04-28 22:33:59 +02:00
Olivier Lambert
c2345df275 Merge pull request #905 from vatesfr/v5-toolbar-improved
V5 toolbar improved, missing patches and xo call removal
2016-04-28 19:15:46 +02:00
Olivier Lambert
b0c341da3f minor fixes 2016-04-28 19:11:56 +02:00
Olivier Lambert
b1ccc16da7 add missing patches 2016-04-28 19:11:44 +02:00
Julien Fontanet
16856a5911 feat(utils/routes): support plain route def 2016-04-28 17:32:06 +02:00
Olivier Lambert
d4ee364349 add host action bar 2016-04-28 17:03:11 +02:00
Olivier Lambert
db62ca7b4b proper col/row for vm tabs 2016-04-28 16:20:36 +02:00
Olivier Lambert
d0b99b854d remove more xo direct call 2016-04-28 15:57:17 +02:00
Olivier Lambert
b3b13b3e01 less xo calls 2016-04-28 15:55:46 +02:00
Julien Fontanet
5cb738b82b chore: reduce xo.call() direct use 2016-04-28 15:22:40 +02:00
Olivier Lambert
cfe3b15cbe Toolbar actions 2016-04-28 15:06:28 +02:00
Julien Fontanet
a1bde80925 chore: move IntlProvider inside XoApp. 2016-04-28 12:37:49 +02:00
Julien Fontanet
4c958dd584 chore(selectors): remove unused code 2016-04-28 12:05:37 +02:00
Olivier Lambert
a05d4d3d18 Merge pull request #892 from vatesfr/pierre-v5-better-action-bar-ui
Better action bar UI.
2016-04-28 10:28:05 +02:00
Pierre
503b6dc914 Dropdown on hover. 2016-04-28 09:24:29 +02:00
Pierre
141cbcd1c0 [WIP] Dropdown on hover. 2016-04-28 09:24:29 +02:00
Olivier Lambert
e340d2d3f5 remove useless import 2016-04-27 18:27:57 +02:00
Olivier Lambert
436d5a3a66 remove dup message keys 2016-04-27 18:27:57 +02:00
Julien Fontanet
3e04fd4790 feat: initial ACLs handling 2016-04-27 16:44:01 +02:00
Julien Fontanet
3f6d149f9d feat(reducer/combineActionHandlers): perf for n=1 & common errors
Warnings when:

- no handlers defined
- there is an handler for the action type `type` (likely an error)

There is now an optimized implementation when there is only one handler.
2016-04-27 16:44:01 +02:00
Olivier Lambert
977fc7832a initial network tab added for host 2016-04-27 15:23:39 +02:00
Olivier Lambert
2e2f0e2e3d handle basic log removal 2016-04-27 14:59:40 +02:00
Julien Fontanet
5628beee72 fix(selectors/createCollectionWrapper): handle removed props 2016-04-27 14:14:53 +02:00
Olivier Lambert
a88fea560b fix indentation 2016-04-26 18:14:37 +02:00
Olivier Lambert
5832345b96 Merge pull request #902 from vatesfr/v5-hosts
V5 hosts view
2016-04-26 15:57:32 +02:00
Olivier Lambert
d3d2daa12f use createFinder 2016-04-26 15:39:58 +02:00
Julien Fontanet
f6f90982f4 feat(selectors/createPager): selector creator to return a page of items 2016-04-26 15:36:21 +02:00
Olivier Lambert
98323b08f0 add host console 2016-04-26 15:31:13 +02:00
Olivier Lambert
8f3112a5e2 advanced tab completed 2016-04-26 15:31:12 +02:00
Olivier Lambert
3408bd41ad additionnal host info 2016-04-26 15:31:12 +02:00
Olivier Lambert
68e12e86c1 add start time in host view 2016-04-26 15:31:12 +02:00
Olivier Lambert
890e0b4906 add control domain VM 2016-04-26 15:31:12 +02:00
Olivier Lambert
3aca7c7ae5 more working host tabs 2016-04-26 15:31:11 +02:00
Olivier Lambert
e8077ddbc5 initial work on host view 2016-04-26 15:31:11 +02:00
Julien Fontanet
6e04907357 feat(selectors/createFinder): selector creator to find an item in a collection 2016-04-26 15:26:28 +02:00
Greenkeeper
3d8c9a99fe chore(package): update modular-css to version 0.18.0 (#895)
https://greenkeeper.io/
2016-04-20 08:05:43 +01:00
Greenkeeper
730768705b chore(package): update modular-css to version 0.17.1 (#890)
http://greenkeeper.io/
2016-04-19 10:04:12 +01:00
Julien Fontanet
13f75a37ab CSS: remove 60em min-width on .xo-content. 2016-04-18 15:58:43 +01:00
Julien Fontanet
f74c69ea6f Disable Bootstrap flex for now as it is broken in responsive mode. 2016-04-18 15:57:56 +01:00
Greenkeeper
fe7be0f518 chore(package): update react-key-handler to version 0.2.0 (#886)
http://greenkeeper.io/
2016-04-18 09:33:30 +01:00
Olivier Lambert
2f0e656c45 menu: move remote in settings 2016-04-15 14:44:53 +02:00
Julien Fontanet
de489b799b Fix npm run build. 2016-04-14 19:12:25 +02:00
Julien Fontanet
6250ef49b6 Minor change in VM/Snapshots. 2016-04-14 19:12:25 +02:00
Julien Fontanet
afdab8dcde Fix About page. 2016-04-14 19:12:25 +02:00
Olivier Lambert
8e1d39f37f navbar style 2016-04-14 18:45:18 +02:00
Julien Fontanet
2a8c346a65 Add basic Page not found. 2016-04-14 18:06:56 +02:00
Olivier Lambert
71e431e744 better dashboard 2016-04-14 17:45:00 +02:00
Julien Fontanet
265cb75d70 Dashboard/Overview: 10 top SRs by size. 2016-04-14 16:51:29 +02:00
Olivier Lambert
4d0470838a move storage list to health 2016-04-14 16:41:05 +02:00
Olivier Lambert
d4ed3aeac0 better dashboard 2016-04-14 16:14:35 +02:00
Julien Fontanet
89fa89fe98 utils/@routes(): TODO add support for function childRoutes. 2016-04-14 16:02:05 +02:00
Julien Fontanet
2d663f0ac5 Remove unused import. 2016-04-14 15:58:38 +02:00
Julien Fontanet
bc9b3f1c5c utils/@routes(): accepts a plain object for child routes. 2016-04-14 15:48:38 +02:00
Julien Fontanet
2f0a46a46d utils/@routes(): use it AMAP. 2016-04-14 15:45:27 +02:00
Julien Fontanet
9559604d1e menu: Remove home special case. 2016-04-14 15:45:27 +02:00
Julien Fontanet
b779ab9bc5 utils/@routes(): accepts a subpath as index route. 2016-04-14 15:45:26 +02:00
Julien Fontanet
481943051c Tooltip component. 2016-04-14 15:45:26 +02:00
Olivier Lambert
cb49b7a906 fix styles 2016-04-14 11:55:14 +02:00
Olivier Lambert
090e4b3117 working health view 2016-04-14 10:35:58 +02:00
Olivier Lambert
9a40d5f784 style fixes 2016-04-13 19:49:59 +02:00
Olivier Lambert
1485637c6d more dashboard work 2016-04-13 17:52:54 +02:00
Olivier Lambert
b0ec8e26e8 sr table on dashboard 2016-04-13 13:53:01 +02:00
Olivier Lambert
e4c12e08cb sr panel on dashboard view 2016-04-13 12:55:24 +02:00
Olivier Lambert
a1675745b5 first charts on Dashboard view 2016-04-13 12:23:38 +02:00
Olivier Lambert
40beb5b104 dashboard work 2016-04-13 11:26:07 +02:00
Olivier Lambert
e49e2f51c2 more work on dashboard 2016-04-12 22:57:45 +02:00
Olivier Lambert
99669f2678 add missing files 2016-04-12 19:03:40 +02:00
Olivier Lambert
9aa88b9dad initial work on dashboard 2016-04-12 19:02:53 +02:00
Julien Fontanet
10de29795a settings/servers: implement edition. 2016-04-12 18:49:25 +02:00
Julien Fontanet
c4767e74f4 Initial server view. 2016-04-12 18:16:07 +02:00
Julien Fontanet
19f8666e1e Use Babel transforms to optimize React in prod. 2016-04-12 18:16:07 +02:00
Julien Fontanet
2e2bbdf0d7 Update gulp-csso to v2. 2016-04-12 18:16:07 +02:00
Olivier Lambert
973bee0ffa fix links to submenus 2016-04-12 18:05:20 +02:00
Olivier Lambert
9470cdf774 better wording 2016-04-12 18:00:11 +02:00
Olivier Lambert
ab198ea60b add import entry 2016-04-12 17:56:59 +02:00
Olivier Lambert
c78f4bb6d2 add dashboard submenu 2016-04-12 17:47:38 +02:00
Olivier Lambert
ff054ca47f Add menu 2016-04-12 17:28:24 +02:00
Olivier Lambert
30cc804022 backup submenu 2016-04-12 17:13:35 +02:00
Olivier Lambert
890d733bf8 snapshot name edition 2016-04-12 15:19:05 +02:00
Olivier Lambert
a554a9c4a1 add editable vdi name and description 2016-04-12 15:16:40 +02:00
Olivier Lambert
9ef212937d log view style 2016-04-12 14:05:30 +02:00
Pierre Donias
82d9c53f3e Left side menu and navbar. (#869)
Merge PR #869 from @pdonias.
2016-04-08 18:34:20 +02:00
Julien Fontanet
d9d91c4953 Update react/react-dom to v15 and react-intl to v2. 2016-04-08 15:16:55 +02:00
Julien Fontanet
dd5f5282e0 Remove special uglify setting for Angular. 2016-04-07 17:44:53 +02:00
Julien Fontanet
cc116defc6 Remove unused browser override ws.js. 2016-04-07 17:44:00 +02:00
Julien Fontanet
90c755e120 Remove unused browserify-plain-jade. 2016-04-07 17:43:40 +02:00
Julien Fontanet
85d1c80581 Move common modules out of src/node_modules. 2016-04-07 15:03:14 +02:00
Julien Fontanet
5bb04d3857 reducers: Fix REMOVE_OBJECTS handling. 2016-04-07 15:03:13 +02:00
Olivier Lambert
dde8404242 fix average computing on sparkline graphs 2016-04-07 14:00:10 +02:00
Julien Fontanet
7940bd2dcc Merge pull request #858 from vatesfr/abhamonr-vm-stats-only-when-vm-running
Get stats only when vm running.
2016-04-07 13:45:30 +02:00
Julien Fontanet
da48d117a0 Merge pull request #872 from vatesfr/pierre-v5-vm-state-icon
VM: state icon in front of VM's name.
2016-04-07 10:16:23 +02:00
Pierre
ffc74967fc VM: State icon in front of VM's name 2016-04-07 10:12:46 +02:00
wescoeur
c7388d5836 Get stats only when vm running. 2016-04-06 16:24:31 +02:00
Julien Fontanet
ee4b8fc66f Merge pull request #868 from vatesfr/pierre-v5-add-multiple-tags
Tags: Adding a tag does not remove the input field
2016-04-06 15:41:55 +02:00
Julien Fontanet
c73f22ca45 home: refactor filtering on top of selectors/createFilter(). 2016-04-06 15:35:45 +02:00
Julien Fontanet
bafa053fd1 vm/logs: initial listing. 2016-04-06 14:55:44 +02:00
Pierre
a00406d2b3 Tags: Adding a tag should keep the input field on 2016-04-06 11:59:10 +02:00
Julien Fontanet
df91e17dc6 vm/disks: use more variables. 2016-04-06 11:01:05 +02:00
Julien Fontanet
7c6eeababc vm/disks: add SR name. 2016-04-06 10:52:34 +02:00
Julien Fontanet
911a5067f9 Factorize selectors. 2016-04-06 10:47:35 +02:00
Julien Fontanet
bfa0fe9c51 editable/Text: initial implementation. 2016-04-05 15:40:16 +02:00
Julien Fontanet
7dafe31d51 react-novnc: Ungrab keyboard/mouse on mouse leave. 2016-04-04 15:44:26 +02:00
Olivier Lambert
1271ecedb4 Merge pull request #859 from vatesfr/pierre-v5-icon-fixed-width
Icon: `fixedWidth` attribute
2016-04-01 19:17:50 +02:00
Pierre
80be18068f Icon: lodash/isInteger instead of Number.isInteger 2016-04-01 18:31:16 +02:00
Julien Fontanet
ecbf2c0958 utils/BlockLink: To use for a block link :) 2016-04-01 18:16:56 +02:00
Pierre
cfb84b677f Icon: fixedWidth attribute 2016-04-01 18:12:33 +02:00
Olivier Lambert
dfbd7a5d76 Merge pull request #857 from vatesfr/abhamonr-fix-select-vm-stats
Fix select vm stats.
2016-04-01 17:30:27 +02:00
wescoeur
8e157f8ff7 Fix select vm stats. 2016-04-01 17:16:04 +02:00
Olivier Lambert
c75580e852 style fixes 2016-04-01 17:03:21 +02:00
Olivier Lambert
e21934fd55 more work on VM advanced tab 2016-04-01 17:03:21 +02:00
Julien Fontanet
844f1609c8 utils/@autobind: bind a method at first call. 2016-04-01 17:00:03 +02:00
Julien Fontanet
6f7de28672 Vm/Console: disable for non-running VMs. 2016-04-01 16:42:27 +02:00
Olivier Lambert
247212d768 update advanced view 2016-04-01 16:31:11 +02:00
Olivier Lambert
6592b880ea reorder stuff 2016-04-01 16:31:11 +02:00
Julien Fontanet
e27a4bf119 Merge pull request #855 from vatesfr/abhamonr-vms-stats-stateful
Stateful component vms stats.
2016-04-01 16:29:23 +02:00
wescoeur
dce5a83093 Stateful component vms stats.
Delay of stats interval is used to get stats.
2016-04-01 16:26:01 +02:00
Julien Fontanet
78c70f35a1 Merge pull request #856 from vatesfr/pierre-v5-col-offset
Added offset management in `Col` component.
2016-04-01 16:25:26 +02:00
Pierre
f4b84a0902 Added offset management in Col component 2016-04-01 16:15:46 +02:00
Julien Fontanet
b16237b514 Vm/Stats: Fix translation of select. 2016-04-01 15:37:26 +02:00
Olivier Lambert
b0077539fa Merge pull request #854 from vatesfr/abhamonr-vms-charts-tooltips
Tooltips on vms charts.
2016-04-01 15:21:14 +02:00
Olivier Lambert
63602216eb using icon component 2016-04-01 14:38:58 +02:00
Olivier Lambert
2f93935009 more links 2016-04-01 14:30:21 +02:00
Olivier Lambert
c0a0b653c1 add links and fix icons 2016-04-01 14:25:41 +02:00
wescoeur
24d6354467 Tooltips on vms charts. 2016-04-01 13:03:02 +02:00
Julien Fontanet
54a07469fd Fix granularity on stats tab. 2016-04-01 12:49:55 +02:00
Olivier Lambert
12f37bead1 translate inside option 2016-04-01 12:42:55 +02:00
Olivier Lambert
8d76dc2511 tab styles 2016-04-01 12:01:52 +02:00
Olivier Lambert
8ef7d6defc more i18n 2016-04-01 11:49:35 +02:00
Olivier Lambert
2f2cbbe3f0 various improvements 2016-04-01 11:05:27 +02:00
Julien Fontanet
2662ac719b Fix tabs display. 2016-04-01 10:50:38 +02:00
Olivier Lambert
1b0fe6e847 center console 2016-04-01 10:29:04 +02:00
Olivier Lambert
9fa9e26324 disk tab 2016-04-01 10:25:56 +02:00
Julien Fontanet
cb434df099 Move prod deps to dev deps. 2016-04-01 10:21:04 +02:00
Julien Fontanet
e3cb3002fe Replace react-tabs with Bootstrap styles + router. 2016-04-01 10:21:00 +02:00
Olivier Lambert
8b2a09b522 better tag placement 2016-03-31 18:44:33 +02:00
Olivier Lambert
03265d2545 stats select translation 2016-03-31 18:10:16 +02:00
Olivier Lambert
9b25e07b5e sort tags and fix snapshot icon 2016-03-31 17:57:56 +02:00
Julien Fontanet
60a21ca58d Merge pull request #853 from vatesfr/abhamonr-vms-charts-time-labels
Intl labels on vms charts.
2016-03-31 17:52:05 +02:00
wescoeur
05172492ef Intl labels on vms charts. 2016-03-31 17:44:42 +02:00
Julien Fontanet
a9c089a994 Merge pull request #851 from vatesfr/pierre-v5-action-bar
VM action bar (without handlers) with react-bootstrap-4
2016-03-31 17:37:18 +02:00
Julien Fontanet
988d018c8e Merge pull request #852 from vatesfr/pierre-v5-fix-sparklines-proptype
Fixed Sparklines propType: array --> object
2016-03-31 17:35:53 +02:00
Pierre
853c611fde Fixed Sparklines propType: array --> object 2016-03-31 17:30:43 +02:00
Pierre
0886f5335f DropdownButton instead of SplitButton (custom width). 2016-03-31 17:22:00 +02:00
Pierre
024d481a4d Using react-bootstrap-4. VM action bar done (no handlers). Minor fixes. 2016-03-31 17:22:00 +02:00
Pierre
b80de1af95 ERR action-bar: DropdownButton incompatible with React 15 2016-03-31 17:21:59 +02:00
Julien Fontanet
da44268f0d ReactNoVnc: remove unnecessary logs. 2016-03-31 17:16:15 +02:00
Julien Fontanet
b921a3ed8e Split the VM view. 2016-03-31 17:15:23 +02:00
Julien Fontanet
d2c9c824f9 Declare routes directly on component. 2016-03-31 16:41:13 +02:00
Olivier Lambert
21c255051c better console panel style 2016-03-31 16:39:30 +02:00
Olivier Lambert
dccf09c5dd charts improvements 2016-03-31 16:12:57 +02:00
Julien Fontanet
0772a17e4c grid/Col: use xs for smallSize. 2016-03-31 15:21:26 +02:00
Olivier Lambert
644ee782d2 fix style issues 2016-03-31 15:11:40 +02:00
Olivier Lambert
ea180cc415 fix col sizes 2016-03-31 15:11:10 +02:00
Olivier Lambert
68e3c4e6ed change stats titles 2016-03-31 15:07:59 +02:00
Julien Fontanet
47b1c2d680 grid/Col: now expects smallSize, mediumSize or largeSize. 2016-03-31 15:07:32 +02:00
Olivier Lambert
2e513043b7 Merge pull request #850 from vatesfr/abhamonr-vms-graphs-titles
Abhamonr vms graphs titles
2016-03-31 14:16:40 +02:00
wescoeur
ea942635f7 VMs graphs titles. 2016-03-31 13:12:41 +02:00
wescoeur
8a5f5cc673 Display spinner icon when stats granularity is selected. 2016-03-31 12:51:29 +02:00
Julien Fontanet
6cc673035d Work around babel-eslint bug. 2016-03-31 11:36:42 +02:00
Olivier Lambert
02d717e5a8 better graph style 2016-03-31 11:35:12 +02:00
Julien Fontanet
77d83b06bd Merge pull request #848 from vatesfr/abhamonr-vm-stats-various-time-steps
Possibility to select time interval on vm stats.
2016-03-31 11:19:57 +02:00
wescoeur
e3d8eabb05 Possibility to select time interval on vm stats. 2016-03-31 11:16:49 +02:00
Julien Fontanet
0596b0106f Handle removeObjects action. 2016-03-30 18:07:40 +02:00
Julien Fontanet
765bbd90fc Install ghooks. 2016-03-30 18:01:51 +02:00
Julien Fontanet
3799902a8a More efficient sort of snapshots. 2016-03-30 17:43:42 +02:00
Julien Fontanet
ca1dbb4556 Initial VM console. 2016-03-30 17:37:37 +02:00
Julien Fontanet
df551d457c Merge pull request #847 from vatesfr/abhamonr-chartist-graphs
VM's graphs. (Chartist)
2016-03-30 16:57:17 +02:00
wescoeur
278d518d8f VM's graphs. (Chartist) 2016-03-30 16:53:20 +02:00
Olivier Lambert
b06fa191f7 prepare limit space in vm advanced tab 2016-03-30 16:02:34 +02:00
Olivier Lambert
13d73f6f27 add translations 2016-03-30 15:54:49 +02:00
Olivier Lambert
d59af117c0 start work of Advanced vm tab 2016-03-30 15:51:23 +02:00
Olivier Lambert
69efd85ad6 check if VBD is a cd drive 2016-03-30 12:33:54 +02:00
Olivier Lambert
ead51787a8 Merge pull request #846 from vatesfr/pierre-v5-tags
Add and remove tag actions. Tag UI improvements.
2016-03-30 12:23:09 +02:00
Olivier Lambert
4bf0fee20d protection again counting twice or more a VDI size 2016-03-30 12:09:04 +02:00
Pierre
209693ee3f Add and remove tag actions. Tag UI improvements. Icon handles lg size. 2016-03-30 11:48:01 +02:00
Olivier Lambert
796d4f5b08 not pill in snapshots tab when no snapshots 2016-03-30 11:37:55 +02:00
Olivier Lambert
96914c9901 compute total vm disk space 2016-03-30 11:29:37 +02:00
Olivier Lambert
9e6073bf56 improve translation 2016-03-30 11:00:16 +02:00
Olivier Lambert
f8ad58159c minor i18n fix 2016-03-29 23:30:34 +02:00
Olivier Lambert
ede4a02315 various UI improvements 2016-03-29 22:43:06 +02:00
Olivier Lambert
e25faba990 basic VM disk tab 2016-03-29 22:35:27 +02:00
Olivier Lambert
4ccf272e53 add snapshot pill in tab name and more i18n 2016-03-29 21:08:58 +02:00
Olivier Lambert
5ad0951db3 improve snapshot view 2016-03-29 20:56:18 +02:00
Olivier Lambert
f72fcb76e3 start to work on snapshot view 2016-03-29 18:58:36 +02:00
Olivier Lambert
8ca00c81b2 display network name_label in vm network view 2016-03-29 18:02:55 +02:00
Olivier Lambert
5c7f87b8ae case when not VM network interface at all 2016-03-29 16:38:16 +02:00
Julien Fontanet
9f4f7ec88c utils/If: experimental component. 2016-03-29 16:14:54 +02:00
Olivier Lambert
ba7676f778 using keys for array 2016-03-29 16:01:46 +02:00
Julien Fontanet
ac248c32bb Fix handling of empty VM stats. 2016-03-29 15:44:46 +02:00
Julien Fontanet
dd6a3e8535 Update babel-eslint to 6.0.0. 2016-03-29 15:32:20 +02:00
Julien Fontanet
69b538cfd6 Remove unused redux-promise. 2016-03-29 15:32:20 +02:00
Julien Fontanet
e248c22f4b Remove unused redux-router. 2016-03-29 15:32:20 +02:00
Olivier Lambert
eff3c43483 better network page 2016-03-29 15:31:56 +02:00
Olivier Lambert
1cbfc3ccd4 various updates and fixes 2016-03-29 14:58:23 +02:00
Olivier Lambert
2fa72838f9 add sparklines to console view 2016-03-28 21:48:56 +02:00
Olivier Lambert
a559ec1fda better vm network translations 2016-03-28 21:42:13 +02:00
Olivier Lambert
8ddbc8b1fb minor network improvements 2016-03-28 21:21:59 +02:00
Olivier Lambert
c650a43d38 add translations 2016-03-28 21:12:30 +02:00
Olivier Lambert
ab4cc20c8c better network tab 2016-03-28 21:09:21 +02:00
Olivier Lambert
30d613ff04 minor vm action reordering 2016-03-28 20:09:41 +02:00
Olivier Lambert
b93da5a281 tag minor style modification 2016-03-28 18:06:57 +02:00
Olivier Lambert
9e2cf67a93 mockup layout for console view 2016-03-28 12:52:00 +02:00
Olivier Lambert
e87720ffdd minor style modification 2016-03-25 23:22:43 +01:00
Olivier Lambert
5108ed7da5 Merge pull request #842 from vatesfr/pierre-v5-tags
`Tags` component, basic version
2016-03-25 23:21:05 +01:00
Olivier Lambert
77936d86f2 position tags in VM view 2016-03-25 23:10:30 +01:00
Olivier Lambert
cbe8927d73 move tag style in main css file + PR comments 2016-03-25 22:57:47 +01:00
Pierre
47a7e98da8 Tags component 2016-03-25 22:56:36 +01:00
Olivier Lambert
d4f27cd2e0 default large buttons 2016-03-25 22:39:35 +01:00
Olivier Lambert
c355ad7a86 css fix 2016-03-25 19:16:48 +01:00
Julien Fontanet
c8c9ec081d Remove incorrect divs in VM page. 2016-03-25 19:12:46 +01:00
Julien Fontanet
1289e46401 Fix xo-sparlines/CpuSparkLines proptypes. 2016-03-25 19:12:46 +01:00
Julien Fontanet
0b54292130 VIFs in VM view. 2016-03-25 19:04:54 +01:00
Olivier Lambert
d1e2b91116 comment ationbar button to merge 2016-03-25 18:49:09 +01:00
Julien Fontanet
cd96b3e8f6 Merge pull request #844 from vatesfr/olivierlambert-clipboard
5.x clipboard
2016-03-25 18:19:27 +01:00
Olivier Lambert
9119f4d06f style fix 2016-03-25 18:16:40 +01:00
Olivier Lambert
4e6ccf2c81 reverse order on general tab 2016-03-25 18:08:18 +01:00
Olivier Lambert
6294e43762 various improvements 2016-03-25 18:08:18 +01:00
Olivier Lambert
feca78e55d reorder stuff and add clipboard support for UUID 2016-03-25 18:08:17 +01:00
Olivier Lambert
0c86526ad2 better sparklines styles 2016-03-25 18:07:33 +01:00
Olivier Lambert
9fd1d26067 minor graph improvements 2016-03-25 17:44:55 +01:00
Julien Fontanet
5ec02078d1 Merge pull request #843 from vatesfr/abhamonr-vm-charts
Vm Sparklines (Cpu, ram, vif, xvd)
2016-03-25 16:02:26 +01:00
wescoeur
012c6f3d41 Vm Sparklines (Cpu, ram, vif, xvd) 2016-03-25 15:41:44 +01:00
Olivier Lambert
8e89d492fc fix style 2016-03-25 14:55:46 +01:00
Olivier Lambert
69fe2f0443 date stuff 2016-03-25 14:52:14 +01:00
Julien Fontanet
ebd7f4ae1b Ignore Redux dev tools in production. 2016-03-25 12:40:46 +01:00
Julien Fontanet
f9ca4f339e Name components for better error messages. 2016-03-25 12:40:46 +01:00
Olivier Lambert
5919020e1c add cpu weight 2016-03-25 12:26:27 +01:00
Olivier Lambert
9d09c2356d add VM style 2016-03-25 12:08:24 +01:00
Julien Fontanet
3cfb597fc6 Properly forward props arg to super(). 2016-03-25 11:39:24 +01:00
Julien Fontanet
03f2da19e5 utils#Debug: component printing an object in JSON. 2016-03-25 11:39:24 +01:00
Julien Fontanet
951e62d984 Do not declare global variable osToFamily in utils. 2016-03-25 11:39:23 +01:00
Olivier Lambert
146039c4c5 translate UUID and use definitions for Advanced tab 2016-03-25 11:37:13 +01:00
Olivier Lambert
98a216fdb9 better translations 2016-03-25 11:00:45 +01:00
Olivier Lambert
28ea09a0c4 More translations 2016-03-24 23:32:59 +01:00
Olivier Lambert
a98a772360 remove trailing comma 2016-03-24 23:11:43 +01:00
Olivier Lambert
4f1da8a24b more translations 2016-03-24 23:11:03 +01:00
Olivier Lambert
cb83e71f2b better VM view 2016-03-24 19:29:49 +01:00
Olivier Lambert
646d174616 VM view stuff 2016-03-24 19:17:59 +01:00
Julien Fontanet
34cf78fd33 Require npm >=3. 2016-03-24 18:55:34 +01:00
Olivier Lambert
457e1bee2f fix osfamily 2016-03-24 18:45:02 +01:00
Olivier Lambert
6b95c63c1e style and some fixes 2016-03-24 18:25:46 +01:00
Julien Fontanet
e965f222db Merge pull request #841 from vatesfr/pierre-v5-action-bar
Action bar fixes
2016-03-24 18:17:50 +01:00
Olivier Lambert
d1591bc01c fix style 2016-03-24 17:36:12 +01:00
Olivier Lambert
a72846be7a uncomment icons 2016-03-24 17:36:12 +01:00
Julien Fontanet
5072661369 utils#{format,parse}Size() 2016-03-24 17:30:04 +01:00
Olivier Lambert
5417a83662 Add icon distro display 2016-03-24 17:09:28 +01:00
Pierre
23be006932 Removed console button in action bar 2016-03-24 16:54:33 +01:00
Pierre
e28553767e Label and icon are required for an ActionBar 2016-03-24 16:53:19 +01:00
Julien Fontanet
c1f64c043d Merge pull request #836 from vatesfr/pierre-v5-action-bar
v5 action bar
2016-03-24 16:50:02 +01:00
Pierre
9e6d0183d4 Button component. 2016-03-24 16:44:57 +01:00
Pierre
8dc7f3fb9e Better propTypes for ActionBar 2016-03-24 16:44:56 +01:00
Pierre
ac7b3b9b67 Icons CSS. propTypes on ActionBar and Icon. ActionBar in separate file. 2016-03-24 16:44:56 +01:00
Pierre
af0ebba5db Default icon. Lint fixes 2016-03-24 16:44:56 +01:00
Pierre
b454709e5e xo-icon- prefix in icon component. Default icon size: 1 2016-03-24 16:44:56 +01:00
Pierre
78684607bd Added VM actions icons 2016-03-24 16:44:56 +01:00
Pierre
3790cad5e5 Editable icon size. VM actions messages. 2016-03-24 16:44:56 +01:00
Pierre
77b7c091a8 Icon component 2016-03-24 16:44:56 +01:00
Pierre
450ad62fa9 ActionButton component. Added delete button in VM view. 2016-03-24 16:44:56 +01:00
Julien Fontanet
1d138c33a4 Col/Row can take a className prop. 2016-03-24 16:32:20 +01:00
Julien Fontanet
fb2a0e4a1e Add font-mfizz. 2016-03-24 16:18:04 +01:00
Julien Fontanet
da3db0b0f9 Cache node_modules on Travis. 2016-03-24 15:54:08 +01:00
Julien Fontanet
bc8aaadd90 Initial VM stats. 2016-03-24 15:39:18 +01:00
Olivier Lambert
e6054a4971 use Col from grid component 2016-03-24 13:44:54 +01:00
Olivier Lambert
26548e1929 using grid component 2016-03-24 13:37:45 +01:00
Julien Fontanet
4424cf8190 Initial grid component. 2016-03-24 12:53:19 +01:00
Julien Fontanet
67c1aacd54 @propTypes decorator. 2016-03-24 12:53:19 +01:00
Olivier Lambert
39b046f18b center properly 2016-03-24 12:50:29 +01:00
Julien Fontanet
d630f04872 Add missing dependency vinyl. 2016-03-24 11:43:22 +01:00
Julien Fontanet
35403c87bd Add missing dependency jsonrcp-websocket-client. 2016-03-24 11:30:27 +01:00
Julien Fontanet
f2b247e042 No tests for now: remove unused deps. 2016-03-24 11:16:04 +01:00
Julien Fontanet
94022bd9f2 Add missing dependency readable-stream. 2016-03-24 11:16:04 +01:00
Julien Fontanet
ccb2abb950 Remove support for Node < 4. 2016-03-24 11:16:00 +01:00
Julien Fontanet
cbafc15292 Various updates. 2016-03-24 10:52:49 +01:00
Julien Fontanet
e12c52294a Various updates. 2016-03-24 10:46:51 +01:00
Olivier Lambert
63b529da00 add react tabs 2016-03-24 10:06:51 +01:00
Olivier Lambert
e4be2fd19e add icons 2016-03-23 19:02:19 +01:00
Julien Fontanet
269bf4feec Various updates. 2016-03-23 18:40:56 +01:00
Olivier Lambert
9d4c4a1e2b translate tabs 2016-03-23 18:38:52 +01:00
Olivier Lambert
2e41fdcb41 More work on VM view 2016-03-23 18:01:32 +01:00
Olivier Lambert
2e48218623 conforming to the planned template display 2016-03-23 16:15:01 +01:00
Olivier Lambert
8576a54056 start the VM in the action bar 2016-03-23 16:02:30 +01:00
Julien Fontanet
79d924f920 Various updates. 2016-03-23 15:23:08 +01:00
Julien Fontanet
305beb3af8 Fix indent. 2016-03-23 13:00:04 +01:00
Julien Fontanet
06fceded14 Various updates. 2016-03-23 12:46:30 +01:00
Olivier Lambert
0eadfd5a58 Merge pull request #835 from vatesfr/abhamonr-fix-plugin-multiple-users-groups-loading
Avoid multiple users/groups loading in plugins view. (fix vatesfr/xo-…
2016-03-23 12:11:44 +01:00
wescoeur
eea34a4f6c Avoid multiple users/groups loading in plugins view. (fix vatesfr/xo-web#829) 2016-03-23 12:03:56 +01:00
Julien Fontanet
500ec36522 Various updates. 2016-03-23 11:21:47 +01:00
Julien Fontanet
ca525bd08c 4.15.1 2016-03-22 15:28:15 +01:00
Olivier Lambert
ac2ffc4586 Fix #830 2016-03-22 14:35:57 +01:00
Olivier Lambert
5781269557 Remove old message about not supported SMB remote for delta 2016-03-22 13:32:19 +01:00
Olivier Lambert
e4422b9fe7 Display only permitted SR for VM copy 2016-03-22 12:14:25 +01:00
Olivier Lambert
269f76d546 Fix #832 2016-03-22 11:47:34 +01:00
Julien Fontanet
540e3f0aaa 4.15.0 2016-03-21 16:50:22 +01:00
Olivier Lambert
5f64ae28e0 Merge pull request #800 from vatesfr/abhamonr-delta-backup-on-smb
SMB can be used with delta backups.
2016-03-21 09:37:40 +01:00
Julien Fontanet
ece364c823 Various updates. 2016-03-18 18:09:44 +01:00
Olivier Lambert
f669f64fcb add changelog 2016-03-18 16:17:36 +01:00
Julien Fontanet
2a53ed93c4 Various updates. 2016-03-18 15:00:33 +01:00
Julien Fontanet
2b731fb30c Various updates. 2016-03-18 12:14:06 +01:00
Julien Fontanet
be2db2dd8e Fix immediately spelling (thx @Danp2). 2016-03-18 10:02:30 +01:00
Julien Fontanet
09c08df1b9 Various updates. 2016-03-18 09:17:49 +01:00
Olivier Lambert
9ccd3438ad Fix #821 2016-03-17 19:15:35 +01:00
Julien Fontanet
393bcbcca5 Various updates. 2016-03-17 18:14:57 +01:00
Julien Fontanet
7fac0958b8 Various updates. 2016-03-17 16:35:45 +01:00
Olivier Lambert
c6a0874b3b Merge pull request #758 from vatesfr/marsaudf-backup-ui-fixes
Fixed backup remote lists
2016-03-17 14:23:56 +01:00
Olivier Lambert
9c80470185 Merge pull request #820 from vatesfr/pierre-server-version
Added server version in About view (See #807)
2016-03-17 14:21:56 +01:00
Julien Fontanet
2034445f5b Various updates. 2016-03-17 12:13:29 +01:00
Pierre
fd8da5ffba Added server version in About view 2016-03-17 10:52:32 +01:00
Olivier Lambert
e987af87f6 Merge pull request #809 from vatesfr/abhamonr-recursive-plugins-config
Complex configurations plugins. (recursion, array of objects...)
2016-03-17 10:31:31 +01:00
Pierre
0074cc3933 Fixed refresh bug. 2016-03-17 09:51:53 +01:00
Pierre
5f2ce89316 Fixed Object/String/Array display in plugin config. 2016-03-17 09:51:53 +01:00
Pierre
60492c48a6 Typo fix. 2016-03-17 09:51:53 +01:00
Pierre
eed2d70017 Better array display when items are objects 2016-03-17 09:51:53 +01:00
Pierre
b859adaa8c Fixes 2016-03-17 09:51:53 +01:00
Pierre
89a587f9ae enum handling 2016-03-17 09:51:53 +01:00
wescoeur
fb56bcff80 Complex configurations plugins. (recursion, array of objects...) 2016-03-17 09:51:53 +01:00
Fabrice Marsaud
99eb6907dd updater will block nav after 1 min out 2016-03-16 16:32:52 +01:00
Fabrice Marsaud
3743fad899 when updater-blocked, any nav attempt will retry connection 2016-03-16 16:18:02 +01:00
Olivier Lambert
c1e59a7e03 Merge pull request #818 from vatesfr/pierre-feedback-when-error-on-sr
Feedback when disconnecting a host from an SR does not work (See #810)
2016-03-16 15:54:11 +01:00
Pierre
b34dee1f83 Error message formatting: leading capital and trailing period. 2016-03-16 15:45:36 +01:00
Pierre
6edd65ad8f xo.pbd.disconnect instead of xoApi.call(...). Better error notification. 2016-03-16 15:01:29 +01:00
Olivier Lambert
0959ca6a40 Merge pull request #813 from vatesfr/pierre-network-management
Host & pool views: better network management (See #805)
2016-03-16 10:57:34 +01:00
Pierre
1287fa2cd0 Allowed network creation without PIF 2016-03-16 10:50:47 +01:00
Pierre
a5a07f250d UI improvements 2016-03-16 10:46:08 +01:00
Pierre
089fb526f5 IP configuration: DHCP & No IP. UI fixes. 2016-03-16 10:46:08 +01:00
Pierre
af58b7593a Configure PIF IP. UI fixes. 2016-03-16 10:46:07 +01:00
Pierre
d4508b25ce Only physical PIFs should be shown when creating network 2016-03-16 10:46:07 +01:00
Pierre
9edc218eaa Delete network 2016-03-16 10:46:07 +01:00
Olivier Lambert
3790f753aa Merge pull request #801 from vatesfr/pierre-pool-networks
Pool view: Interface panel and network creation (See #226)
2016-03-16 10:45:06 +01:00
Julien Fontanet
82b30d8388 Do not use nice-pipe (too buggy). 2016-03-10 17:23:04 +01:00
Julien Fontanet
e9a0dc7826 Various updates. 2016-03-10 17:01:16 +01:00
wescoeur
8ce3a4f904 SMB can be used with delta backups. 2016-03-09 17:12:15 +01:00
Julien Fontanet
1d42e9c348 Disable tests for now. 2016-03-09 14:29:27 +01:00
Julien Fontanet
2340a6bc37 Various updates. 2016-03-09 14:28:18 +01:00
Pierre
be0b9c7e53 Removed log 2016-03-09 10:38:45 +01:00
Pierre
6d75cd9025 Minor fix 2016-03-09 10:33:09 +01:00
Pierre
345d6f369e network.create instead of createNetwork for host and pool 2016-03-09 10:33:09 +01:00
Pierre
959ea86d85 Pool view: Interface panel and network creation 2016-03-09 10:33:09 +01:00
Olivier Lambert
b67a99af3d Add types for ISO SRs 2016-03-04 13:36:35 +01:00
Olivier Lambert
fa3b848d40 Merge pull request #799 from vatesfr/pierre-add-smb-sr
UI to add an SMB SR (user and password inputs) (Fix #731)
2016-03-03 18:25:55 +01:00
Pierre
0f971e9e7d Minor fix. 2016-03-03 17:55:43 +01:00
Pierre
c17f76c009 SMB case fix. 2016-03-03 17:50:23 +01:00
Pierre
bf23b5d295 Enabled Create button and removed search button when SMB. 2016-03-03 17:39:18 +01:00
Pierre
09c7256d42 UI to add an SMB SR (user and password inputs) 2016-03-03 16:58:46 +01:00
Olivier Lambert
eaee8a2fbb Merge pull request #798 from vatesfr/pierre-new-vm-from-pool-enhancement
New VM on pool: display all SRs (Fix #790)
2016-03-03 16:41:45 +01:00
Pierre
3b18dd67be Compatibility with self service 2016-03-03 16:16:03 +01:00
Pierre
c3f87b4248 Explicit message in summary 2016-03-03 15:27:07 +01:00
Julien Fontanet
f6b91ad652 Update deps. 2016-03-03 14:54:29 +01:00
Pierre
1c79edc52f Detection of incompatible SRs 2016-03-03 13:05:26 +01:00
Julien Fontanet
fe2dfd0e8f Merge branch 'stable' into next-release 2016-03-03 13:03:18 +01:00
Olivier Lambert
fa6056c1b1 Add unknown state 2016-03-03 12:26:06 +01:00
Olivier Lambert
d5762c7ad8 limit VDI form for admin users 2016-03-03 12:26:06 +01:00
Julien Fontanet
d9c9dd2a4f Welcome message in the issue template 2016-03-03 11:31:27 +01:00
Olivier Lambert
3a4d945c68 Merge pull request #793 from Danp2/next-release
Fix issue with gathering NFS shares
2016-03-02 23:41:04 +01:00
Danp2
f4a364816b Fix issue with gathering NFS shares
scsiList vs nfsList
2016-03-02 16:11:26 -06:00
Olivier Lambert
931bc03cab Inverse critical/warning SR usage in health view 2016-03-02 18:30:05 +01:00
Olivier Lambert
1abd4937cd Merge pull request #792 from vatesfr/pierre-licenses
Host and pool licenses (Fix #763)
2016-03-02 17:39:09 +01:00
Pierre
0df8b51c62 Host view and pool view: License panel. 2016-03-02 17:09:20 +01:00
Julien Fontanet
e5b7190015 Fix file uploads (2). 2016-03-02 16:24:15 +01:00
Olivier Lambert
279b8aacf6 add missing map filters 2016-03-02 15:44:23 +01:00
Olivier Lambert
9eebaab2f4 Add a map param for backup schedule view 2016-03-02 15:42:33 +01:00
Julien Fontanet
16e9d60033 Fix file uploads. 2016-03-02 15:27:30 +01:00
Olivier Lambert
335b378e9a Merge pull request #789 from vatesfr/pierre-disk-names
Default VDI names and descriptions (Fix #780)
2016-03-02 15:20:39 +01:00
Pierre
9c41bc33a3 Default names for template VDIs 2016-03-02 15:13:34 +01:00
Olivier Lambert
7f7d6b4d5d Merge pull request #772 from vatesfr/pierre-cpu-weight-in-resource-set
CPU weight edition should be disabled for resource set members (Fix #…
2016-03-02 14:56:05 +01:00
Olivier Lambert
cc0e3bbce0 Merge pull request #773 from vatesfr/pierre-host-patches-in-pool-view
Pool view: host updates panel (Fix #762)
2016-03-02 14:41:11 +01:00
Pierre
2eead65fef CPU weight should not be editable when creating a VM from a resource set 2016-03-02 14:36:46 +01:00
Pierre
e664be451f VDIs default names initialization in view 2016-03-02 12:40:44 +01:00
Pierre
d2d8160096 Default VDI names and descriptions 2016-03-02 10:28:29 +01:00
Olivier Lambert
3bd503c28d remove useless device number in VM migration window 2016-03-02 10:27:57 +01:00
Olivier Lambert
aa1df8eb33 Add Misc panel in host view to deliver system S/N etc. Fix #760 2016-03-01 17:17:36 +01:00
Olivier Lambert
c1aace45ae Match target network names for migration. Fix #782 2016-03-01 16:40:45 +01:00
Olivier Lambert
217a60aadc Improve the migration VM modal. Fix #785 2016-03-01 15:47:37 +01:00
Olivier Lambert
5654f528ca fix the task list for angular 1.5 2016-03-01 15:35:48 +01:00
Olivier Lambert
4da036a064 Add a missing angular map 2016-03-01 15:16:55 +01:00
Olivier Lambert
2256b3d262 Merge pull request #788 from Danp2/next-release
Minor fix to unitConfirms
2016-03-01 13:36:24 +01:00
Danp2
d84ecc307d Minor fix to unitConfirms 2016-03-01 06:32:30 -06:00
Julien Fontanet
237313d5fb Merge pull request #781 from vatesfr/fix-vdi-iteration-in-vm-creation
VM creation: correctly iterate over template VDIs (fix #778).
2016-02-29 18:49:33 +01:00
Olivier Lambert
7caf766bca Do not display CDs VBDs 2016-02-29 18:44:08 +01:00
Julien Fontanet
0a3f9f5ef1 Add issue template. 2016-02-29 16:37:13 +01:00
Julien Fontanet
e890b8f7c1 VM creation: correctly iterate over template VDIs (fix #778). 2016-02-29 15:14:52 +01:00
Olivier Lambert
dc4d5f0ecb fixing angular 1.5 2016-02-26 18:03:07 +01:00
Pierre
a2f0980731 Pool view: host updates panel (Fix #762) 2016-02-26 17:59:33 +01:00
Julien Fontanet
0a5c029f8b lodash.sum(): does not work with objects anymore. 2016-02-26 17:36:06 +01:00
Julien Fontanet
85bb79e4fb Move shims to app/node_modules.
Hopefully this will avoid there accidental deletion by users.
2016-02-26 15:55:05 +01:00
Julien Fontanet
f18d1e50f8 Fix ng-file-upload import. 2016-02-26 15:55:05 +01:00
Julien Fontanet
943b10dd5d Update angular-chart.js to 0.8. 2016-02-26 15:55:05 +01:00
Julien Fontanet
0a48e17c88 Update ng-angular-upload to 12.0. 2016-02-26 15:55:05 +01:00
Olivier Lambert
da1381e14e Map usage before orderBy for dashboard view 2016-02-26 15:53:14 +01:00
Pierre
bdffb0ee10 CPU weight edition should be disabled for resource set members (Fix #767) 2016-02-26 14:51:53 +01:00
Julien Fontanet
7bdb7d2ca8 Fix angular-bootstrap usage in updater. 2016-02-26 14:34:56 +01:00
Julien Fontanet
92567561b8 Update angularjs-toaster to 1.2. 2016-02-26 13:06:02 +01:00
Julien Fontanet
335bdcd89d Update angular-xeditable-npm to 0.1.9. 2016-02-26 13:05:56 +01:00
Julien Fontanet
4c2fc13abb Update ui-select to 0.14. 2016-02-26 13:05:51 +01:00
Julien Fontanet
7f8f29daa2 Update angular-ui-bootstrap to 0.14. 2016-02-26 12:43:48 +01:00
Julien Fontanet
8fac845ecb Use angular-ui-{event,indeterminate} instead of deprecated angular-ui-utils. 2016-02-26 12:34:56 +01:00
Olivier Lambert
d8076e7630 Merge pull request #756 from vatesfr/pierre-self-service-dashboard
Self service dashboard (Fix #741)
2016-02-26 11:56:27 +01:00
Pierre
b370bc27c4 Fixed condition when no resource set found 2016-02-26 11:41:08 +01:00
Pierre
334c3f4488 Removed arrows when only 1 page is needed 2016-02-26 11:34:46 +01:00
Pierre
33822109c0 Minor fixes 2016-02-26 11:20:11 +01:00
Pierre
b1f18b0f5b Added templates, SRs and networks to details 2016-02-26 10:00:32 +01:00
Julien Fontanet
c0d6284368 Fix Jade compilation for Node < v4. 2016-02-25 17:48:16 +01:00
Pierre
16e294f6fc Resource sets details 2016-02-25 17:47:46 +01:00
Pierre
5f7925b2b8 Display page number 2016-02-25 17:47:46 +01:00
Pierre
2e001b0ce4 Pages layout 2016-02-25 17:47:46 +01:00
Pierre
c1ca3ff5b5 [WIP] All resource sets together (other layout commented). 2016-02-25 17:47:46 +01:00
Pierre
1de33cd4ca Self service dashboard (Fix #741)
Fixed no limit condition and icons.
2016-02-25 17:47:46 +01:00
Olivier Lambert
77b773388f fix network list in new vm, using map before orderby 2016-02-25 15:47:34 +01:00
Olivier Lambert
3e668ee439 Merge pull request #759 from vatesfr/fix-babel-6-imports
Fix Babel 6: `require module` --> `require(module).default`
2016-02-25 11:38:23 +01:00
Pierre
0d3ea9af36 Fix Babel 6: require module --> require(module).default 2016-02-25 11:21:47 +01:00
Fabrice Marsaud
0d81bc8056 Fixed backup remote lists 2016-02-25 09:24:38 +01:00
Julien Fontanet
e4b532a34d week heatmap: fix lodash.pluck usage. 2016-02-24 17:49:32 +01:00
Julien Fontanet
61f86c0ac3 Merge pull request #739 from vatesfr/update-deps
Update deps
2016-02-24 16:58:35 +01:00
Julien Fontanet
66fad37116 Remove unused lodash.puck dep. 2016-02-24 16:53:12 +01:00
Julien Fontanet
c7bbd8c823 Update nice-pipe to v3. 2016-02-24 16:44:07 +01:00
Julien Fontanet
dc6f8baf1e Update Babel to v6. 2016-02-24 16:44:07 +01:00
Julien Fontanet
0e76e65d65 Update Coffeeify to v2. 2016-02-24 16:44:07 +01:00
Julien Fontanet
877dbed999 Update Browserify to v13. 2016-02-24 16:44:07 +01:00
Julien Fontanet
668fd05fae Update Bluebird to v3. 2016-02-24 16:44:07 +01:00
Julien Fontanet
3e49998f41 Update Lodash to v4. 2016-02-24 16:44:07 +01:00
Julien Fontanet
99b183ac17 Update Angular to v1.5. 2016-02-24 16:42:51 +01:00
Fabrice Marsaud
bb04cddc48 4.14.1 2016-02-24 13:57:24 +01:00
Fabrice Marsaud
ba3f095dd8 4.14.0 2016-02-24 13:57:13 +01:00
Julien Fontanet
f8438421c8 4.13.1 2016-02-24 13:42:15 +01:00
Julien Fontanet
334361860b Merge pull request #753 from vatesfr/pierre-self-service-user
New-VM: Fixed summary when modifying an existing disk size
2016-02-24 13:42:00 +01:00
Pierre
23bd211758 Fixed summary when modifying an existing disk size 2016-02-24 13:26:58 +01:00
Julien Fontanet
4cc8fb9891 Merge pull request #752 from vatesfr/pierre-state-go
Better redirection when creating VM(s)
2016-02-24 12:51:32 +01:00
Pierre
ed3cd690fe Better redirection when creating VM(s) 2016-02-24 12:50:04 +01:00
Julien Fontanet
9a40c7cdc6 Merge pull request #750 from vatesfr/pierre-self-service-user
No limit: limit value should not exist when input field is empty
2016-02-24 12:44:37 +01:00
Pierre
ae4c9ce819 Better handle for no limit 2016-02-24 12:44:06 +01:00
Pierre
2f8bae1356 No limit: limit value should be undefined when input field is empty 2016-02-24 12:23:51 +01:00
Olivier Lambert
2dfcd5b7ef Merge pull request #740 from vatesfr/pierre-self-service-user
Create VM with self service (See #285)
2016-02-23 18:56:48 +01:00
Pierre
739926f64e Fixed button addon in disk list (VM view) 2016-02-23 18:51:04 +01:00
Pierre
a18dde07de Fixed multiple lines ng-disabled 2016-02-23 18:42:54 +01:00
Pierre
6480017a91 Fixed Create button disabled condition 2016-02-23 18:39:47 +01:00
Pierre
4467ec52f7 No limit: undefined instead of null. 2016-02-23 18:24:53 +01:00
Pierre
072d82a10e Size unit fix. 2016-02-23 18:15:43 +01:00
Pierre
b50b759f4f Default RAM size unit in New VM view 2016-02-23 18:11:07 +01:00
Pierre
c1477ad45f Typo fix. 2016-02-23 18:09:02 +01:00
Pierre
679d45399b Typo fix. Default resource set RAM size unit. 2016-02-23 17:31:37 +01:00
Pierre
0e15a789ff Fixed buttons addons 2016-02-23 16:55:47 +01:00
Pierre
dff5b3f497 Fixed resourceSet edition 2016-02-23 16:55:47 +01:00
Pierre
483e49a6ae Connect interface and server 2016-02-23 16:55:47 +01:00
Pierre
a689b5b917 Changed resourceSet^Ctructure for limits. Minor fixes. 2016-02-23 16:55:46 +01:00
Pierre
1363d98280 New VM: progress bars to show remaining available resources 2016-02-23 16:55:46 +01:00
Pierre
405f3dcbdd Resource sets: CPU, RAM and disk space restrictions 2016-02-23 16:55:46 +01:00
Pierre
4b48408bc9 Margin fix 2016-02-23 16:55:46 +01:00
Pierre
d6f1e2d7e2 Form alignements 2016-02-23 16:55:46 +01:00
Pierre
c04c8e3aa4 Moved "select resource set" on title row 2016-02-23 16:55:46 +01:00
Pierre
ff5a08d3b0 Enabled resource set edition 2016-02-23 16:55:46 +01:00
Pierre
d2049c759e Enabled ISO installing method 2016-02-23 16:55:46 +01:00
Pierre
f940cb0ace Redirect to list view instead of VM view 2016-02-23 16:55:46 +01:00
Pierre
507f2f4af4 Creation form updated when resource set selected 2016-02-23 16:55:45 +01:00
Pierre
deca7099f3 Checking available resource sets for a specific user 2016-02-23 16:55:45 +01:00
Pierre
46a741825a [WIP] Create VM as non-admin user with self service 2016-02-23 16:55:45 +01:00
Fabrice Marsaud
14fdcd3052 Reworked for sequential SR and Network choice 2016-02-23 16:55:44 +01:00
Fabrice Marsaud
c76b01608a Fixes. Commented quotas for later use. 2016-02-23 16:55:44 +01:00
Fabrice Marsaud
be709d6601 Rewrite on server API 2016-02-23 16:55:44 +01:00
Fabrice Marsaud
7dc8fac198 Fix constraint rules 2016-02-23 16:55:44 +01:00
Fabrice Marsaud
29ae7d57fd display and mock save/edit 2016-02-23 16:55:43 +01:00
Fabrice Marsaud
1bf9ce872b constraint reolutions 2016-02-23 16:55:43 +01:00
Fabrice Marsaud
0071c9504f first steps 2016-02-23 16:55:43 +01:00
Olivier Lambert
594a872c84 forget _reportWhen 2016-02-23 16:54:23 +01:00
Julien Fontanet
0d1f78e82e Better permission handling when not connected. 2016-02-23 16:49:14 +01:00
Julien Fontanet
a12de51897 generic modal: fix missing cancel button. 2016-02-23 16:12:59 +01:00
Olivier Lambert
74fa084dd0 update changelog 2016-02-23 16:02:37 +01:00
Julien Fontanet
a1ee258da5 Do not call vm.set() directly in new VM controller. 2016-02-23 15:18:34 +01:00
Julien Fontanet
c1af171c5d Do not call vm.set() directly in VM controller. 2016-02-23 15:04:50 +01:00
Olivier Lambert
e36c9560fa fix form declaration for conditional backup. Thanks to @Danp2 for pointing it 2016-02-23 13:58:37 +01:00
Olivier Lambert
5cd19ddc8d UI fix for non admin users 2016-02-23 11:00:36 +01:00
Olivier Lambert
ac243e5d11 Merge pull request #745 from vatesfr/pierre-overview-remote-status-indicator
Fixed error button condition in Overview. Minor UI fix.
2016-02-23 10:23:00 +01:00
Olivier Lambert
b480d019f6 add conditional reporting for rolling snaps 2016-02-23 10:21:46 +01:00
Olivier Lambert
cc13ab97d6 add conditional reporting for DR 2016-02-23 10:19:00 +01:00
Olivier Lambert
fee1d2ed04 add conditional report for basic backup 2016-02-23 10:15:36 +01:00
Pierre
4144d5faa6 Fixed error button condition in Overview. Minor UI fix. 2016-02-23 10:11:09 +01:00
Olivier Lambert
38a23c0bee add conditional reporting for delta backup 2016-02-23 09:50:23 +01:00
Olivier Lambert
8fcfebe170 Merge pull request #744 from Danp2/reportWhen
CR conditional reporting
2016-02-22 21:54:34 +01:00
Danp2
f917fa8138 CR conditional reporting
Add functionality to allow conditional reporting to continuous
replication backup
2016-02-22 14:31:40 -06:00
Julien Fontanet
f60b611304 Revert to use ~ for Angular versions. 2016-02-22 18:32:40 +01:00
Olivier Lambert
a54624e5c8 Merge pull request #743 from vatesfr/sources-disclaimer
Sources disclaimer
2016-02-22 18:08:09 +01:00
Olivier Lambert
370b14b82e better text and link to XOA page 2016-02-17 13:21:00 +01:00
Julien Fontanet
88205adeb2 Update Angular to v1.4.9. 2016-02-17 12:42:57 +01:00
Julien Fontanet
351ce995d9 Sources disclaimer appears once every week. 2016-02-17 12:42:42 +01:00
Julien Fontanet
a9aa92de90 modal service: new htmlMessage option. 2016-02-17 12:34:46 +01:00
Olivier Lambert
9ea665dea2 include default cloudconfig + link toward the official doc 2016-02-17 11:42:53 +01:00
Julien Fontanet
30b52527e7 modal service: new alert() method. 2016-02-17 11:40:54 +01:00
Julien Fontanet
bb4125153b Dashboard/Health: fix deletion of VDIs/VMs after unselected item(s). 2016-02-16 17:50:41 +01:00
Olivier Lambert
f0d5b2b1da Merge pull request #732 from vatesfr/pierre-overview-remote-status-indicator
Backup overview: Status indicator for the remote associated to each job (Fix #728)
2016-02-12 18:04:25 +01:00
Pierre
30c4048e4a Handle remote/remoteId property 2016-02-12 17:48:51 +01:00
Pierre
93770ca9ce Alert when remote does not exist 2016-02-12 17:21:41 +01:00
Pierre
e788783d12 Backup overview: Status indicator for the remote associated to each job 2016-02-12 17:10:11 +01:00
Olivier Lambert
1314444d7c Merge pull request #730 from vatesfr/pierre-boot-order
Fixed boot order options bug (Fix #726)
2016-02-12 11:27:44 +01:00
Pierre
2a14664d34 Fixed boot order options bug (Fix #726)
Unchecking a boot option should not uncheck all the options below it.
2016-02-12 11:12:48 +01:00
Olivier Lambert
07a03940a0 order installed patch by name 2016-02-11 11:45:56 +01:00
Olivier Lambert
5f2f6fff56 Merge pull request #725 from vatesfr/pierre-vm-view-ui-enhancements
New VM: fixed summary refresh (Fix #721)
2016-02-11 11:06:55 +01:00
Pierre
353548660c New VM: fixed summary refresh (Fix #721) 2016-02-11 10:58:00 +01:00
Olivier Lambert
912f07225c Merge pull request #723 from vatesfr/pierre-custom-cloud-config
Custom config in Config Drive
2016-02-11 10:47:29 +01:00
Pierre
a23b7eeff1 Uplad config file: status icons, size check. Minor fixes. 2016-02-11 10:32:58 +01:00
Pierre
574f0d71b2 Custom config in Config Drive 2016-02-10 16:32:11 +01:00
Olivier Lambert
a368312035 Merge pull request #720 from vatesfr/pierre-vm-view-ui-enhancements
Size input should allow float numbers (Fix #719)
2016-02-10 14:46:16 +01:00
Pierre
2f88b1ab65 +string instead of parseFloat(string) 2016-02-10 14:43:15 +01:00
Pierre
f85f97e061 Size input should allow float numbers (Fix #719) 2016-02-10 14:36:00 +01:00
Olivier Lambert
30dec13903 Merge pull request #718 from vatesfr/pierre-table-ellipsis
Fixed text overflow in tables. (See #713)
2016-02-10 14:02:37 +01:00
Pierre
3057e5c997 Fixed text overflow in tables. (See #713)
`overflow: hidden` for td and th. Inline CSS style when `overflow: visible` is needed.
2016-02-10 10:04:49 +01:00
Olivier Lambert
6c413eb1ba Fix issue #703 2016-02-08 17:38:22 +01:00
Julien Fontanet
dcdd9132e2 The main bug tracker is xo-web. 2016-02-08 15:33:35 +01:00
Olivier Lambert
d9b1c36055 typo in changelog 2016-02-04 22:14:39 +01:00
Olivier Lambert
a593a247d7 change log update 2016-02-04 22:13:51 +01:00
Julien Fontanet
155debc864 4.13.0 2016-02-04 19:51:07 +01:00
Julien Fontanet
a5975ac38b Merge branch 'next-release' into stable 2016-02-04 19:50:39 +01:00
Olivier Lambert
204f1cfd6b Merge pull request #674 from vatesfr/pierre-vm-view-ui-enhancements
Select RAM units with dropdown menus
2016-02-04 09:52:50 +01:00
Pierre
2d22e043a0 Dropdown menus to select byte units (Fix #666)
New-VM view: RAM & VDIs sizes
VM view: RAM & VDIs sizes
SR view: VDIs sizes
2016-02-03 16:18:05 +01:00
Olivier Lambert
c26cacaf4e Merge pull request #687 from vatesfr/xo-acl-resolver
Use xo-acl-resolver.
2016-02-03 14:26:40 +01:00
Olivier Lambert
f0048544e2 Merge pull request #681 from vatesfr/olivierlambert-health
WIP: initial work on new health view
2016-02-03 14:16:45 +01:00
Olivier Lambert
cf227dbfa2 Merge pull request #695 from vatesfr/marsaudf-fix-sr-form
fix SR form
2016-02-03 14:00:38 +01:00
Olivier Lambert
a5f8bdbe61 fix issue #693 2016-02-03 13:26:07 +01:00
Olivier Lambert
e442553c6f Fix issue #691 2016-02-03 13:21:17 +01:00
Olivier Lambert
7134acfcd6 Fix issue #690 2016-02-03 13:18:21 +01:00
Olivier Lambert
82439f444e Fix issue #688 2016-02-03 13:03:58 +01:00
Fabrice Marsaud
1a17908488 fix SR form 2016-02-03 12:12:15 +01:00
Julien Fontanet
9af30e99f8 Use xo-acl-resolver. 2016-02-03 11:53:54 +01:00
Fabrice Marsaud
6f942c3417 orphans in sr view 2016-02-03 11:07:07 +01:00
Fabrice Marsaud
57083c90cd Fixes 2016-02-03 10:48:21 +01:00
Fabrice Marsaud
e28bcdd978 Correct rule for orphan snapshots 2016-02-03 10:28:49 +01:00
Olivier Lambert
0b4a5ab2eb working filter 2016-02-02 23:31:00 +01:00
Fabrice Marsaud
034704a330 No warnings for iso SRs 2016-02-02 17:59:59 +01:00
Fabrice Marsaud
5c60eaf6ab SR warnings 2016-02-02 17:45:49 +01:00
Fabrice Marsaud
f5709eac2c orphan snapshots panels 2016-02-02 16:52:57 +01:00
Fabrice Marsaud
5a5e714aca Fixed cpuWeight default choice 2016-02-02 09:43:18 +01:00
Olivier Lambert
747d48e4d9 adding missing files 2016-02-01 18:30:02 +01:00
Olivier Lambert
07a0200f30 WIP: initial work on new health view 2016-02-01 18:28:09 +01:00
Fabrice Marsaud
1c5313f2d9 Fixed cpuWeight type 2016-02-01 17:51:10 +01:00
Olivier Lambert
05e08719fb Merge pull request #678 from vatesfr/olivierlambert-srfixes
Use only physical usage for SRs
2016-02-01 17:31:10 +01:00
Olivier Lambert
ca0e616f88 Only use physical utilization for SR 2016-02-01 17:26:08 +01:00
Fabrice Marsaud
a8d20caba4 CPU Weight can back to default 2016-02-01 16:29:53 +01:00
Olivier Lambert
0d4bbb0a48 Merge pull request #677 from vatesfr/marsaudf-cpu-weigth#633
Edit VM CPU Weight
2016-02-01 16:10:36 +01:00
Fabrice Marsaud
b9cc219530 Handle VM CPU Weight 2016-02-01 15:54:52 +01:00
Olivier Lambert
e204ab5871 Merge pull request #650 from vatesfr/pierre-vm-migration-details
Custom VM migration in VM view
2016-01-28 17:02:35 +01:00
Fabrice Marsaud
16d0c05b4b Fiw attempt on console canvas 2016-01-28 15:33:48 +01:00
Fabrice Marsaud
6f8329d191 VDI multi delete 2016-01-28 15:09:36 +01:00
Olivier Lambert
d751463b26 Merge pull request #660 from vatesfr/abhamonr-avoid-metadata-imp-exp-delta-backups
New delta backup format used. (without 'xva' files) (fix #651)
2016-01-28 11:35:11 +01:00
Olivier Lambert
d3b66eff59 Merge pull request #671 from vatesfr/marsaudf-clear-logs#661
Delete job logs
2016-01-28 11:01:15 +01:00
Olivier Lambert
4257d0332a Merge pull request #672 from vatesfr/marsaudf-console-links#668
Differentiate VM and VM-controller console
2016-01-28 10:02:40 +01:00
Julien Fontanet
ccbcaa94fe Various updates. 2016-01-28 09:45:40 +01:00
Fabrice Marsaud
b80442c061 Fix to remove smb remotes for delta-backups 2016-01-28 09:22:22 +01:00
Fabrice Marsaud
3a0f6820ad Differentiate VM and VM-controller console 2016-01-28 09:02:58 +01:00
Fabrice Marsaud
1bc92f5363 Delete job logs 2016-01-28 08:50:50 +01:00
Olivier Lambert
818ddcf01e Merge pull request #663 from vatesfr/marsaudf-angular-crash#662
Secure VM object concurrent suppression
2016-01-28 08:18:43 +01:00
Olivier Lambert
618ba361c7 Merge pull request #568 from vatesfr/marsaudf-smb-mounts#338
SMB remotes
2016-01-28 08:18:24 +01:00
wescoeur
599160a325 New delta backup format used. (without 'xva' files) (fix #651) 2016-01-27 13:37:54 +01:00
Pierre
35fba6f4ed Custom VM migration from VM view (See #567)
- Migration on the same pool :
	- if the VM's VDIs are on the pool's SRs : standard migration
	- if the VM's VDIs are on local SRs : choose migration network and target SRs
- Migration on another pool : choose migration network, target SRs and target VIFs
2016-01-27 11:36:38 +01:00
Fabrice Marsaud
a14aad75fd external remote url module 2016-01-27 10:12:16 +01:00
Fabrice Marsaud
3513e85b0b remote url composing fix 2016-01-27 10:12:16 +01:00
Fabrice Marsaud
66c0390fc7 No smb remotes for delta backups 2016-01-27 10:12:16 +01:00
Fabrice Marsaud
a6549ccb08 SMB remotes 2016-01-27 10:12:16 +01:00
Julien Fontanet
15d2878014 Merge pull request #669 from Danp2/Danp2-patch-1
Fix spelling of "immediately"
2016-01-27 09:10:44 +01:00
Danp2
d271be8723 Update view.jade 2016-01-26 19:32:09 -06:00
Danp2
6f9d2d99dd Update view.jade 2016-01-26 19:31:43 -06:00
Danp2
5d62664ee3 Update view.jade 2016-01-26 19:30:45 -06:00
Danp2
7124d9f2f8 Update view.jade 2016-01-26 19:26:53 -06:00
Fabrice Marsaud
0459744771 Fixes disk save handling 2016-01-25 17:40:47 +01:00
Fabrice Marsaud
417544b781 Secure VM object concurrent suppression 2016-01-25 17:40:35 +01:00
Olivier Lambert
f9028cb366 Change the word Terminated by Finished for backups 2016-01-22 18:22:50 +01:00
Julien Fontanet
0ffa9d4225 Various updates. 2016-01-22 16:03:33 +01:00
Olivier Lambert
9a264719a9 Avoid broken Angular views. Fix #662 2016-01-21 15:11:42 +01:00
Olivier Lambert
96c213dcc4 Typo about the year in the changelog 2016-01-18 12:56:29 +01:00
Julien Fontanet
dec1a8e204 4.12.0 2016-01-18 10:45:50 +01:00
Olivier Lambert
a17fd697e2 update the CHANGELOG 2016-01-17 16:58:31 +01:00
Fabrice Marsaud
a6ab66e799 Fix #654 2016-01-17 16:12:11 +01:00
Fabrice Marsaud
17095ec3c6 Fix #652 2016-01-17 15:57:58 +01:00
Olivier Lambert
82687147b8 changelog for release 2016-01-17 10:24:28 +01:00
Olivier Lambert
ba76422c1f Merge pull request #648 from vatesfr/abhamonr-continuous-replication-view
Continuous replication view.
2016-01-16 20:04:05 +01:00
wescoeur
083b3c4ece Continuous replication view. (fix #582) 2016-01-15 13:15:43 +01:00
Olivier Lambert
5ecfdf38a8 Merge pull request #600 from vatesfr/abhamonr-button-bootable-disk
Use checkbox to disable/enable bootable disk property. (fix #583)
2016-01-14 16:26:54 +01:00
wescoeur
dd1acf3c2a Use checkbox to disable/enable bootable disk property. (fix #583) 2016-01-14 16:22:45 +01:00
Olivier Lambert
76e9c2d196 Fix issue #643 2016-01-13 18:54:19 +01:00
Julien Fontanet
15f046959d Fix lodash.trim to 3.0.1 (see lodash/lodash#1769). 2016-01-13 16:23:20 +01:00
Olivier Lambert
bf3ba04624 Merge pull request #620 from vatesfr/abhamonr-disable-vm-start-during-delta-import
Disable vm start during delta import and explicit notification. (fix #613)
2016-01-13 11:53:54 +01:00
Olivier Lambert
d997894d9a Merge pull request #614 from vatesfr/pierre-create-multiple-vms
Create multiple VMs at once
2016-01-13 11:33:18 +01:00
wescoeur
c1059db6e5 Disable vm start during delta import and explicit notification. (fix #613) 2016-01-13 11:04:24 +01:00
Pierre
8ad29a2836 Creation of multiple VMs at once
- Panel to enable the creation of multiple VMs at once
- Main name is no longer required when creating multiple VMs
- Number of VMs is checked before creating VMs names input fields
- Redirection to tree view instead of VM view when creating multiple VMs
- Number of new VMs in summary
2016-01-13 10:52:48 +01:00
Olivier Lambert
93a454b835 fix id propagation problem 2016-01-13 10:33:06 +01:00
Olivier Lambert
da899386ec Merge pull request #640 from vatesfr/marsaudf-plugin-view-fix#637
Plugin reload after changes
2016-01-07 11:53:16 +01:00
Fabrice Marsaud
05d22903ea Plugin reload after changes 2016-01-07 11:45:15 +01:00
Olivier Lambert
33945520f1 Fix issue #639 2016-01-06 10:22:52 +01:00
Olivier Lambert
40284809cf choose to boot VM after creation. Fix #635 2016-01-04 16:41:16 +01:00
Olivier Lambert
efc18aaaec ensure CloudConfig drive is created before going on the freshly created VM view 2016-01-04 16:37:04 +01:00
Olivier Lambert
348441b046 improve hostname regex for CloudInit 2016-01-04 12:35:47 +01:00
Olivier Lambert
66601b2e7c remove space in hostname for cloudconfig. Fix #634 2016-01-04 12:33:52 +01:00
Olivier Lambert
724c5e4b73 VM creation auto name, description & select existing install repo 2015-12-31 10:50:15 +01:00
Olivier Lambert
7eff29bc65 remove useless logs 2015-12-31 10:25:49 +01:00
Olivier Lambert
ca002003c2 fix VIFs issues in VM creation 2015-12-31 10:25:23 +01:00
Olivier Lambert
f0675f1f3c Merge pull request #618 from vatesfr/pierre-delete-running-vm
Delete a running or suspended VM (See #616)
2015-12-31 08:56:19 +01:00
Olivier Lambert
976186c525 Merge pull request #631 from vatesfr/olivierlambert-existing-vifs
manage existing VDIs, fix #630
2015-12-30 22:16:00 +01:00
Olivier Lambert
89d5777e52 allow existing VIFs edition during VM creation. Fix #630 2015-12-30 22:12:15 +01:00
Olivier Lambert
8dbb69809c Merge pull request #629 from vatesfr/olivierlambert-custom-templates
Custom templates, fix #627 and #628
2015-12-30 18:18:09 +01:00
Olivier Lambert
7348bd5d15 support templates with existing install_repository, as requested for issue #625 2015-12-30 16:08:39 +01:00
Olivier Lambert
9a46a466f7 properlly manage PV args (related to #625) 2015-12-30 15:27:41 +01:00
Fabrice Marsaud
fafc5c8553 Deltabackup display fix 2015-12-30 13:46:12 +01:00
Julien Fontanet
4ffdfaa506 Merge pull request #619 from vatesfr/pierre-fix-suspend-vm-tree-view
Fixed `suspendVM` in tree view.
2015-12-22 15:56:50 +01:00
Pierre
e3989840ee Fixed suspendVM in tree view. 2015-12-22 15:51:59 +01:00
Pierre
b3e6f531a1 Delete not halted VMs (See #616) 2015-12-22 15:46:19 +01:00
Julien Fontanet
4f6ee34592 4.11.0 2015-12-22 13:05:56 +01:00
Olivier Lambert
3ae58a323e update changelog 2015-12-22 12:36:12 +01:00
Fabrice Marsaud
26b958c270 SR host names displayed when necessary 2015-12-22 12:00:15 +01:00
Olivier Lambert
12a4af5900 fix a broken link 2015-12-22 10:39:18 +01:00
Julien Fontanet
69479d538c Merge pull request #611 from vatesfr/abhamonr-incremental-backups-integration
Delta Backup is now known by xo-web.
2015-12-21 18:52:26 +01:00
wescoeur
829397dd5a Delta Backup is now known by xo-web. 2015-12-21 18:00:31 +01:00
Olivier Lambert
2bc89026db Merge pull request #612 from vatesfr/marsaudf-sr-list#601
All host SRs from the pool are shown for Halted VMs disk edition
2015-12-21 16:03:22 +01:00
Fabrice Marsaud
ebbc44d181 All host SRs from the pool are shwon for Halted VMs disk edition 2015-12-21 15:58:49 +01:00
Olivier Lambert
2228a1e36b update changelog 2015-12-21 12:37:33 +01:00
Olivier Lambert
a8cbf3e8ff Merge pull request #602 from vatesfr/pierre-plugin-config-detailed-errors
Plugin config: feedback on form filling errors
2015-12-21 12:02:57 +01:00
Olivier Lambert
fa32e3d734 Merge pull request #598 from vatesfr/marsaudf-disk-size-edition#587
Marsaudf disk size edition#587
2015-12-21 12:02:13 +01:00
Pierre
0d17148ff0 Minor fixes 2015-12-21 11:30:07 +01:00
Pierre
aa38411cf7 Checking titles for each config group. Displaying errors only for the concerned plugin 2015-12-21 11:11:04 +01:00
Olivier Lambert
4913c8699d Merge pull request #610 from vatesfr/cache-missingPatches-dashboard
Cache # of missing patches in dashboard (fix #609).
2015-12-21 10:42:36 +01:00
Julien Fontanet
1035a11487 Cache # of missing patches in dashboard (fix #609). 2015-12-21 10:38:31 +01:00
Olivier Lambert
15c2efe706 Merge pull request #607 from vatesfr/fix-removeListener-dashboard
Stop computing charts data when no longer on dashboard (fix #604).
2015-12-21 10:09:19 +01:00
Julien Fontanet
d7fd71bb62 Same fix for dataviz view. 2015-12-21 10:05:51 +01:00
Julien Fontanet
b11ee993fa Stop computing charts data when no longer on dashboard (fix #604). 2015-12-21 10:05:46 +01:00
Olivier Lambert
614aa7873c update changelog 2015-12-20 14:21:30 +01:00
Pierre
1adf31fe15 [WIP] Display field title when possible and multiple fixes. 2015-12-18 17:24:19 +01:00
Julien Fontanet
824ffd7b5b Merge pull request #603 from vatesfr/abhamonr-fix-remote-importVm
The vm import call use a sr instead of a host.
2015-12-18 17:10:11 +01:00
wescoeur
c31c6fdebb The vm import call use a sr instead of a host. 2015-12-18 17:03:59 +01:00
Pierre
83f3276429 Plugin config: feedback on form filling errors 2015-12-18 15:25:24 +01:00
Julien Fontanet
d21f68ce54 Merge pull request #586 from vatesfr/pierre-read-only-connection
Added read-only checkboxes in the interface
2015-12-18 12:03:44 +01:00
Pierre
18b1e1b133 Connection to a server in read-only mode. (Fix #439)
Checkboxes in Settings view to connect to a Xen Server in read-only mode and then to toggle mode while connected to the server.
2015-12-18 11:48:29 +01:00
Fabrice Marsaud
0edaa40052 Confirm modals before disk resizing 2015-12-18 10:18:02 +01:00
Fabrice Marsaud
627077c8f3 Better code for Human readable size input 2015-12-18 10:18:02 +01:00
Fabrice Marsaud
a897b1798d bytesToSize only alters numbers 2015-12-18 10:18:02 +01:00
Olivier Lambert
50e39993bf Merge pull request #599 from vatesfr/marsaudf-newmv-disk-size
HR size for new VM new disks
2015-12-17 10:59:50 +01:00
Fabrice Marsaud
5e397dd01e HR size for new VM new disks 2015-12-17 10:53:32 +01:00
Olivier Lambert
f57ff5d5e0 Merge pull request #593 from vatesfr/pierre-no-orderby-when-focus
Settings view: the servers list should not re-order while a field is being edited. Fix #594
2015-12-16 18:26:55 +01:00
Olivier Lambert
5c3e40917c Merge pull request #577 from vatesfr/olivierlambert-configdrive
Allow cloud drive usage for disk templates VMs
2015-12-16 18:20:13 +01:00
Olivier Lambert
90a2dc4581 Merge pull request #597 from vatesfr/marsaudf-disk-size-edition#587
Marsaudf disk size edition. Fix #587
2015-12-16 17:37:15 +01:00
Olivier Lambert
b64243fdd6 add parent :o 2015-12-16 17:12:51 +01:00
Fabrice Marsaud
42db87d305 resize disks in SR View 2015-12-16 16:43:39 +01:00
Fabrice Marsaud
e7ab1b589a resize disks in VM view 2015-12-16 16:17:15 +01:00
Fabrice Marsaud
e9979c9887 Human readable sizes for editing template disks on VM creation 2015-12-16 16:07:08 +01:00
Olivier Lambert
3bb9bb56f0 better placeholder 2015-12-16 16:07:08 +01:00
Olivier Lambert
5a99474c55 add stuff 2015-12-16 16:07:08 +01:00
Olivier Lambert
182ee6c25f add stuff 2015-12-16 16:07:08 +01:00
Fabrice Marsaud
4d3f0a06db Modfified template disk properties are stored for future update 2015-12-16 16:07:08 +01:00
Fabrice Marsaud
0e182c519b Config drive button looks better 2015-12-16 16:07:08 +01:00
Fabrice Marsaud
b1ee30ce7d cloud config message 2015-12-16 16:07:08 +01:00
Fabrice Marsaud
93ba764e23 Config drive can be toggled, modified template disks data are isolated in the controller 2015-12-16 16:07:08 +01:00
Olivier Lambert
433e17bb81 more comments 2015-12-16 16:07:08 +01:00
Olivier Lambert
61c09083ad more modifications 2015-12-16 16:07:08 +01:00
Olivier Lambert
018377e724 reorder the cloud config at the end of the vm creation process 2015-12-16 16:07:08 +01:00
Olivier Lambert
b76f9513ba various fixes 2015-12-16 16:07:08 +01:00
Olivier Lambert
40ebb7ba75 add a removed by error stuff 2015-12-16 16:07:08 +01:00
Olivier Lambert
a9e52e8954 remove preliminar work in existing VM view 2015-12-16 16:07:08 +01:00
Olivier Lambert
3c8876cac7 Allow cloud drive usage for disk templates VMs 2015-12-16 16:07:08 +01:00
Olivier Lambert
b7e005f9c7 fix an indentation problem 2015-12-16 16:06:37 +01:00
Olivier Lambert
e6fe0a19fa Merge pull request #596 from vatesfr/olivierlambert-clean-size-to-byte
clean size to byte filter
2015-12-16 16:04:07 +01:00
Olivier Lambert
fba11b6a44 fix a useless filter 2015-12-16 16:01:10 +01:00
Olivier Lambert
c270e7f5dd clean size to byte filter 2015-12-16 15:41:42 +01:00
Pierre
9ee00d345e Settings: the servers list should not re-order while a field is being edited. (Fix #594)
The angular `orderBy` is triggered when the server list is triggered ie every 3 seconds when every text fields are unfocused.
2015-12-16 13:47:13 +01:00
Julien Fontanet
0379fbc4eb Merge pull request #590 from vatesfr/pierre-no-refresh-when-focus
Servers should not refresh while a field is being edited
2015-12-16 13:44:43 +01:00
Olivier Lambert
9748a3ae91 display correct size in interface (binary scale). fix #592 2015-12-16 11:23:37 +01:00
Pierre
1881944748 Servers infos should not refresh while a field is being edited 2015-12-15 16:56:52 +01:00
Olivier Lambert
3721fa194c remove metadata export. Fix #580 2015-12-11 16:38:03 +01:00
Olivier Lambert
8c3fcad20b Merge pull request #574 from vatesfr/marsaudf-prevent-add-host#466
Check IP of a new server to avoid double connection. Fix #466
2015-12-10 14:02:41 +01:00
Fabrice Marsaud
decf373d0b Check IP of a new server to avoid double connection 2015-12-10 12:25:04 +01:00
Olivier Lambert
ff1d50f993 Merge pull request #573 from vatesfr/olivierlambert-set-default-sr
set default SR. Fix #572
2015-12-10 12:14:14 +01:00
Olivier Lambert
ef34204b59 set default SR. Fix #572 2015-12-10 12:10:47 +01:00
Olivier Lambert
270b636d80 Merge pull request #569 from vatesfr/pierre-users-cannot-add-tags-on-disks
Non-admin users don't see the '+' button to add a tag (Fix Issue #516)
2015-12-09 19:22:48 +01:00
Olivier Lambert
ac01da2ae9 Merge pull request #570 from vatesfr/marsaudf-run-job#562
Buttons to run jobs for one shot (backup or job manager). Fix #570
2015-12-09 19:17:13 +01:00
Fabrice Marsaud
0136310c54 Buttons to run jobs for one shot (backup or job manager) 2015-12-09 16:57:50 +01:00
Pierre
ecf4cf852e Non-admin users don't see the '+' button to add a tag (Issue #516) 2015-12-09 16:51:12 +01:00
Olivier Lambert
c66384adfb Merge pull request #566 from vatesfr/olivierlambert-recoveryStart
Generic recovery start (both PV and HVM compatible). Fix #564
2015-12-07 18:03:33 +01:00
Olivier Lambert
98bdda629d Order ISOs by their name. Fix #565 2015-12-07 17:28:48 +01:00
Olivier Lambert
a8286f9cba minor fix 2015-12-07 17:22:40 +01:00
Olivier Lambert
fa3db4fcf6 Generic recovery start (both PV and HVM) 2015-12-07 15:43:46 +01:00
Olivier Lambert
ddac0cfee1 Display failures on VM boot order modification. Fix #560 2015-12-07 13:48:32 +01:00
Olivier Lambert
9368673459 Display PV args for PV guest even if they are empty. Fix #557 2015-12-07 13:37:25 +01:00
Olivier Lambert
43dc999ab5 display boot order only for HVM guests. Fix #558 2015-12-07 13:32:21 +01:00
Olivier Lambert
3b7333e866 remove most of the left margin 2015-12-04 14:11:38 +01:00
Olivier Lambert
bc0ddbaf16 Merge pull request #554 from vatesfr/abhamonr-plugin-config-avoid-reset-form
Avoid plugin config form reset. Fix #529
2015-12-04 12:38:23 +01:00
Olivier Lambert
45f0ae7e1c Merge pull request #425 from vatesfr/pierre-search-bar
Improved search bar
2015-12-04 12:35:35 +01:00
Pierre
a521c4ae01 Clicking on the search button will always bring to the list view. Lag fix when the text field is emptied. Transparent background for filter menus. 2015-12-04 12:00:55 +01:00
Julien Fontanet
8e5dee79e0 Use Babel 6. 2015-12-04 11:49:19 +01:00
Pierre
5b8238adeb 2 filter menus : 'Types' and 'States'. FontAwesome checkboxes. Bug fix. 2015-12-04 10:48:32 +01:00
Pierre
ec330474fa The 'Filters' menu is below the search bar and appears only in the list view. *disconnected filter shows hosts and SRs which have at least 1 PBD not attached. 2015-12-04 10:48:32 +01:00
Pierre
ece28904a8 All the checkboxes are unchecked when the search field is empty 2015-12-04 10:48:32 +01:00
Pierre
4f1c495afb Added *disconnected option. Added a 'Filters' dropdown menu in the search bar to add/remove options with a Github like behaviour 2015-12-04 10:48:32 +01:00
Pierre
5fdd27b7e6 Added option key-word *halted 2015-12-04 10:48:32 +01:00
Pierre
91f449af9a Search improvements
1) select several types of objects (eg: *vm *host)
2) combine types and states (eg: *vm *running)
3) negation is considered as an option
2015-12-04 10:48:32 +01:00
Pierre
efc0a0dfe3 Added '*running' option to show only running entities (for VMs and hosts). This option can be banned (statusrunning) to show only not running entities 2015-12-04 10:48:32 +01:00
Pierre
fee47baa66 Added key-words to ban some objects from search list (host, vm, sr, pool) + Back to tree view when search field is empty 2015-12-04 10:48:32 +01:00
Julien Fontanet
9abd9d20ec Initial work on React/Redux. 2015-12-03 18:22:13 +01:00
wescoeur
0ad7bfc7e7 Avoid plugin config form reset. 2015-12-03 15:11:44 +01:00
Julien Fontanet
bd64143ae1 Merge pull request #551 from vatesfr/abhamonr-plugin-root-integer-properties
Root integer properties can be edited in plugins configuration form. …
2015-12-03 15:09:52 +01:00
wescoeur
ec982ba9a3 Root integer properties can be edited in plugins configuration form. fix #550 2015-12-03 15:03:47 +01:00
Julien Fontanet
6280f6ff98 Merge pull request #542 from vatesfr/abhamonr-purge-plugin-config
The plugins configurations can be cleaned.
2015-12-03 14:37:52 +01:00
Olivier Lambert
35d20390a9 hide non auhorized containers for VMs (host or pool). Fix #545 2015-12-03 14:23:32 +01:00
wescoeur
c487c5042f The plugins configurations can be cleaned. fix #539 2015-12-02 16:14:36 +01:00
Olivier Lambert
aaf7927aa2 Cloud config default SR. (Fix #548) 2015-11-30 18:45:29 +01:00
Julien Fontanet
3c677f3d21 Merge pull request #544 from vatesfr/abhamonr-plugin-config-boolean-default-value
Plugin config boolean properties have a default false value.
2015-11-27 17:01:22 +01:00
wescoeur
94eb76b3a6 Plugin config boolean properties have a default false value. fix #543 2015-11-27 16:49:46 +01:00
Julien Fontanet
a921cb2d0d 4.10.0 2015-11-27 14:35:50 +01:00
Olivier Lambert
f3aaa363d8 Merge pull request #541 from vatesfr/marsaudf-UI-fix
Minor UI fix
2015-11-27 13:39:20 +01:00
Fabrice Marsaud
45a79e1920 Minor UI fix 2015-11-27 13:35:27 +01:00
Olivier Lambert
6fd9b2a453 Merge pull request #493 from vatesfr/marsaudf-task-manager
Generic task manager
2015-11-27 12:03:01 +01:00
Olivier Lambert
01d8e89a71 add changelog 2015-11-27 11:58:00 +01:00
Fabrice Marsaud
c89fa63910 Minor UI fix 2015-11-27 11:25:23 +01:00
Fabrice Marsaud
9fc5c49dbf UI enhancements 2015-11-27 11:25:23 +01:00
Fabrice Marsaud
7dfc269df9 Enhanced UI inputs for XO object management 2015-11-27 11:25:18 +01:00
Fabrice Marsaud
76d0b397db Instant one shot for generic jobs 2015-11-27 11:24:25 +01:00
Fabrice Marsaud
5413f887af Bare generic job creation and scheduling 2015-11-27 11:24:13 +01:00
Julien Fontanet
b3d0c61f0e Merge pull request #540 from vatesfr/abhamonr-plugin-input-type-number
Plugin 'number' property use input number in config form (fix #538)
2015-11-27 10:49:32 +01:00
wescoeur
4ce0441d68 Plugin 'number' property use input number in config form 2015-11-27 10:42:45 +01:00
Julien Fontanet
72be34e18d Move clipboard to dev deps. 2015-11-27 10:04:43 +01:00
Julien Fontanet
d2961b7650 Merge pull request #537 from vatesfr/abhamonr-plugins-supports-numbers
Plugin config supports integer properties (fix #531).
2015-11-27 09:54:46 +01:00
wescoeur
fdca1bbf72 Plugin config supports integer properties. 2015-11-27 09:43:33 +01:00
Julien Fontanet
ab7a2f9dee Merge pull request #536 from vatesfr/abhamonr-plugin-boolean-checkbox
Plugin boolean properties use checkboxes (fix #528).
2015-11-27 09:42:06 +01:00
wescoeur
7b72857a3b Plugin boolean properties use checkboxes 2015-11-26 22:44:24 +01:00
Olivier Lambert
4787146658 Merge pull request #533 from vatesfr/marsaudf-backup-ui
better backup log display
2015-11-26 16:30:18 +01:00
Fabrice Marsaud
430f9356c3 Minor button fix 2015-11-26 16:27:40 +01:00
Fabrice Marsaud
70a3b3518f Better schedule state UI in overview 2015-11-26 16:25:00 +01:00
Fabrice Marsaud
c0944c17e0 better backup log display 2015-11-26 16:07:47 +01:00
Julien Fontanet
da1b2a91e7 Merge pull request #526 from vatesfr/pierre-console-keyboard-unfocus
Console has keyboard and mouse focus only when mouse is hovering
2015-11-26 15:59:48 +01:00
Pierre
aa27492713 Console catches keyboard and mouse inputs only when mouse is hovering.
Also, when the mouse enters the VM screen, the current active element is unfocused.
2015-11-26 15:44:01 +01:00
Julien Fontanet
afe589dec3 Merge pull request #527 from vatesfr/abhamonr-plugin-title-property
Support title property in plugin configuration schema
2015-11-26 15:25:25 +01:00
wescoeur
978d140c8f Support title property in plugin configuration schema 2015-11-26 14:31:32 +01:00
Olivier Lambert
2ce213b62c Merge pull request #525 from vatesfr/pierre-clipboard-management-through-console
Clipboard management through console
2015-11-26 11:35:57 +01:00
Pierre
7748266078 Clipboard support in console.
- From VM to client :
	1) Copy text in VM
	2) The text field (above the console) updates automatically with the VM's clipboard content
	3) Click on the 'Copy' button to get the text in the local clipboard
- From client to VM :
	1) Write text in the text field
	2) The VM's clipboard updates automatically with the new content
	3) Paste text anywhere in the VM
2015-11-26 11:23:40 +01:00
Olivier Lambert
83783d07a1 hide action panel for host or VM if only viewer 2015-11-25 14:38:47 +01:00
Olivier Lambert
49a1f2c7c5 Merge pull request #517 from vatesfr/marsaudf-disable-host-buttons#474
Disable host buttons relying on ACLs
2015-11-25 14:31:49 +01:00
Olivier Lambert
ddfc0151fc Merge pull request #515 from vatesfr/marsaudf-backup-display#512
Tag display for backup schedules in overview #512
2015-11-25 14:01:33 +01:00
Fabrice Marsaud
81c508e13c Host view OK 2015-11-25 10:25:10 +01:00
Fabrice Marsaud
7195cfc3cf First step 2015-11-24 17:31:26 +01:00
Fabrice Marsaud
93fe5e2cf7 PR feedback 2015-11-24 17:31:00 +01:00
Fabrice Marsaud
a2bf795d12 Tag display for backup schedules in overview 2015-11-24 17:31:00 +01:00
Julien Fontanet
c8d78f39e0 Upgrade npm to latest on Travis. 2015-11-24 17:17:58 +01:00
Fabrice Marsaud
d9ab8a1c8b Fix #508 2015-11-23 15:24:23 +01:00
Olivier Lambert
5125ad4889 Merge pull request #506 from vatesfr/pierre-emergency-host-shutdown
Emergency button in host view is now calling the server function
2015-11-20 17:32:17 +01:00
Olivier Lambert
951e85b04b Merge pull request #507 from vatesfr/olivierlambert-cloudconfig
CoreOS cloud config management during VM creation
2015-11-20 17:32:10 +01:00
Olivier Lambert
711d922695 CoreOS cloud config during VM creation 2015-11-20 17:10:10 +01:00
Pierre
3692ffcde7 Rename function : emergencyHostShutdown -> emergencyShutdownHost 2015-11-20 10:19:06 +01:00
Pierre
b049420c59 Emergency button in host view is now calling the server function (suspends all the VMs running on the host and then shuts the host down) 2015-11-19 17:07:10 +01:00
Olivier Lambert
241103c369 Merge pull request #501 from vatesfr/pierre-install-patches-on-all-pools
Created panel in dashboard
2015-11-19 14:49:59 +01:00
Pierre
2128367113 Update panel in dashboard. 2015-11-19 12:29:48 +01:00
Julien Fontanet
f555c8190d Revert "nvm (on Travis) does not use stable correctly."
This reverts commit f85dc3b7e7.
2015-11-18 17:32:54 +01:00
Pierre
d5df633def Removed some useless CSS 2015-11-18 17:13:54 +01:00
Olivier Lambert
fe7dc859e3 Merge pull request #499 from vatesfr/pierre-suspend-all-vms-and-shutdown-host
emergency shutdown feature in host view (suspend all VMs then shutdown)
2015-11-18 17:04:04 +01:00
Pierre
569c5046c6 Added an emergency button in Action panel (host view) : suspends all the VMs and shuts the host down. 2015-11-18 16:56:56 +01:00
Julien Fontanet
e0210ae2d8 Stable is the new stable branch. 2015-11-18 16:30:30 +01:00
Julien Fontanet
f85dc3b7e7 nvm (on Travis) does not use stable correctly. 2015-11-18 16:10:07 +01:00
Olivier Lambert
92d4363120 tree view improvements and fix 2015-11-17 15:18:57 +01:00
Olivier Lambert
6c69220de2 add start in recovery mode for HVM guests and support new API call setBootOrder() instead of bootOrder() 2015-11-17 14:59:26 +01:00
Julien Fontanet
3a1229b072 Only test on stable as there is just linting for now. 2015-11-16 16:59:55 +01:00
Olivier Lambert
45538c9f62 add quiesce display in VM view 2015-11-16 13:28:51 +01:00
Julien Fontanet
0c173fde53 Explicit .scss for angular-notify-toaster (fix #488). 2015-11-13 11:53:32 +01:00
Julien Fontanet
77db2bbfec 4.9.0 2015-11-13 11:31:19 +01:00
Julien Fontanet
2987185a9d Fix coding style. 2015-11-13 11:30:47 +01:00
Olivier Lambert
7a7baf7175 change the release date 2015-11-12 16:54:30 +01:00
Olivier Lambert
5645cc0af2 removing an entry in the changelog 2015-11-12 12:35:46 +01:00
Olivier Lambert
63a6756fed add changelog 2015-11-12 11:37:31 +01:00
Olivier Lambert
9f408c98a6 Merge pull request #480 from vatesfr/marsaudf-vm-copy-sr
Copy VM
2015-11-12 11:16:25 +01:00
Olivier Lambert
26d6998d82 Merge pull request #485 from vatesfr/abhamonr-perf-12-cpus
for cpus graph: draw only one line which is an average of all CPUs (i…
2015-11-12 11:06:08 +01:00
wescoeur
6bee44acb7 for cpus graph: draw only one line which is an average of all CPUs (if more than 12 cores) 2015-11-12 10:38:37 +01:00
Fabrice Marsaud
441992cf37 Copy VM, first delivery 2015-11-12 10:33:46 +01:00
Fabrice Marsaud
490c224ac3 Merge pull request #469 from vatesfr/marsaudf-disaster-recovery
Disaster Recovery
2015-11-12 10:31:39 +01:00
Fabrice Marsaud
f5c55048de DR UI enhancemnts 2015-11-12 10:19:49 +01:00
Fabrice Marsaud
8139e124c2 DR features fixes 2015-11-12 10:19:49 +01:00
Fabrice Marsaud
cba73a5139 Disaster recovery feature 2015-11-12 10:19:48 +01:00
Fabrice Marsaud
de0c9367e5 Merge pull request #483 from vatesfr/abhamonr-backup-logs
Abhamonr backup logs
2015-11-12 10:11:44 +01:00
Fabrice Marsaud
630060860c Backup log UI fix 2015-11-12 10:09:09 +01:00
Fabrice Marsaud
dccd11fb7b Backup logs UI 2015-11-12 10:09:09 +01:00
Olivier Lambert
b8a4b2cf16 add duration filter 2015-11-12 10:09:09 +01:00
wescoeur
e52f55bfba backup view (logs) in progress 2015-11-12 10:09:09 +01:00
wescoeur
1cb99e02a9 Logs of jobs in progress in backup/management view 2015-11-12 10:09:09 +01:00
Fabrice Marsaud
c9c5c35e56 Merge pull request #476 from vatesfr/abhamonr-backup-logs
Abhamonr backup logs
2015-11-12 10:06:34 +01:00
Olivier Lambert
bc7c9f9c01 fix inversion in vCPUs and CPUs in dashboard view 2015-11-11 22:10:52 +01:00
Fabrice Marsaud
e4bfc4cb8d Better chosen objects display in ACL UI 2015-11-11 17:44:19 +01:00
Fabrice Marsaud
d64995c4a1 Backup log UI fix 2015-11-10 17:08:59 +01:00
Fabrice Marsaud
2952ea7404 Backup logs UI 2015-11-10 17:08:59 +01:00
Olivier Lambert
f34c807a2c add duration filter 2015-11-10 17:08:59 +01:00
wescoeur
b1f9704055 backup view (logs) in progress 2015-11-10 17:08:59 +01:00
wescoeur
9382829ba5 Logs of jobs in progress in backup/management view 2015-11-10 17:08:59 +01:00
Fabrice Marsaud
373a6ea912 Merge pull request #479 from vatesfr/marsaudf-backup-fixes
Backup UI enhancements
2015-11-10 16:53:00 +01:00
Fabrice Marsaud
72eb4e7b3b Backup UI enhancements 2015-11-10 15:21:24 +01:00
Julien Fontanet
315c0870ed Fix VM exports when not directly under /. 2015-11-09 16:13:17 +01:00
Olivier Lambert
200fa621bf use the new xenTools method 2015-11-06 13:54:13 +01:00
Fabrice Marsaud
80348c1980 Patched a display delay for some stats 2015-11-06 13:47:01 +01:00
Fabrice Marsaud
856dd8403c Patched stat display bug 2015-11-06 13:39:23 +01:00
Olivier Lambert
0bb9acd4c1 Merge pull request #470 from vatesfr/marsaudf-backup-no-compression
Compression can be disabled for backups
2015-11-06 11:40:06 +01:00
Fabrice Marsaud
047a80917f Compression can be disabled for backups 2015-11-06 11:37:31 +01:00
Fabrice Marsaud
e6e8fe4763 Fixed backup overview links 2015-11-06 11:36:17 +01:00
Olivier Lambert
6cd212398e Merge pull request #473 from vatesfr/marsaudf-fix-convertToTemplate
Back to index after VM converts to template
2015-11-06 11:10:34 +01:00
Fabrice Marsaud
44ad6d4247 Back to index after VM converts to template 2015-11-06 11:07:42 +01:00
Olivier Lambert
7302782853 Merge pull request #465 from vatesfr/marsaudf-restore-backup
Restore backups
2015-11-05 15:47:04 +01:00
Fabrice Marsaud
7fa1aba6b8 Backup restore and global backup UI rework 2015-11-05 15:18:01 +01:00
Julien Fontanet
2fed4e3e8b Update deps. 2015-11-03 12:08:05 +01:00
Julien Fontanet
bd343c51a3 4.8.0 2015-10-29 10:43:17 +01:00
Olivier Lambert
8a05f06efa changelog update 2015-10-28 17:56:51 +01:00
Julien Fontanet
27b049eada Fix permissions checking for XO admins. 2015-10-28 16:43:50 +01:00
Julien Fontanet
2d1afb5291 Fixes some permissions checking. 2015-10-28 16:24:13 +01:00
Olivier Lambert
63c17a3abf Merge pull request #456 from vatesfr/abhamonr-avoid-use-of-vms-offline-on-dashboard
Avoid the selection of vms or hosts which are not in the running state
2015-10-28 16:14:57 +01:00
wescoeur
94f9bc5fca Avoid the selection of vms or hosts which are not the running state 2015-10-28 15:46:04 +01:00
Julien Fontanet
ab273430d2 Merge pull request #455 from vatesfr/julien-f-acl-inheritance
Adapt to new ACLs API (and implement inheritance).
2015-10-28 15:30:05 +01:00
Julien Fontanet
0b3dc315ad Adapt to new ACLs API (and implement inheritance). 2015-10-28 15:09:08 +01:00
Olivier Lambert
f26a2d2f13 remove old parameter for granularity 2015-10-28 14:59:57 +01:00
Olivier Lambert
8edf9bf508 Merge pull request #454 from vatesfr/abhamonr-intelligent-stats
Remove default value of granularity in refreshStats
2015-10-28 14:44:20 +01:00
Olivier Lambert
415381cebd fix a missing char in the Jade template 2015-10-28 14:41:29 +01:00
wescoeur
59accec1c0 remove default value of granularity in refreshStats 2015-10-28 14:35:55 +01:00
Olivier Lambert
dd2699fcc1 Merge pull request #453 from vatesfr/abhamonr-intelligent-stats
host, vm and dashboard/health pages use now the new stats format prov…
2015-10-28 13:53:14 +01:00
wescoeur
0986a5f985 host, vm and dashboard/health pages use now the new stats format provided by the server 2015-10-28 12:51:13 +01:00
Olivier Lambert
fa77229b72 Merge pull request #452 from vatesfr/proxy-auth-updater
Proxy auth for update panel
2015-10-28 11:52:31 +01:00
Olivier Lambert
78b5080c9a Merge pull request #440 from vatesfr/reg-renewal#424
Xoa registration can be renewed
2015-10-28 10:49:15 +01:00
Fabrice Marsaud
0641da786c Proxy auth for update panel 2015-10-27 16:05:31 +01:00
Olivier Lambert
3291f3bb3c initial CHANGELOG for 4.8 2015-10-27 14:30:41 +01:00
Olivier Lambert
a0cfef8bda Merge pull request #444 from vatesfr/pierre-install-all-patches-button
Added button to install all the missing patches on host at one go
2015-10-26 15:23:50 +01:00
Julien Fontanet
4d033f4a03 Direct links work again (fix #371). 2015-10-26 12:41:45 +01:00
Pierre
562820180c Added button to install all the missing patches on host at one go 2015-10-23 15:48:03 +02:00
Olivier Lambert
a29832207e Merge pull request #443 from vatesfr/pierre-fix-patches-display
In host : fixed uploaded patches properties (name, description, uuid)
2015-10-23 15:28:29 +02:00
Pierre
2afd549826 In host : fixed uploaded patches properties (name, description, uuid) 2015-10-23 15:21:50 +02:00
Olivier Lambert
8a71b2c6dd Merge pull request #430 from vatesfr/pierre-2-status-patches
Patches installed on a host appear as 'Applied' or 'Not applied' and …
2015-10-23 15:11:08 +02:00
Pierre
d633d2691d Patches installed on a host do not appear as missing 2015-10-23 14:43:44 +02:00
Fabrice Marsaud
f9b1608fd2 Xoa registration can be renewed 2015-10-21 12:34:13 +02:00
Julien Fontanet
4d8ed3f00e Use bundler collapser for production build. 2015-10-21 11:28:46 +02:00
Julien Fontanet
359e7d0543 Merge pull request #437 from vatesfr/julien-f-hvm-network-install
Add PXE installation method for HVM templates. (fix #436)
2015-10-19 15:12:37 +02:00
Julien Fontanet
07bf93e022 Add PXE installation method for HVM templates. (fix #436) 2015-10-19 15:11:43 +02:00
Olivier Lambert
57e27da0c4 update style 2015-10-13 19:19:11 +02:00
Olivier Lambert
9ecbf62d25 fix #136 by adding FreeBSD icons from another icon pack 2015-10-13 18:56:23 +02:00
Olivier Lambert
48ffa591ca display the correct distro icons 2015-10-13 18:46:23 +02:00
Olivier Lambert
b7dd617bb1 update filter 2015-10-13 18:46:23 +02:00
Olivier Lambert
392f9d0775 install of new fonts Mfizz 2015-10-13 18:46:23 +02:00
Fabrice Marsaud
4361b11c68 4.7.0 2015-10-12 16:56:56 +02:00
Fabrice Marsaud
28bccad010 No plugin message 2015-10-12 16:44:47 +02:00
Fabrice Marsaud
29d31a0deb Cleaner plugin conf saving 2015-10-12 16:17:39 +02:00
Fabrice Marsaud
1d9960d349 Plugin configuration fixed and enhanced 2015-10-12 14:49:09 +02:00
Fabrice Marsaud
2747b241ab Notification for plugin conf saved 2015-10-12 12:13:32 +02:00
Fabrice Marsaud
6b8035b116 Plugin conf supports default values + fixes 2015-10-12 11:57:11 +02:00
Olivier Lambert
33ad5f4d45 release date 2015-10-12 10:56:06 +02:00
Fabrice Marsaud
af7ad9251a (not)required plugin conf values of object type are handled + fix 2015-10-12 10:54:23 +02:00
Fabrice Marsaud
4ec9975aa3 Merge pull request #416 from vatesfr/pluginConf#352
Plugin conf#352
2015-10-09 17:41:01 +02:00
Fabrice Marsaud
c6b0841583 Plugin configuration panel 2015-10-09 17:35:26 +02:00
Olivier Lambert
9312435076 Merge pull request #422 from vatesfr/pierre-cant-migrate-vm-to-current-host
Removed current host in migrate list. Disabled button when no other h…
2015-10-08 16:24:43 +02:00
Pierre
49427f1c54 Fix : condition for disabled button 2015-10-08 16:22:06 +02:00
Pierre
82e7e06dc4 Fix : button not diabled if host available on another pool 2015-10-08 16:03:08 +02:00
Pierre
76cf82bb19 Removed current host in migrate list. Disabled button when no other host available 2015-10-08 15:46:11 +02:00
Olivier Lambert
4f8ad2962e changelog updated 2015-10-08 15:22:27 +02:00
Olivier Lambert
fe4be48bff remove useless entries in the menu for hosts 2015-10-08 15:05:36 +02:00
Olivier Lambert
66fc0b421b fix tooltip as explained in #421 2015-10-08 15:03:50 +02:00
Olivier Lambert
c0b4867659 Merge pull request #420 from vatesfr/pierre-lone-host-cant-leave-pool
Added condition to remove 'remove host from pool'-button when host is…
2015-10-08 14:51:58 +02:00
Pierre
95253fbc76 Added condition to remove 'remove host from pool'-button when host is alone 2015-10-08 14:26:20 +02:00
Olivier Lambert
df519b3042 Merge pull request #418 from vatesfr/pierre-add-host-to-pool
Added button to merge host to another pool
2015-10-08 12:30:37 +02:00
Pierre
9ed963ef70 Modified icon for 'moving host to another pool' 2015-10-08 12:26:06 +02:00
Pierre
1dd7993e7a Added button to mode host to another pool. Doesn't work yet 2015-10-08 11:55:03 +02:00
Olivier Lambert
386b33b65d Merge pull request #411 from vatesfr/chartswitch
add chart selector for dataviz
2015-10-07 23:57:08 +02:00
florent
416deb8711 chart selector : less opacity and bigger font 2015-10-07 21:50:24 +02:00
florent
3c7fdac55e add navigation between dataviz
also : fix import in health, fix thumbnail size
2015-10-07 21:13:04 +02:00
Olivier Lambert
392a6af47f Merge pull request #415 from vatesfr/abhamonr-pass-generator-on-users
Password generation is implemented with password-generator module.
2015-10-07 17:30:16 +02:00
wescoeur
6b03e3f603 Password generation is implemented with password-generator module.
One button (with tooltip) is visible to the left of each password field.
One click on this button generate one visible password of 8 characters (upper/lower-case letters, underscore, numbers)
2015-10-07 17:24:09 +02:00
Olivier Lambert
9397f6beda minor changelog fix 2015-10-07 15:56:26 +02:00
Olivier Lambert
d17b386fd6 changelog updated 2015-10-07 15:44:50 +02:00
Olivier Lambert
f6d2e1a447 more explicit modal when host is removed from pool 2015-10-07 15:38:41 +02:00
Olivier Lambert
bd95ef5db6 Merge pull request #407 from vatesfr/desktop-notif
Use desktop notification when available and when the browser is minified
2015-10-07 15:13:13 +02:00
Olivier Lambert
6e76c621b8 Merge pull request #413 from vatesfr/pierre-unfocus-on-cd-list
Unfocusing CD list after selecting one
2015-10-07 15:08:11 +02:00
Olivier Lambert
3e58bee0eb Merge pull request #409 from vatesfr/abhamon-ronan-issue-396
Abhamon ronan issue 396
2015-10-07 14:46:25 +02:00
wescoeur
8c2ed1f581 Password viewer button added to right (with tooltip) and only displayed if input is not empty. 2015-10-07 14:41:31 +02:00
Pierre
500dd3bfaf Unfocusing CD list after selecting one 2015-10-07 12:04:35 +02:00
Olivier Lambert
bc7bacd654 remove Travis test on Node 0.10 2015-10-07 10:58:54 +02:00
florent
fa16b990b6 add chart selector for dataviz 2015-10-06 22:06:33 +02:00
Florent BEAUCHAMP
9d5e9dd9e5 Use desktop notification when avilable and when the browser is minified
without jquery, and using angular $window and $document
2015-10-06 20:37:56 +02:00
Olivier Lambert
4046f9dde1 restrict export button for admins only. Fix #410 2015-10-05 16:45:35 +02:00
Julien Fontanet
fcd82ada14 Fix coding styles and test on Travis. 2015-10-02 19:20:13 +02:00
Olivier Lambert
d616da7f67 Merge pull request #399 from vatesfr/circle
first integration of cricle chart
2015-10-01 21:45:43 +02:00
florent
0c81202bbb how circle chart and sunburst charts + bug fix
correct bug where wraptext was going wild with dimension less node
2015-10-01 20:53:43 +02:00
Julien Fontanet
6284bd3f17 Remove an unecessary console.log(). 2015-10-01 18:38:54 +02:00
Julien Fontanet
7adc9d94b4 Upgrade gulp-livereload to 3.8.1 to support npm 3. 2015-10-01 18:38:42 +02:00
florent
73e030d2f5 d3 circle : hide text if fully zoomed out 2015-09-30 22:07:19 +02:00
florent
3a3b45aa04 d3 charts : externalize a breadcrumbs directive
refactor sunburst and circle to use it
2015-09-30 22:00:39 +02:00
florent
81c19e9964 circle : hide virtual node ( like free ram or free disk) 2015-09-30 18:55:12 +02:00
florent
df856bc4a0 zoomable circle chart 2015-09-30 18:31:24 +02:00
florent
8558dc7ee4 first integration of cricle chart, no zoom
Drop in remplacement of sunburst or treemap
2015-09-30 15:14:42 +02:00
Fabrice Marsaud
087d5f6e58 4.6.1 2015-09-25 12:16:17 +02:00
Fabrice Marsaud
9540bc350a Fix a wrong deletion 2015-09-25 12:14:17 +02:00
Julien Fontanet
09153c6c30 Revert "Minor fix in release process."
This reverts commit 8dbab73d2b.

The release process was already correct.
2015-09-25 10:18:46 +02:00
Olivier Lambert
f66d81f147 4.6.0 2015-09-25 00:10:29 +02:00
Olivier Lambert
75925143b6 Merge pull request #395 from vatesfr/cubism
Multigraph, resolve issue #358
2015-09-24 21:37:28 +02:00
Florent BEAUCHAMP
e7dc00991e remove cubism from package.json 2015-09-24 21:26:45 +02:00
Florent BEAUCHAMP
dd9da82ed3 Merge branch 'cubism' of https://github.com/vatesfr/xo-web into cubism 2015-09-24 21:18:59 +02:00
Florent BEAUCHAMP
c995b8fa81 horizon: sort metrics name, rename cpu average to all cpus 2015-09-24 21:15:53 +02:00
Florent BEAUCHAMP
e7c2994ea3 horizon : delete last traces of cubism 2015-09-24 21:15:52 +02:00
Florent BEAUCHAMP
106997b26c horizon responsive 2015-09-24 21:15:51 +02:00
Florent BEAUCHAMP
fa842c1566 horizon : smaller label on date axis 2015-09-24 21:15:50 +02:00
Florent BEAUCHAMP
be03dd82f9 remove cubism 2015-09-24 21:15:49 +02:00
Florent BEAUCHAMP
39c46995e1 horizon : properly clean existing label 2015-09-24 21:15:48 +02:00
Florent BEAUCHAMP
97adc01e8d horizon : replace checkbox by button, remove bold 2015-09-24 21:15:47 +02:00
Florent BEAUCHAMP
36be881741 handle missing value 2015-09-24 21:15:45 +02:00
Florent BEAUCHAMP
955cc6dff5 horizon : add filter on hover 2015-09-24 21:15:44 +02:00
Florent BEAUCHAMP
2be1399eda horizon : add label, center label vertically, add a checkbox to
synchronize scales
2015-09-24 21:15:43 +02:00
Olivier Lambert
ef5d2a7654 change the panel title 2015-09-24 21:09:56 +02:00
Florent BEAUCHAMP
1cd00cab62 horizon : synchronize scales 2015-09-24 21:09:54 +02:00
Olivier Lambert
7652c231f6 case for foreach 2015-09-24 21:09:53 +02:00
Florent BEAUCHAMP
e17cdf0ca7 horizon : over text lighter 2015-09-24 21:09:51 +02:00
Florent BEAUCHAMP
3317791e68 rizons : two numbers 2015-09-24 21:09:50 +02:00
Florent BEAUCHAMP
c3871bc2ec Horizon : hide cpu x in metrics list 2015-09-24 21:09:49 +02:00
Florent BEAUCHAMP
ebba86f741 horizon : add label before chart
better handling of form when loading new metrics
2015-09-24 21:09:47 +02:00
Florent BEAUCHAMP
5ac84a6a02 replace cubism with a custom implementation 2015-09-24 21:09:46 +02:00
Florent BEAUCHAMP
cf3e9704e8 wip 2015-09-24 21:09:44 +02:00
Florent BEAUCHAMP
37eac8afcf formatting 2015-09-24 21:09:43 +02:00
Florent BEAUCHAMP
692a0535ff move cubism from dataviz to health 2015-09-24 21:09:42 +02:00
Olivier Lambert
0f0d804052 fix a typo in clonedeep import and save the depencency 2015-09-24 21:09:40 +02:00
florent
d189e6b53d first integration of cubism 2015-09-24 21:08:56 +02:00
Florent BEAUCHAMP
5da31691a9 horizon: sort metrics name, rename cpu average to all cpus 2015-09-24 21:02:34 +02:00
Florent BEAUCHAMP
4059a4fd9a horizon : delete last traces of cubism 2015-09-24 20:47:20 +02:00
Florent BEAUCHAMP
e56da71856 horizon responsive 2015-09-24 20:40:15 +02:00
Florent BEAUCHAMP
91e10f627f horizon : smaller label on date axis 2015-09-24 20:04:52 +02:00
Florent BEAUCHAMP
338c686e8d remove cubism 2015-09-24 19:53:31 +02:00
Florent BEAUCHAMP
0007e9ea2b horizon : properly clean existing label 2015-09-24 19:50:08 +02:00
Florent BEAUCHAMP
1e09e9b322 horizon : replace checkbox by button, remove bold 2015-09-24 19:13:48 +02:00
Florent BEAUCHAMP
43c358119a handle missing value 2015-09-24 18:48:03 +02:00
Florent BEAUCHAMP
7a0f251ebd horizon : add filter on hover 2015-09-24 18:36:17 +02:00
Florent BEAUCHAMP
e989321c5f Merge branch 'cubism' of https://github.com/vatesfr/xo-web into cubism 2015-09-24 18:12:42 +02:00
Florent BEAUCHAMP
56f27e6aaa horizon : add label, center label vertically, add a checkbox to
synchronize scales
2015-09-24 18:08:36 +02:00
Julien Fontanet
7c4e5aa667 Move lodash.debounce to dev deps. 2015-09-24 16:48:12 +02:00
Julien Fontanet
d253d826bb Update xo-lib to 0.7.3 to support Node 4. 2015-09-24 16:47:57 +02:00
Olivier Lambert
888fa20ca3 update the changelog 2015-09-24 12:13:31 +02:00
Julien Fontanet
598dbb2b7a Typos. 2015-09-24 11:37:02 +02:00
Julien Fontanet
71eb1eab14 Properly handles invalid auth tokens. 2015-09-24 11:09:22 +02:00
Olivier Lambert
62a6bd99e8 Merge pull request #393 from vatesfr/issue#237
Rely on unified server-side VM migrate
2015-09-24 10:27:29 +02:00
Olivier Lambert
174cdf2149 fix issue #394 2015-09-24 10:24:10 +02:00
Olivier Lambert
5267fbce7b change the panel title 2015-09-23 23:00:18 +02:00
Fabrice Marsaud
dd814e7e95 removed late migrate notification 2015-09-23 22:41:50 +02:00
Florent BEAUCHAMP
f806b45d3d Merge branch 'cubism' of https://github.com/vatesfr/xo-web into cubism 2015-09-23 22:35:30 +02:00
Florent BEAUCHAMP
8575e9eabe horizon : synchronize scales 2015-09-23 22:34:50 +02:00
Olivier Lambert
6ff9e22049 case for foreach 2015-09-23 22:18:42 +02:00
Fabrice Marsaud
caa86fdab7 Rely on unified server-side VM migrate 2015-09-23 22:15:19 +02:00
Florent BEAUCHAMP
48246716cc horizon : over text lighter 2015-09-23 22:04:29 +02:00
Florent BEAUCHAMP
6e07429e8a rizons : two numbers 2015-09-23 22:01:41 +02:00
Florent BEAUCHAMP
1a271c32b6 Horizon : hide cpu x in metrics list 2015-09-23 21:57:07 +02:00
Florent BEAUCHAMP
3fddec8f20 horizon : add label before chart
better handling of form when loading new metrics
2015-09-23 21:42:11 +02:00
Florent BEAUCHAMP
ac3944aece replace cubism with a custom implementation 2015-09-23 20:59:25 +02:00
Florent BEAUCHAMP
958cc2a50c wip 2015-09-22 23:17:32 +02:00
Florent BEAUCHAMP
058dfcfa9f Merge branch 'cubism' of https://github.com/vatesfr/xo-web into cubism 2015-09-22 19:09:35 +02:00
Florent BEAUCHAMP
9dbb1ca386 formatting 2015-09-22 19:06:01 +02:00
Florent BEAUCHAMP
4d1def6e9d move cubism from dataviz to health 2015-09-22 18:51:51 +02:00
Olivier Lambert
ff763b0278 fix a typo in clonedeep import and save the depencency 2015-09-22 13:28:04 +02:00
florent
74f611e0fd first integration of cubism 2015-09-22 09:23:28 +02:00
Olivier Lambert
61f8be1c60 Merge pull request #388 from vatesfr/issue#222
Filter for SR view VDIs #222
2015-09-17 18:01:41 +02:00
Olivier Lambert
96b18dab00 just add a placeholder in the filter for VDIs 2015-09-17 18:01:12 +02:00
Fabrice Marsaud
0a21b239bc Filter for SR view VDIs #222 2015-09-17 17:51:55 +02:00
Olivier Lambert
9c3589aea4 add PV args during VM creation. Fix #112 2015-09-17 16:36:14 +02:00
Olivier Lambert
2433485d13 Merge pull request #387 from vatesfr/issue#350
Issue#350
2015-09-17 14:56:21 +02:00
Fabrice Marsaud
6b5f254e0a Confirmations on tree and SR view 2015-09-17 14:51:33 +02:00
Fabrice Marsaud
e1b41b1e26 Additional confirmations for console view 2015-09-17 14:51:33 +02:00
Fabrice Marsaud
bd7a265df0 Additional confirmations for VM view 2015-09-17 14:51:33 +02:00
Olivier Lambert
039cca9529 Merge pull request #385 from vatesfr/issue#383
Html fixes so form required are no more ignored
2015-09-17 12:35:06 +02:00
Olivier Lambert
963347dbc2 Merge pull request #381 from vatesfr/issue#107
noVnc connection reset on disconnection
2015-09-17 12:19:19 +02:00
Fabrice Marsaud
697cc9f758 Html fixes so form required are no more ignored 2015-09-17 11:00:24 +02:00
Fabrice Marsaud
3892225584 Limited retries to reset consoles after reboot or halt or whatever disconnects... 2015-09-17 10:52:08 +02:00
Fabrice Marsaud
a7880a0ef5 noVnc connection reset on disconnection 2015-09-17 10:52:08 +02:00
Fabrice Marsaud
dd574830f5 Merge pull request #380 from vatesfr/issue#367
Tag management in xo-web
2015-09-17 10:30:10 +02:00
Fabrice Marsaud
71a0d15c35 Tag directive ensures an up to date tag display 2015-09-17 10:25:58 +02:00
Fabrice Marsaud
8a33c4f09a Various enhancements of the tag directive 2015-09-17 10:25:57 +02:00
Fabrice Marsaud
d223ce062a tags for VDIs. A refresh problem in VM view 2015-09-17 10:25:57 +02:00
Fabrice Marsaud
39c8f12963 Fixes for tag management 2015-09-17 10:25:57 +02:00
Fabrice Marsaud
bd4ba8c826 Autofocus, and smaller + button 2015-09-17 10:25:57 +02:00
Fabrice Marsaud
3d38c8e088 Add tag module 2015-09-17 10:25:57 +02:00
Fabrice Marsaud
ce58c80c6d Tag management UI for issue#367 2015-09-17 10:25:57 +02:00
Julien Fontanet
19b3a0781c Deps update. 2015-09-17 10:12:02 +02:00
Olivier Lambert
b42c1971b9 Merge pull request #382 from vatesfr/issue#323
Issue#323
2015-09-16 18:45:14 +02:00
Olivier Lambert
02440941e0 homogenize by using spaces vs nbsp 2015-09-16 17:58:27 +02:00
Olivier Lambert
cd2f986c50 fix a missing space in the list view 2015-09-16 17:56:22 +02:00
Olivier Lambert
e7cbd6b31f Update CHANGELOG.md
Add the fix pushed in the 4.5.1
2015-09-16 15:09:34 +02:00
Fabrice Marsaud
a7f6d5eebd Better order for acl management 2015-09-16 13:45:48 +02:00
Fabrice Marsaud
4f3b8c0906 Acls are editable 2015-09-16 13:45:48 +02:00
Fabrice Marsaud
7126c71943 Merge branch 'master' into next-release 2015-09-16 13:42:27 +02:00
Fabrice Marsaud
489cf16af8 4.5.1 2015-09-16 12:05:00 +02:00
Fabrice Marsaud
b012f44259 Merge pull request #379 from vatesfr/issue378
Fixes issue#378 and adds some cancel edit buttons on VM view. Ready for 4.5.1.
2015-09-16 12:03:00 +02:00
Fabrice Marsaud
5ce765bd27 Fixes issue#378 and adds some cancel edit buttons on VM view 2015-09-16 11:44:46 +02:00
Olivier Lambert
2450edd070 another minor UI fix 2015-09-15 20:01:54 +02:00
Olivier Lambert
fc2a61835c fix edge cases display of tools outdated but installed 2015-09-14 22:12:34 +02:00
Fabrice Marsaud
d06d73d5f7 Merge pull request #376 from vatesfr/issue#362
Any user can manage his password himself
2015-09-14 17:02:10 +02:00
Fabrice Marsaud
2c10996bb3 UI terms 2015-09-14 16:13:33 +02:00
Fabrice Marsaud
b9c85bb1bf Rework on password change 2015-09-14 15:36:22 +02:00
Fabrice Marsaud
f436afb9aa Any user can manage his password himself 2015-09-14 15:36:22 +02:00
Olivier Lambert
750efe4152 Merge pull request #377 from vatesfr/issue#342
Clearer tooltips for heatmap
2015-09-14 14:36:04 +02:00
Fabrice Marsaud
99cee95cd5 Clearer tooltips for heatmap 2015-09-14 14:24:10 +02:00
Olivier Lambert
ec10b84fa6 add new favicon. Fix #369 2015-09-11 22:16:35 +02:00
Olivier Lambert
f0442fe2ce spaces between tags in flat view 2015-09-11 22:16:06 +02:00
Olivier Lambert
7907969696 Merge pull request #372 from vatesfr/issue#368
Fix update panel for issue#368
2015-09-11 18:08:59 +02:00
Julien Fontanet
8dbab73d2b Minor fix in release process. 2015-09-11 18:04:18 +02:00
Fabrice Marsaud
ade8acb4e2 Fix update panel for issue#368 2015-09-11 15:54:08 +02:00
Fabrice Marsaud
9cb78e6954 Fix for Issue#357 2015-09-11 15:34:17 +02:00
Julien Fontanet
e9127bdbb3 4.5.0 2015-09-11 12:59:00 +02:00
Olivier Lambert
9b750bc756 add missing stuff in the changelog 2015-09-10 17:32:22 +02:00
Fabrice Marsaud
c3349e8cc7 Merge pull request #366 from vatesfr/issue#268
Issue#268
2015-09-10 17:24:58 +02:00
Olivier Lambert
f4d7c7f739 hide other buttons 2015-09-10 17:24:55 +02:00
Olivier Lambert
19d51cb1a4 remove a typo 2015-09-10 17:24:55 +02:00
Olivier Lambert
cc9983aa16 hide actions for a viewer and fix others 2015-09-10 17:24:55 +02:00
Fabrice Marsaud
81f8467f66 ng-if solution for unauthorized action button and links 2015-09-10 17:24:55 +02:00
Fabrice Marsaud
df6b23e3c7 disable solution. not very satisfying 2015-09-10 17:24:55 +02:00
Fabrice Marsaud
4dd81e7d59 Merge pull request #365 from vatesfr/issue#330
Issue#330
2015-09-10 17:22:27 +02:00
Fabrice Marsaud
54ce7067b4 Nan and data type bugs fixed 2015-09-10 17:22:32 +02:00
Fabrice Marsaud
2673f790e6 Issue #330 enhanced heatmap, first delivery 2015-09-10 17:22:32 +02:00
Fabrice Marsaud
69bea2ec9b Merge pull request #364 from vatesfr/issue#315
Issue#315
2015-09-10 16:18:58 +02:00
Fabrice Marsaud
37037cf797 Fixed "onlymetadata" backup bugs 2015-09-10 15:59:36 +02:00
Fabrice Marsaud
2a1586aab3 Onlymetadata scheduled backups 2015-09-09 12:12:06 +02:00
florent
915281d138 cleanup and enlarge brush 2015-09-08 23:05:36 +02:00
florent
b53a179ea0 correctly invoke parallel chart + readme + add drag filter 2015-09-08 22:56:32 +02:00
Olivier Lambert
7077e8b50e Merge pull request #359 from vatesfr/dynamic-charts
Dynamic charts
2015-09-08 13:16:57 +02:00
florent
d9181277d9 correct wrong throttle/debounce use * 2015-09-08 12:18:27 +02:00
florent
810c2d6a1a listen to xoApi.onUpdate event to refresh charts, throttle refresh to once every 300ms 2015-09-08 12:18:08 +02:00
Olivier Lambert
f31113fb90 change panel name 2015-09-08 12:08:01 +02:00
florent
1702b9dd37 force domain to start at zero 2015-09-08 12:06:13 +02:00
florent
f8e61c713c first implementation of parrallel chart directive 2015-09-08 12:05:16 +02:00
Julien Fontanet
643132754a xoApi.onUpdate(fn) 2015-09-07 14:10:51 +02:00
Olivier Lambert
4f0a131bd2 fix #341 2015-09-07 13:13:08 +02:00
Olivier Lambert
52aa0350cf update the changelog 2015-09-07 13:12:56 +02:00
Olivier Lambert
c9884f32fe fix #355 2015-09-07 12:36:35 +02:00
Olivier Lambert
aea3ae3d37 fix #356 2015-09-07 12:36:23 +02:00
Olivier Lambert
10f7c3045f fix #348 2015-09-03 15:15:51 +02:00
Olivier Lambert
bf4e158c30 fix #347 2015-09-03 14:48:08 +02:00
Olivier Lambert
4a3155ed22 Merge pull request #346 from vatesfr/performance
Performance improvment
2015-09-02 21:38:03 +02:00
florent
29f1c89fa5 fix sunburst layout on FF/IE 2015-09-02 21:08:54 +02:00
florent
4a92e8a99f improve performance
make suburst graph static and synchronize animation
2015-09-02 20:40:32 +02:00
Olivier Lambert
c6cffb1156 add metadata export in the VM view 2015-09-02 17:15:10 +02:00
Olivier Lambert
f6e4e59905 add outdate tools info in VM view 2015-09-02 15:55:20 +02:00
Olivier Lambert
3a0736c4bf fix #304 2015-09-02 15:43:05 +02:00
Julien Fontanet
47455b2029 Merge pull request #344 from vatesfr/coding-standard
Fix coding style of the dashboard.
2015-09-02 11:24:24 +02:00
Julien Fontanet
05eb7d765f Coding style fixes. 2015-09-02 11:12:37 +02:00
Julien Fontanet
5e786686d0 Remove unecessary dep. 2015-09-02 10:29:40 +02:00
florent
5cb8e3a7c3 comply to coding standards 2015-09-01 20:18:10 +02:00
Fabrice Marsaud
84bd077eac 4.4.0 2015-08-28 17:38:23 +02:00
Julien Fontanet
db39b27119 Fix home page on sign in. 2015-08-28 17:14:59 +02:00
Julien Fontanet
f2d2b35543 Merge pull request #335 from vatesfr/passport
Authentication is moved to xo-server.
2015-08-28 16:09:59 +02:00
Julien Fontanet
5dfd5766f2 Authentication is moved to xo-server. 2015-08-28 15:04:47 +02:00
Fabrice Marsaud
0e4c3e1e92 CSS tree view fixes 2015-08-28 10:53:13 +02:00
Fabrice Marsaud
221f42606c Fixes from Issue#329 2015-08-28 10:45:20 +02:00
Olivier Lambert
742f092ed3 add CSS flexbox issue in the changelog 2015-08-28 10:37:23 +02:00
Fabrice Marsaud
36bffa1475 gulpFilter 3.x 2015-08-28 09:22:35 +02:00
Fabrice Marsaud
936abc1b1a Fix for undefined VDIs (base copy) 2015-08-27 23:45:25 +02:00
Fabrice Marsaud
584bdd545f icon fix 2015-08-27 22:38:12 +02:00
Fabrice Marsaud
99debc18d7 Heatmap modifs 2015-08-27 21:41:34 +02:00
Olivier Lambert
56b896eda0 add better title 2015-08-27 18:27:44 +02:00
Fabrice Marsaud
cab102528d add omitted template 2015-08-27 18:24:29 +02:00
Fabrice Marsaud
1875cdcda2 Imporvements 2015-08-27 18:22:28 +02:00
Fabrice Marsaud
386dcc8d43 Host heatmap seems ok 2015-08-27 17:55:21 +02:00
Fabrice Marsaud
e6d59a47b1 Unstable progress 2015-08-27 17:01:25 +02:00
Fabrice Marsaud
2659393f33 First heatmap correct integration 2015-08-27 17:01:25 +02:00
Fabrice Marsaud
916b2363d9 Fixed storage dataviz (avoid hidden base copy vdis) 2015-08-27 17:01:25 +02:00
Olivier Lambert
bb513790b5 add changelog for 4.4 2015-08-27 17:01:25 +02:00
Olivier Lambert
e5ab15a727 remove permission for dashboard view if non admin 2015-08-27 17:01:25 +02:00
Fabrice Marsaud
bbaa750fda css touches
Conflicts:
	app/modules/dashboard/dataviz/view.jade
2015-08-27 17:01:25 +02:00
Fabrice Marsaud
a46e19210a css touch 2015-08-27 17:01:25 +02:00
Olivier Lambert
9d6772edd1 disable dashboard link menu 2015-08-27 17:01:25 +02:00
Olivier Lambert
3aeaa564a2 remove useless treemap 2015-08-27 17:01:25 +02:00
Olivier Lambert
8baad494e3 minor fixes 2015-08-27 17:01:25 +02:00
florent
fb04753d52 doc dor heatmap 2015-08-27 17:01:25 +02:00
florent
ea37c4ccd8 backport some correction to sunburst charts 2015-08-27 17:01:25 +02:00
florent
80f02b52e1 a littel doc for sunburst 2015-08-27 17:01:25 +02:00
florent
55464845d6 week heatmap 2015-08-27 17:01:25 +02:00
Florent BEAUCHAMP
8aef4bb455 treemap directive 2015-08-27 17:01:25 +02:00
Florent BEAUCHAMP
d8a2adbca2 dataviz refacto : split megacronlller in two bigcontroller 2015-08-27 17:01:25 +02:00
Florent BEAUCHAMP
02e56da08a more transition, less console.log 2015-08-27 17:01:25 +02:00
Florent BEAUCHAMP
9d9f857e73 sunburst : transition 2015-08-27 17:01:25 +02:00
Florent BEAUCHAMP
b140c1e65f dataviz > overview : show shared SRS 2015-08-27 17:01:25 +02:00
Florent BEAUCHAMP
81ff03462e dataviz breadcrumbs are full width 2015-08-27 17:01:25 +02:00
Florent BEAUCHAMP
2ea7c09c84 dataviz : add cursor pointer if applicable 2015-08-27 17:01:25 +02:00
Florent BEAUCHAMP
4163ed212c make dataviz clickable 2015-08-27 17:01:25 +02:00
Florent BEAUCHAMP
c83722c2df dataviz : correct typo in storage sums 2015-08-27 17:01:25 +02:00
Florent BEAUCHAMP
700db655e6 dataviz : storage is now pool > host > SRS > VDI
hide .iso srs
2015-08-27 17:01:25 +02:00
Florent BEAUCHAMP
226428f631 dataviz : replace cpu view by storage view pool>SRS>vdi 2015-08-27 17:01:25 +02:00
Florent BEAUCHAMP
e2b293e49b no udev in overview list 2015-08-27 17:01:25 +02:00
Florent BEAUCHAMP
1f6e9d4660 directive - less border 2015-08-27 17:01:25 +02:00
Florent BEAUCHAMP
ecf2ee888f dataviz : remove logarithmic scale 2015-08-27 17:01:25 +02:00
Florent BEAUCHAMP
1e8eeadb1d switch to a logarithm scale for ram 2015-08-27 17:01:25 +02:00
Florent BEAUCHAMP
e7ceccdd83 dataviz : do not show "virtual pool" for poolless host 2015-08-27 17:01:25 +02:00
Florent BEAUCHAMP
5390b4a4b3 oups, wrong CPU count 2015-08-27 17:01:25 +02:00
Florent BEAUCHAMP
f25ec34bc3 show free ram and cpu 2015-08-27 17:01:24 +02:00
Florent BEAUCHAMP
53ece86816 don't show iso in overview > SR. Order SR by usage ratio desc 2015-08-27 17:01:24 +02:00
Florent BEAUCHAMP
9b128cdfcc add comprehensible tooltip on overview > ram 2015-08-27 17:01:24 +02:00
Florent BEAUCHAMP
c047386755 sunburst : add text info in the center 2015-08-27 17:01:24 +02:00
Florent BEAUCHAMP
b0ffb272b3 sunburst : border width is coherent with graph width 2015-08-27 17:01:24 +02:00
Olivier Lambert
956e21c8db code style now using JS standard 2015-08-27 17:01:24 +02:00
Florent BEAUCHAMP
95057a2b09 use the right visualization 2015-08-27 17:01:24 +02:00
Florent BEAUCHAMP
788aa24a80 overview with real data 2015-08-27 17:01:24 +02:00
Florent BEAUCHAMP
0a72ef91cc less opacity to non hovered sunburst node. text ellipsis in breadcrumbs 2015-08-27 17:01:24 +02:00
Florent BEAUCHAMP
f0f4e0985a sunburst directive : externalized in a module, react to vm changes 2015-08-27 17:01:24 +02:00
Florent BEAUCHAMP
a6bedea4b6 sunburst are responsive 2015-08-27 17:01:24 +02:00
Florent BEAUCHAMP
055316e1ca multiple synchronizated sunburst + breadcrumbs 2015-08-27 17:01:24 +02:00
Olivier Lambert
25fece5947 add initial d3 work of FBP 2015-08-27 17:01:24 +02:00
Olivier Lambert
5ec3cdbcc5 health page mockup 2015-08-27 17:01:24 +02:00
Olivier Lambert
b530ab2ef6 clean copy/pasted code 2015-08-27 17:01:24 +02:00
Olivier Lambert
5164f60c98 Ui fixes for dashboard 2015-08-27 17:01:24 +02:00
Olivier Lambert
19ba3015f7 not responsive graph to avoid a display bug 2015-08-27 17:01:24 +02:00
Olivier Lambert
fb00b2672c start dashboard mockup 2015-08-27 17:01:24 +02:00
Fabrice Marsaud
3e0f936d2a host refreshStats fix 2015-08-27 16:47:58 +02:00
Fabrice Marsaud
f5be146dbb refreshStats fix 2015-08-27 10:01:44 +02:00
Olivier Lambert
95431a0874 disable the scheduler for non admin users 2015-08-26 16:53:15 +02:00
Julien Fontanet
f76b130ca4 Coding style fixes. 2015-08-26 15:03:48 +02:00
Julien Fontanet
d19f8259d0 Upgrade deps. 2015-08-26 15:03:35 +02:00
Julien Fontanet
68cd62d756 Scheduler view is only accessible to admins. 2015-08-26 11:08:58 +02:00
Fabrice Marsaud
ea4a55d3dd grid css enhanced 2015-08-25 19:11:28 +02:00
Fabrice Marsaud
788bdcd35b menu-entry class is back 2015-08-24 18:20:38 +02:00
Fabrice Marsaud
ebd7e24830 group icon fix 2015-08-24 17:21:22 +02:00
Fabrice Marsaud
0b7fbffa0a Icons and styles enhanced a bit 2015-08-24 17:02:14 +02:00
Fabrice Marsaud
2afda9a055 form template touch 2015-08-24 17:02:14 +02:00
Fabrice Marsaud
28dd275bd8 Honest responsive grid 2015-08-24 17:02:14 +02:00
Fabrice Marsaud
9a3cf182ac side menu and other enhancements 2015-08-24 17:02:14 +02:00
Fabrice Marsaud
dd278c28be first steps 2015-08-24 17:02:14 +02:00
Fabrice Marsaud
37572122b0 Reload prompt after upgrade 2015-08-24 16:55:04 +02:00
Fabrice Marsaud
5348f75b5e ACL enhanced object selector 2015-08-10 18:43:44 +02:00
Fabrice Marsaud
6b8873d385 Updater flow and display fixed 2015-07-31 09:27:06 +02:00
Fabrice Marsaud
8db18d87e5 Minor vocabulary fix 2015-07-29 15:18:26 +02:00
Fabrice Marsaud
444920d15c 4.3.0 2015-07-22 15:48:52 +02:00
Fabrice Marsaud
8aa2fab603 Merge branch 'next-release' 2015-07-22 15:39:36 +02:00
Olivier Lambert
9ded4386cc Update CHANGELOG.md 2015-07-22 15:16:13 +02:00
Fabrice Marsaud
cc6b1b5aa1 Fixed delete all host logs 2015-07-22 15:05:54 +02:00
Olivier Lambert
74f20da82f Merge pull request #305 from vatesfr/issue#301
GUI fix for vm delete
2015-07-21 14:34:59 +02:00
Olivier Lambert
4c9c838b70 Merge pull request #300 from vatesfr/marsaud-backup
Scheduled VM Backup feature
2015-07-21 14:34:51 +02:00
Fabrice Marsaud
9a9d27d37a GUI fix for vm delete 2015-07-21 14:26:07 +02:00
Fabrice Marsaud
0347d4cec4 Rolling backup feature 2015-07-21 14:14:15 +02:00
Fabrice Marsaud
b1b189288e Fix issue #302 2015-07-21 14:11:24 +02:00
Fabrice Marsaud
b3220f981b GUI fix for vm delete 2015-07-20 19:29:53 +02:00
Julien Fontanet
a5573e62c6 Update deps. 2015-07-15 09:47:01 +02:00
Fabrice Marsaud
c4ccee8df6 4.2.0 2015-06-29 09:18:43 +02:00
Fabrice Marsaud
fbcf803d06 Merge branch 'next-release' 2015-06-29 09:16:31 +02:00
Olivier Lambert
5247b7a9af Update CHANGELOG.md 2015-06-27 22:42:39 +02:00
Fabrice Marsaud
dc218cc992 rollingSnap view clean 2015-06-26 14:39:42 +02:00
Fabrice Marsaud
c21761d9d4 Merge pull request #289 from vatesfr/scheduler#176
Scheduler#176
2015-06-26 14:24:38 +02:00
Fabrice Marsaud
36c0bf06d7 Rolling VM Snapshot scheduling feature 2015-06-26 12:35:02 +02:00
Fabrice Marsaud
ccdab2b083 Fixed VM snapshots pagination 2015-06-26 12:34:35 +02:00
Fabrice Marsaud
15a8a56807 Fixes service link 2015-06-26 09:47:35 +02:00
Fabrice Marsaud
385d42281b Revert "This code should now be unnecessary."
This reverts commit 5f9cf47003.
2015-06-25 17:29:20 +02:00
Julien Fontanet
b0dc933021 Do not use babel-plugin-closure-elimination. 2015-06-23 15:01:49 +02:00
Olivier Lambert
b73ee1f638 Merge pull request #293 from vatesfr/SRViewFix
Fixed VM display on SR view
2015-06-22 10:40:23 +02:00
Fabrice Marsaud
51c2a54179 Fixed VM display on SR view 2015-06-22 10:25:44 +02:00
Julien Fontanet
2d71a916a2 Update vinyl to 0.5. 2015-06-15 16:47:56 +02:00
Julien Fontanet
5f9cf47003 This code should now be unnecessary. 2015-06-15 15:15:12 +02:00
Julien Fontanet
16b39185dc Fix coding style in gulpfile.js 2015-06-15 14:29:45 +02:00
Julien Fontanet
6f0410f26e Fix Angular to 1.4.x.
Angular's devs tend to break API on minor versions.
2015-06-15 10:58:18 +02:00
Julien Fontanet
0b86845852 Add Babel plugin for closure elimination (disabled for now). 2015-06-11 08:54:58 +02:00
Julien Fontanet
d5f914bd2f Do not distribute examples & tests. 2015-06-11 08:54:58 +02:00
Julien Fontanet
663c65e42e Babel configuration. 2015-06-11 08:54:58 +02:00
Julien Fontanet
b9de86f96c Minor fix in EditorConfig. 2015-06-11 08:54:58 +02:00
Olivier Lambert
bd9c0ffb25 4.1.0 2015-06-10 16:59:17 +02:00
Olivier Lambert
9d763773cf 4.1.0 2015-06-10 16:58:48 +02:00
Olivier Lambert
540f977146 Update CHANGELOG.md 2015-06-10 16:24:33 +02:00
Olivier Lambert
d16b09d3fc fix issue #287 2015-06-10 16:22:35 +02:00
Olivier Lambert
6f8a8d3b90 Update CHANGELOG.md 2015-06-10 13:19:02 +02:00
Olivier Lambert
00ef4166c7 fix #286 2015-06-10 10:35:56 +02:00
Olivier Lambert
b88414735e minor style modification for drag'n drop 2015-06-09 13:31:53 +02:00
Fabrice Marsaud
af092fae9b Fixed missing anguler injection 2015-06-09 12:58:11 +02:00
Fabrice Marsaud
b889efc913 migratePool fallback for dragNdrop migration 2015-06-09 12:58:11 +02:00
Fabrice Marsaud
877dd68a6b Final drag style 2015-06-09 12:58:11 +02:00
Fabrice Marsaud
2805a1c7bc A bit of style 2015-06-09 12:58:11 +02:00
Fabrice Marsaud
c5c000ea6f Work in progress 2015-06-09 12:58:11 +02:00
Fabrice Marsaud
673f1072bf Minor fix 2015-06-09 12:58:11 +02:00
Fabrice Marsaud
d0e93b9b9f Drag & drop VM migration in progress 2015-06-09 12:58:11 +02:00
Olivier Lambert
f239088bcb fix #270 2015-06-08 20:49:10 +02:00
Fabrice Marsaud
32642f105c Groups UI enhancement 2015-06-08 16:50:04 +02:00
Fabrice Marsaud
4adaf6d355 Group panel allows ACL suppression, and user search for add 2015-06-08 14:21:09 +02:00
Fabrice Marsaud
291e2a5e40 group: direct user add, without button 2015-06-08 13:34:26 +02:00
Fabrice Marsaud
05bdb56203 Minor code fix 2015-06-08 11:59:29 +02:00
Fabrice Marsaud
cb71df8345 Group view improvements 2015-06-08 11:54:03 +02:00
Fabrice Marsaud
c6c5f5188b Group dedicated edit page with acl recap 2015-06-05 15:29:34 +02:00
Fabrice Marsaud
a7b6ca0914 Fix for Issue #272 hide non auth objects 2015-06-04 17:16:49 +02:00
Fabrice Marsaud
30ba062695 Fixes for issue #271 newvm 2015-06-04 09:17:10 +02:00
Fabrice Marsaud
a595af7b3f vm controller clean up 2015-06-03 17:51:57 +02:00
Fabrice Marsaud
b2ee3172d8 console view data behaves ok on browser refresh 2015-06-03 17:45:23 +02:00
Fabrice Marsaud
73992ee8e9 console iso-device integration 2015-06-03 17:28:24 +02:00
Fabrice Marsaud
78885fd00a Fixed iso-device bug 2015-06-03 17:27:53 +02:00
Fabrice Marsaud
ce55ac6ccb Reworked iso-device module and integration on vm view 2015-06-03 17:01:30 +02:00
Fabrice Marsaud
8ce0951e5f Fix Issue #271 2015-06-03 14:53:42 +02:00
Julien Fontanet
7788fa9d3e Use standard with babel-eslint. 2015-06-03 09:40:38 +02:00
Julien Fontanet
7f36552c71 Release process. 2015-06-03 09:40:38 +02:00
Fabrice Marsaud
16f9437b29 Solving Issue #269 2015-06-02 15:51:40 +02:00
Julien Fontanet
0beaff718e Update release process. 2015-06-01 16:18:31 +02:00
Olivier Lambert
9b6f37b5d0 add changelog for patch releases 2015-06-01 16:16:08 +02:00
Olivier Lambert
3d6d4aea6a 4.0.2 2015-06-01 10:26:34 +02:00
Fabrice Marsaud
2356a21e54 Fix for Issue #264 field resets whil editing users 2015-06-01 09:32:20 +02:00
298 changed files with 34590 additions and 10124 deletions

View File

@@ -1,3 +0,0 @@
{
"directory": "dist/bower_components"
}

View File

@@ -46,7 +46,7 @@ indent_size = 2
indent_style = space
# Less
[*.js]
[*.less]
indent_size = 2
indent_style = space

9
.gitignore vendored
View File

@@ -1,6 +1,9 @@
/.nyc_output/
/bower_components/
/dist/
/node_modules/*
!/node_modules/*.js
/node_modules/*.js/
npm-debug.log
npm-debug.log.*
!node_modules/*
node_modules/*/

10
.npmignore Normal file
View File

@@ -0,0 +1,10 @@
/examples/
example.js
example.js.map
*.example.js
*.example.js.map
/test/
/tests/
*.spec.js
*.spec.js.map

12
.travis.yml Normal file
View File

@@ -0,0 +1,12 @@
language: node_js
node_js:
- 'stable'
#- '4' # Disabled for now because npm 2 cannot properly handled broken peer dependencies.
cache:
directories:
- node_modules
# Use containers.
# http://docs.travis-ci.com/user/workers/container-based-infrastructure/
sudo: false

View File

@@ -1,10 +1,553 @@
# ChangeLog
## **5.0.0** (2016-06-24)
### Enhancements
- Handle failed quiesce in snapshots [\#1088](https://github.com/vatesfr/xo-web/issues/1088)
- Sparklines stats [\#1061](https://github.com/vatesfr/xo-web/issues/1061)
- Task view [\#1060](https://github.com/vatesfr/xo-web/issues/1060)
- Improved import system [\#1048](https://github.com/vatesfr/xo-web/issues/1048)
- Backup restore view improvements [\#1021](https://github.com/vatesfr/xo-web/issues/1021)
- Restore VM - Wrong VLAN on the VMs interface [\#1016](https://github.com/vatesfr/xo-web/issues/1016)
- Fast Disk Cloning [\#960](https://github.com/vatesfr/xo-web/issues/960)
- Disaster recovery job should target SRs, not pools [\#955](https://github.com/vatesfr/xo-web/issues/955)
- Improve Header/Content interaction in a page [\#926](https://github.com/vatesfr/xo-web/issues/926)
- New default view [\#912](https://github.com/vatesfr/xo-web/issues/912)
- Xen Patching - Restart Pending [\#883](https://github.com/vatesfr/xo-web/issues/883)
- Hide About page for user that are not admin [\#877](https://github.com/vatesfr/xo-web/issues/877)
- ACL: Ability to view/sort/group by User/Group, Objects or Role [\#875](https://github.com/vatesfr/xo-web/issues/875)
- ACL: Ability to select multiple users & group when creating a rule [\#874](https://github.com/vatesfr/xo-web/issues/874)
- Translation [\#839](https://github.com/vatesfr/xo-web/issues/839)
- XO offer useless network interfaces for XenMontion [\#833](https://github.com/vatesfr/xo-web/issues/833)
- Show HVM, PVM, PVHVM modes in guest details [\#806](https://github.com/vatesfr/xo-web/issues/806)
- Tree view: display cpu available/total for each host [\#696](https://github.com/vatesfr/xo-web/issues/696)
- Greenkeeper integration [\#667](https://github.com/vatesfr/xo-web/issues/667)
- Clarify vCPUs and RAM editor [\#658](https://github.com/vatesfr/xo-web/issues/658)
- Backup LZ4 compression [\#647](https://github.com/vatesfr/xo-web/issues/647)
- Support enum in plugins configuration [\#638](https://github.com/vatesfr/xo-web/issues/638)
- Add configuration option to disable xoa-updater [\#535](https://github.com/vatesfr/xo-web/issues/535)
- Use cursors to add more context to actions [\#523](https://github.com/vatesfr/xo-web/issues/523)
- Review UI for flat view [\#354](https://github.com/vatesfr/xo-web/issues/354)
- Review UI for the tree view [\#353](https://github.com/vatesfr/xo-web/issues/353)
- Tag filtering [\#233](https://github.com/vatesfr/xo-web/issues/233)
- GUI review [\#230](https://github.com/vatesfr/xo-web/issues/230)
- Review UI for VM creation [\#214](https://github.com/vatesfr/xo-web/issues/214)
- Ability to collapse pools/hosts in main view [\#173](https://github.com/vatesfr/xo-web/issues/173)
- Issue importing .xva VM via xo-web [\#1022](https://github.com/vatesfr/xo-web/issues/1022)
- Enhancement Proposal - Cancel In Progress Backups [\#1003](https://github.com/vatesfr/xo-web/issues/1003)
- Can't create VM with CloudConfigDrive [\#917](https://github.com/vatesfr/xo-web/issues/917)
- Auth: LDAP User causes problems [\#893](https://github.com/vatesfr/xo-web/issues/893)
- No tags in Continuous Replication [\#838](https://github.com/vatesfr/xo-web/issues/838)
- Delta backup Depth not working [\#802](https://github.com/vatesfr/xo-web/issues/802)
- Update Section - Running version info missing - gui enhancement [\#795](https://github.com/vatesfr/xo-web/issues/795)
- On reboot, vnc console wrongly scaled [\#722](https://github.com/vatesfr/xo-web/issues/722)
- Make the object name \(title\) "sticky" at the top of the page [\#705](https://github.com/vatesfr/xo-web/issues/705)
- pool view: display Local SR from hosts in the current pool [\#692](https://github.com/vatesfr/xo-web/issues/692)
- tree view: display all IPs [\#689](https://github.com/vatesfr/xo-web/issues/689)
- XO5 parallel distribution [\#462](https://github.com/vatesfr/xo-web/issues/462)
- Load balancing with XO [\#423](https://github.com/vatesfr/xo-web/issues/423)
### Bug fixes
- vCPUs number when no tools installed [\#1089](https://github.com/vatesfr/xo-web/issues/1089)
- Config Drive textbox disappears when content is deleted [\#1012](https://github.com/vatesfr/xo-web/issues/1012)
- storage status not changed in host view page after disconnect/connect [\#1009](https://github.com/vatesfr/xo-web/issues/1009)
- Cannot Delete Logs From Backup Overview [\#1004](https://github.com/vatesfr/xo-web/issues/1004)
- \[v5.x\] Plugins configuration: optional non-used objects are sent [\#1000](https://github.com/vatesfr/xo-web/issues/1000)
- "@" char in remote password break the remote view [\#997](https://github.com/vatesfr/xo-web/issues/997)
- Handle MEMORY\_CONSTRAINT\_VIOLATION correctly [\#970](https://github.com/vatesfr/xo-web/issues/970)
- VM creation error on XenServer Dundee [\#964](https://github.com/vatesfr/xo-web/issues/964)
- Copy VMs doesn't display all SRs [\#945](https://github.com/vatesfr/xo-web/issues/945)
- Autopower\_on wrong value [\#937](https://github.com/vatesfr/xo-web/issues/937)
- Correctly handle unknown users in group view [\#900](https://github.com/vatesfr/xo-web/issues/900)
- Importing into Dundee [\#887](https://github.com/vatesfr/xo-web/issues/887)
- update status - gui resize issue [\#803](https://github.com/vatesfr/xo-web/issues/803)
- Backup Remote Stores Problem [\#751](https://github.com/vatesfr/xo-web/issues/751)
- VM view is broken when changing a disk SR twice [\#670](https://github.com/vatesfr/xo-web/issues/670)
- console mouse sync [\#280](https://github.com/vatesfr/xo-web/issues/280)
## **4.16.0** (2016-04-29)
Maintenance release
### Enhancements
- TOO\_MANY\_PENDING\_TASKS [\#861](https://github.com/vatesfr/xo-web/issues/861)
### Bug fixes
- Incorrect VM target name with continuous replication [\#904](https://github.com/vatesfr/xo-web/issues/904)
- Error while deleting users [\#901](https://github.com/vatesfr/xo-web/issues/901)
- Use an available path to the SR to create a config drive [\#882](https://github.com/vatesfr/xo-web/issues/882)
- VM autoboot don't set the right pool parameter [\#879](https://github.com/vatesfr/xo-web/issues/879)
- BUG: ACL with NFS ISO Library not working! [\#870](https://github.com/vatesfr/xo-web/issues/870)
- Broken paths in backups in SMB [\#865](https://github.com/vatesfr/xo-web/issues/865)
- Plugins page loads users/groups multiple times [\#829](https://github.com/vatesfr/xo-web/issues/829)
- "Ghost" VM remains after migration [\#769](https://github.com/vatesfr/xo-web/issues/769)
## **4.15.0** (2016-03-21)
Load balancing, SMB delta support, advanced network operations...
### Enhancements
- Add the job name inside the backup email report [\#819](https://github.com/vatesfr/xo-web/issues/819)
- Delta backup with quiesce [\#812](https://github.com/vatesfr/xo-web/issues/812)
- Hosts: No user feedback when error occurs with SR connect / disconnect [\#810](https://github.com/vatesfr/xo-web/issues/810)
- Expose components versions [\#807](https://github.com/vatesfr/xo-web/issues/807)
- Rework networks/PIFs management [\#805](https://github.com/vatesfr/xo-web/issues/805)
- Displaying all SRs and a list of available hosts for creating VM from a pool [\#790](https://github.com/vatesfr/xo-web/issues/790)
- Add "Source network" on "VM migration" screen [\#785](https://github.com/vatesfr/xo-web/issues/785)
- Migration queue [\#783](https://github.com/vatesfr/xo-web/issues/783)
- Match network names for VM migration [\#782](https://github.com/vatesfr/xo-web/issues/782)
- Disk names [\#780](https://github.com/vatesfr/xo-web/issues/780)
- Self service: should the user be able to set the CPU weight? [\#767](https://github.com/vatesfr/xo-web/issues/767)
- host & pool Citrix license status [\#763](https://github.com/vatesfr/xo-web/issues/763)
- pool view: Provide "updates" section [\#762](https://github.com/vatesfr/xo-web/issues/762)
- XOA ISO image: ambigious root disk label [\#761](https://github.com/vatesfr/xo-web/issues/761)
- Host info: provide system serial number [\#760](https://github.com/vatesfr/xo-web/issues/760)
- CIFS ISO SR Creation [\#731](https://github.com/vatesfr/xo-web/issues/731)
- MAC address not preserved on VM restore [\#707](https://github.com/vatesfr/xo-web/issues/707)
- Failing replication job should send reports [\#659](https://github.com/vatesfr/xo-web/issues/659)
- Display networks in the Pool view [\#226](https://github.com/vatesfr/xo-web/issues/226)
### Bug fixes
- Broken link to backup remote [\#821](https://github.com/vatesfr/xo-web/issues/821)
- Issue with self-signed cert for email plugin [\#817](https://github.com/vatesfr/xo-web/issues/817)
- Plugins view, reset form and errors [\#815](https://github.com/vatesfr/xo-web/issues/815)
- HVM recovery mode is broken [\#794](https://github.com/vatesfr/xo-web/issues/794)
- Disk bug when creating vm from template [\#778](https://github.com/vatesfr/xo-web/issues/778)
- Can't mount NFS shares in remote stores [\#775](https://github.com/vatesfr/xo-web/issues/775)
- VM disk name and description not passed during creation [\#774](https://github.com/vatesfr/xo-web/issues/774)
- NFS mount problem for Windows share [\#771](https://github.com/vatesfr/xo-web/issues/771)
- lodash.pluck not installed [\#757](https://github.com/vatesfr/xo-web/issues/757)
- this.\_getAuthenticationTokensForUser is not a function [\#755](https://github.com/vatesfr/xo-web/issues/755)
- CentOS 6.x 64bit template creates a VM that won't boot [\#733](https://github.com/vatesfr/xo-web/issues/733)
- Lot of xo:perf leading to XO crash [\#575](https://github.com/vatesfr/xo-web/issues/575)
- New collection checklist [\#262](https://github.com/vatesfr/xo-web/issues/262)
## **4.14.0** (2016-02-23)
Self service, custom CloudInit...
### Enhancements
- VM creation self service with quotas [\#285](https://github.com/vatesfr/xo-web/issues/285)
- Cloud config custom user data [\#706](https://github.com/vatesfr/xo-web/issues/706)
- Patches behind a proxy [\#737](https://github.com/vatesfr/xo-web/issues/737)
- Remote store status indicator [\#728](https://github.com/vatesfr/xo-web/issues/728)
- Patch list order [\#724](https://github.com/vatesfr/xo-web/issues/724)
- Enable reporting on additional backup types [\#717](https://github.com/vatesfr/xo-web/issues/717)
- Tooltip name for cancel [\#703](https://github.com/vatesfr/xo-web/issues/703)
- Portable VHD merging [\#646](https://github.com/vatesfr/xo-web/issues/646)
### Bug fixes
- Avoid merge between two delta vdi backups [\#702](https://github.com/vatesfr/xo-web/issues/702)
- Text in table is not cut anymore [\#713](https://github.com/vatesfr/xo-web/issues/713)
- Disk size edition issue with float numbers [\#719](https://github.com/vatesfr/xo-web/issues/719)
- Create vm, summary is not refreshed [\#721](https://github.com/vatesfr/xo-web/issues/721)
- Boot order problem [\#726](https://github.com/vatesfr/xo-web/issues/726)
## **4.13.0** (2016-02-05)
Backup checksum, SMB remotes...
### Enhancements
- Add SMB mount for remote [\#338](https://github.com/vatesfr/xo-web/issues/338)
- Centralize Perm in a lib [\#345](https://github.com/vatesfr/xo-web/issues/345)
- Expose interpool migration details [\#567](https://github.com/vatesfr/xo-web/issues/567)
- Add checksum for delta backup [\#617](https://github.com/vatesfr/xo-web/issues/617)
- Redirect from HTTP to HTTPS [\#626](https://github.com/vatesfr/xo-web/issues/626)
- Expose vCPU weight [\#633](https://github.com/vatesfr/xo-web/issues/633)
- Avoid metadata in delta backup [\#651](https://github.com/vatesfr/xo-web/issues/651)
- Button to clear logs [\#661](https://github.com/vatesfr/xo-web/issues/661)
- Units for RAM and disks [\#666](https://github.com/vatesfr/xo-web/issues/666)
- Remove multiple VDIs at once [\#676](https://github.com/vatesfr/xo-web/issues/676)
- Find orphaned VDI snapshots [\#679](https://github.com/vatesfr/xo-web/issues/679)
- New health view in Dashboard [\#680](https://github.com/vatesfr/xo-web/issues/680)
- Use physical usage for VDI and SR [\#682](https://github.com/vatesfr/xo-web/issues/682)
- TLS configuration [\#685](https://github.com/vatesfr/xo-web/issues/685)
- Better VM info on tree view [\#688](https://github.com/vatesfr/xo-web/issues/688)
- Absolute values in tooltips for tree view [\#690](https://github.com/vatesfr/xo-web/issues/690)
- Absolute values for host memory [\#691](https://github.com/vatesfr/xo-web/issues/691)
### Bug fixes
- Issues on host console screen [\#672](https://github.com/vatesfr/xo-web/issues/672)
- NFS remote mount fails in particular case [\#665](https://github.com/vatesfr/xo-web/issues/665)
- Unresponsive pages [\#662](https://github.com/vatesfr/xo-web/issues/662)
- Live migration fail in the same pool with local SR fails [\#655](https://github.com/vatesfr/xo-web/issues/655)
## **4.12.0** (2016-01-18)
Continuous Replication, Continuous Delta backup...
### Enhancements
- Continuous VM replication [\#582](https://github.com/vatesfr/xo-web/issues/582)
- Continuous Delta Backup [\#576](https://github.com/vatesfr/xo-web/issues/576)
- Scheduler should not run job again if previous instance is not finished [\#642](https://github.com/vatesfr/xo-web/issues/642)
- Boot VM automatically after creation [\#635](https://github.com/vatesfr/xo-web/issues/635)
- Manage existing VIFs in templates [\#630](https://github.com/vatesfr/xo-web/issues/630)
- Support templates with existing install repository [\#627](https://github.com/vatesfr/xo-web/issues/627)
- Remove running VMs [\#616](https://github.com/vatesfr/xo-web/issues/616)
- Prevent a VM to start before delta import is finished [\#613](https://github.com/vatesfr/xo-web/issues/613)
- Spawn multiple VMs at once [\#606](https://github.com/vatesfr/xo-web/issues/606)
- Fixed `suspendVM` in tree view. [\#619](https://github.com/vatesfr/xo-web/pull/619) ([pdonias](https://github.com/pdonias))
### Bug fixes
- User defined MAC address is not fetch in VM install [\#643](https://github.com/vatesfr/xo-web/issues/643)
- CoreOsCloudConfig is not shown with CoreOS [\#639](https://github.com/vatesfr/xo-web/issues/639)
- Plugin activation/deactivation in web UI seems broken [\#637](https://github.com/vatesfr/xo-web/issues/637)
- Issue when creating CloudConfig drive [\#636](https://github.com/vatesfr/xo-web/issues/636)
- CloudConfig hostname shouldn't have space [\#634](https://github.com/vatesfr/xo-web/issues/634)
- Cloned VIFs are not properly deleted on VM creation [\#632](https://github.com/vatesfr/xo-web/issues/632)
- Default PV args missing during VM creation [\#628](https://github.com/vatesfr/xo-web/issues/628)
- VM creation problems from custom templates [\#625](https://github.com/vatesfr/xo-web/issues/625)
- Emergency shutdown race condition [\#622](https://github.com/vatesfr/xo-web/issues/622)
- `vm.delete\(\)` should not delete VDIs attached to other VMs [\#621](https://github.com/vatesfr/xo-web/issues/621)
- VM creation error from template with a disk [\#581](https://github.com/vatesfr/xo-web/issues/581)
- Only delete VDI exports when VM backup is successful [\#644](https://github.com/vatesfr/xo-web/issues/644)
- Change the name of an imported VM during the import process [\#641](https://github.com/vatesfr/xo-web/issues/641)
- Creating a new VIF in view is partially broken [\#652](https://github.com/vatesfr/xo-web/issues/652)
- Grey out the "create button" during VM creation [\#654](https://github.com/vatesfr/xo-web/issues/654)
## **4.11.0** (2015-12-22)
Delta backup, CloudInit...
### Enhancements
- Visible list of SR inside a VM [\#601](https://github.com/vatesfr/xo-web/issues/601)
- VDI move [\#591](https://github.com/vatesfr/xo-web/issues/591)
- Edit pre-existing disk configuration during VM creation [\#589](https://github.com/vatesfr/xo-web/issues/589)
- Allow disk size edition [\#587](https://github.com/vatesfr/xo-web/issues/587)
- Better VDI resize support [\#585](https://github.com/vatesfr/xo-web/issues/585)
- Remove manual VM export metadata in UI [\#580](https://github.com/vatesfr/xo-web/issues/580)
- Support import VM metadata [\#579](https://github.com/vatesfr/xo-web/issues/579)
- Set a default pool SR [\#572](https://github.com/vatesfr/xo-web/issues/572)
- ISOs should be sorted by name [\#565](https://github.com/vatesfr/xo-web/issues/565)
- Button to boot a VM from a disc once [\#564](https://github.com/vatesfr/xo-web/issues/564)
- Ability to boot a PV VM from a disc [\#563](https://github.com/vatesfr/xo-web/issues/563)
- Add an option to manually run backup jobs [\#562](https://github.com/vatesfr/xo-web/issues/562)
- backups to unmounted storage [\#561](https://github.com/vatesfr/xo-web/issues/561)
- Root integer properties cannot be edited in plugins configuration form [\#550](https://github.com/vatesfr/xo-web/issues/550)
- Generic CloudConfig drive [\#549](https://github.com/vatesfr/xo-web/issues/549)
- Auto-discovery of installed xo-server plugins [\#546](https://github.com/vatesfr/xo-web/issues/546)
- Hide info on flat view [\#545](https://github.com/vatesfr/xo-web/issues/545)
- Config plugin boolean properties must have a default value \(undefined prohibited\) [\#543](https://github.com/vatesfr/xo-web/issues/543)
- Present detailed errors on plugin configuration failures [\#530](https://github.com/vatesfr/xo-web/issues/530)
- Do not reset form on failures in plugins configuration [\#529](https://github.com/vatesfr/xo-web/issues/529)
- XMPP alert plugin [\#518](https://github.com/vatesfr/xo-web/issues/518)
- Hide tag adders depending on ACLs [\#516](https://github.com/vatesfr/xo-web/issues/516)
- Choosing a framework for xo-web 5 [\#514](https://github.com/vatesfr/xo-web/issues/514)
- Prevent adding a host in an existing XAPI connection [\#466](https://github.com/vatesfr/xo-web/issues/466)
- Read only connection to Xen servers/pools [\#439](https://github.com/vatesfr/xo-web/issues/439)
- generic notification system [\#391](https://github.com/vatesfr/xo-web/issues/391)
- Data architecture review [\#384](https://github.com/vatesfr/xo-web/issues/384)
- Make filtering easier to understand/add some "default" filters [\#207](https://github.com/vatesfr/xo-web/issues/207)
- Improve performance [\#148](https://github.com/vatesfr/xo-web/issues/148)
### Bug fixes
- VM metadata export should not require a snapshot [\#615](https://github.com/vatesfr/xo-web/issues/615)
- Missing patch for all hosts is continuously refreshed [\#609](https://github.com/vatesfr/xo-web/issues/609)
- Backup import memory issue [\#608](https://github.com/vatesfr/xo-web/issues/608)
- Host list missing patch is buggy [\#604](https://github.com/vatesfr/xo-web/issues/604)
- Servers infos should not been refreshed while a field is being edited [\#595](https://github.com/vatesfr/xo-web/issues/595)
- Servers list should not been re-order while a field is being edited [\#594](https://github.com/vatesfr/xo-web/issues/594)
- Correctly display size in interface \(binary scale\) [\#592](https://github.com/vatesfr/xo-web/issues/592)
- Display failures on VM boot order modification [\#560](https://github.com/vatesfr/xo-web/issues/560)
- `vm.setBootOrder\(\)` should throw errors on failures \(non-HVM VMs\) [\#559](https://github.com/vatesfr/xo-web/issues/559)
- Hide boot order form for non-HVM VMs [\#558](https://github.com/vatesfr/xo-web/issues/558)
- Allow editing PV args even when empty \(but only for PV VMs\) [\#557](https://github.com/vatesfr/xo-web/issues/557)
- Crashes when using legacy event system [\#556](https://github.com/vatesfr/xo-web/issues/556)
- XenServer patches check error for 6.1 [\#555](https://github.com/vatesfr/xo-web/issues/555)
- activation plugin xo-server-transport-email [\#553](https://github.com/vatesfr/xo-web/issues/553)
- Server error with JSON on 32 bits Dom0 [\#552](https://github.com/vatesfr/xo-web/issues/552)
- Cloud Config drive shouldn't be created on default SR [\#548](https://github.com/vatesfr/xo-web/issues/548)
- Deep properties cannot be edited in plugins configuration form [\#521](https://github.com/vatesfr/xo-web/issues/521)
- Aborted VM export should cancel the operation [\#490](https://github.com/vatesfr/xo-web/issues/490)
- VM missing with same UUID after an inter-pool migration [\#284](https://github.com/vatesfr/xo-web/issues/284)
## **4.10.0** (2015-11-27)
Job management, email notifications, CoreOS/Docker, Quiesce snapshots...
### Enhancements
- Job management ([xo-web#487](https://github.com/vatesfr/xo-web/issues/487))
- Patch upload on all connected servers ([xo-web#168](https://github.com/vatesfr/xo-web/issues/168))
- Emergency shutdown ([xo-web#185](https://github.com/vatesfr/xo-web/issues/185))
- CoreOS/docker template install ([xo-web#246](https://github.com/vatesfr/xo-web/issues/246))
- Email for backups ([xo-web#308](https://github.com/vatesfr/xo-web/issues/308))
- Console Clipboard ([xo-web#408](https://github.com/vatesfr/xo-web/issues/408))
- Logs from CLI ([xo-web#486](https://github.com/vatesfr/xo-web/issues/486))
- Save disconnected servers ([xo-web#489](https://github.com/vatesfr/xo-web/issues/489))
- Snapshot with quiesce ([xo-web#491](https://github.com/vatesfr/xo-web/issues/491))
- Start VM in reovery mode ([xo-web#495](https://github.com/vatesfr/xo-web/issues/495))
- Username in logs ([xo-web#498](https://github.com/vatesfr/xo-web/issues/498))
- Delete associated tokens with user ([xo-web#500](https://github.com/vatesfr/xo-web/issues/500))
- Validate plugin configuration ([xo-web#503](https://github.com/vatesfr/xo-web/issues/503))
- Avoid non configured plugins to be loaded ([xo-web#504](https://github.com/vatesfr/xo-web/issues/504))
- Verbose API logs if configured ([xo-web#505](https://github.com/vatesfr/xo-web/issues/505))
- Better backup overview ([xo-web#512](https://github.com/vatesfr/xo-web/issues/512))
- VM auto power on ([xo-web#519](https://github.com/vatesfr/xo-web/issues/519))
- Title property supported in config schema ([xo-web#522](https://github.com/vatesfr/xo-web/issues/522))
- Start VM export only when necessary ([xo-web#534](https://github.com/vatesfr/xo-web/issues/534))
- Input type should be number ([xo-web#538](https://github.com/vatesfr/xo-web/issues/538))
### Bug fixes
- Numbers/int support in plugins config ([xo-web#531](https://github.com/vatesfr/xo-web/issues/531))
- Boolean support in plugins config ([xo-web#528](https://github.com/vatesfr/xo-web/issues/528))
- Keyboard unusable outside console ([xo-web#513](https://github.com/vatesfr/xo-web/issues/513))
- UsernameField for SAML ([xo-web#513](https://github.com/vatesfr/xo-web/issues/513))
- Wrong display of "no plugin found" ([xo-web#508](https://github.com/vatesfr/xo-web/issues/508))
- Bower build error ([xo-web#488](https://github.com/vatesfr/xo-web/issues/488))
- VM cloning should require SR permission ([xo-web#472](https://github.com/vatesfr/xo-web/issues/472))
- Xen tools status ([xo-web#471](https://github.com/vatesfr/xo-web/issues/471))
- Can't delete ghost user ([xo-web#464](https://github.com/vatesfr/xo-web/issues/464))
- Stats with old versions of Node ([xo-web#463](https://github.com/vatesfr/xo-web/issues/463))
## **4.9.0** (2015-11-13)
Automated DR, restore backup, VM copy
### Enhancements
- DR: schedule VM export on other host ([xo-web#447](https://github.com/vatesfr/xo-web/issues/447))
- Scheduler logs ([xo-web#390](https://github.com/vatesfr/xo-web/issues/390) and [xo-web#477](https://github.com/vatesfr/xo-web/issues/477))
- Restore backups ([xo-web#450](https://github.com/vatesfr/xo-web/issues/350))
- Disable backup compression ([xo-web#467](https://github.com/vatesfr/xo-web/issues/467))
- Copy VM to another SR (even remote) ([xo-web#475](https://github.com/vatesfr/xo-web/issues/475))
- VM stats without time sync ([xo-web#460](https://github.com/vatesfr/xo-web/issues/460))
- Stats perfs for high CPU numbers ([xo-web#461](https://github.com/vatesfr/xo-web/issues/461))
### Bug fixes
- Rolling backup bug ([xo-web#484](https://github.com/vatesfr/xo-web/issues/484))
- vCPUs/CPUs inversion in dashboard ([xo-web#481](https://github.com/vatesfr/xo-web/issues/481))
- Machine to template ([xo-web#459](https://github.com/vatesfr/xo-web/issues/459))
### Misc
- Console fix in XenServer ([xo-web#406](https://github.com/vatesfr/xo-web/issues/406))
## **4.8.0** (2015-10-29)
Fully automated patch system, ACLs inheritance, stats performance improved.
### Enhancements
- ACLs inheritance ([xo-web#279](https://github.com/vatesfr/xo-web/issues/279))
- Patch automatically all missing updates ([xo-web#281](https://github.com/vatesfr/xo-web/issues/281))
- Intelligent stats polling ([xo-web#432](https://github.com/vatesfr/xo-web/issues/432))
- Cache latest result of stats request ([xo-web#431](https://github.com/vatesfr/xo-web/issues/431))
- Improve stats polling on multiple objects ([xo-web#433](https://github.com/vatesfr/xo-web/issues/433))
- Patch upload task should display the patch name ([xo-web#449](https://github.com/vatesfr/xo-web/issues/449))
- Backup filename for Windows ([xo-web#448](https://github.com/vatesfr/xo-web/issues/448))
- Specific distro icons ([xo-web#446](https://github.com/vatesfr/xo-web/issues/446))
- PXE boot for HVM ([xo-web#436](https://github.com/vatesfr/xo-web/issues/436))
- Favicon display before sign in ([xo-web#428](https://github.com/vatesfr/xo-web/issues/428))
- Registration renewal ([xo-web#424](https://github.com/vatesfr/xo-web/issues/424))
- Reconnect to the host if pool merge fails ([xo-web#403](https://github.com/vatesfr/xo-web/issues/403))
- Avoid brute force login ([xo-web#339](https://github.com/vatesfr/xo-web/issues/339))
- Missing FreeBSD icon ([xo-web#136](https://github.com/vatesfr/xo-web/issues/136))
- Hide halted objects in the Health view ([xo-web#457](https://github.com/vatesfr/xo-web/issues/457))
- Click on "Remember me" label ([xo-web#438](https://github.com/vatesfr/xo-web/issues/438))
### Bug fixes
- Pool patches in multiple pools not displayed ([xo-web#442](https://github.com/vatesfr/xo-web/issues/442))
- VM Import crashes with Chrome ([xo-web#427](https://github.com/vatesfr/xo-web/issues/427))
- Cannot open a direct link ([xo-web#371](https://github.com/vatesfr/xo-web/issues/371))
- Patch display edge case ([xo-web#309](https://github.com/vatesfr/xo-web/issues/309))
- VM snapshot should require user permission on SR ([xo-web#429](https://github.com/vatesfr/xo-web/issues/429))
## **4.7.0** (2015-10-12)
Plugin config management and browser notifications.
### Enhancements
- Plugin management in the web interface ([xo-web#352](https://github.com/vatesfr/xo-web/issues/352))
- Browser notifications ([xo-web#402](https://github.com/vatesfr/xo-web/issues/402))
- Graph selector ([xo-web#400](https://github.com/vatesfr/xo-web/issues/400))
- Circle packing visualization ([xo-web#374](https://github.com/vatesfr/xo-web/issues/374))
- Password generation ([xo-web#397](https://github.com/vatesfr/xo-web/issues/397))
- Password reveal during user creation ([xo-web#396](https://github.com/vatesfr/xo-web/issues/396))
- Add host to a pool ([xo-web#62](https://github.com/vatesfr/xo-web/issues/62))
- Better modal when removing a host from a pool ([xo-web#405](https://github.com/vatesfr/xo-web/issues/405))
- Drop focus on CD/ISO selector ([xo-web#290](https://github.com/vatesfr/xo-web/issues/290))
- Allow non persistent session ([xo-web#243](https://github.com/vatesfr/xo-web/issues/243))
### Bug fixes
- VM export permission corrected ([xo-web#410](https://github.com/vatesfr/xo-web/issues/410))
- Proper host removal in a pool ([xo-web#402](https://github.com/vatesfr/xo-web/issues/402))
- Sub-optimal tooltip placement ([xo-web#421](https://github.com/vatesfr/xo-web/issues/421))
- VM migrate host incorrect target ([xo-web#419](https://github.com/vatesfr/xo-web/issues/419))
- Alone host can't leave its pool ([xo-web#414](https://github.com/vatesfr/xo-web/issues/414))
## **4.6.0** (2015-09-25)
Tags management and new visualization.
### Enhancements
- Multigraph for correlation ([xo-web#358](https://github.com/vatesfr/xo-web/issues/358))
- Tags management ([xo-web#367](https://github.com/vatesfr/xo-web/issues/367))
- Google Provider for authentication ([xo-web#363](https://github.com/vatesfr/xo-web/issues/363))
- Password change for users ([xo-web#362](https://github.com/vatesfr/xo-web/issues/362))
- Better live migration process ([xo-web#237](https://github.com/vatesfr/xo-web/issues/237))
- VDI search filter in SR view ([xo-web#222](https://github.com/vatesfr/xo-web/issues/222))
- PV args during VM creation ([xo-web#112](https://github.com/vatesfr/xo-web/issues/330))
- PV args management ([xo-web#394](https://github.com/vatesfr/xo-web/issues/394))
- Confirmation dialog on important actions ([xo-web#350](https://github.com/vatesfr/xo-web/issues/350))
- New favicon ([xo-web#369](https://github.com/vatesfr/xo-web/issues/369))
- Filename of VM for exports ([xo-web#370](https://github.com/vatesfr/xo-web/issues/370))
- ACLs rights edited on the fly ([xo-web#323](https://github.com/vatesfr/xo-web/issues/323))
- Heatmap values now human readable ([xo-web#342](https://github.com/vatesfr/xo-web/issues/342))
### Bug fixes
- Export backup fails if no tags specified ([xo-web#383](https://github.com/vatesfr/xo-web/issues/383))
- Wrong login give an obscure error message ([xo-web#373](https://github.com/vatesfr/xo-web/issues/373))
- Update view is broken during updates ([xo-web#356](https://github.com/vatesfr/xo-web/issues/356))
- Settings/dashboard menu incorrect display ([xo-web#357](https://github.com/vatesfr/xo-web/issues/357))
- Console View Not refreshing if the VM restart ([xo-web#107](https://github.com/vatesfr/xo-web/issues/107))
## **4.5.1** (2015-09-16)
An issue in `xo-web` with the VM view.
### Bug fix
- Attach disk/new disk/create interface is broken ([xo-web#378](https://github.com/vatesfr/xo-web/issues/378))
## **4.5.0** (2015-09-11)
A new dataviz (parallel coord), a new provider (GitHub) and faster consoles.
### Enhancements
- Parallel coordinates view ([xo-web#333](https://github.com/vatesfr/xo-web/issues/333))
- Faster consoles ([xo-web#337](https://github.com/vatesfr/xo-web/issues/337))
- Disable/hide button ([xo-web#268](https://github.com/vatesfr/xo-web/issues/268))
- More details on missing-guest-tools ([xo-web#304](https://github.com/vatesfr/xo-web/issues/304))
- Scheduler meta data export ([xo-web#315](https://github.com/vatesfr/xo-web/issues/315))
- Better heatmap ([xo-web#330](https://github.com/vatesfr/xo-web/issues/330))
- Faster dashboard ([xo-web#331](https://github.com/vatesfr/xo-web/issues/331))
- Faster sunburst ([xo-web#332](https://github.com/vatesfr/xo-web/issues/332))
- GitHub provider for auth ([xo-web#334](https://github.com/vatesfr/xo-web/issues/334))
- Filter networks for users ([xo-web#347](https://github.com/vatesfr/xo-web/issues/347))
- Add networks in ACLs ([xo-web#348](https://github.com/vatesfr/xo-web/issues/348))
- Better looking login page ([xo-web#341](https://github.com/vatesfr/xo-web/issues/341))
- Real time dataviz (dashboard) ([xo-web#349](https://github.com/vatesfr/xo-web/issues/349))
### Bug fixes
- Typo in dashboard ([xo-web#355](https://github.com/vatesfr/xo-web/issues/355))
- Global RAM usage fix ([xo-web#356](https://github.com/vatesfr/xo-web/issues/356))
- Re-allowing XO behind a reverse proxy ([xo-web#361](https://github.com/vatesfr/xo-web/issues/361))
## **4.4.0** (2015-08-28)
SSO and Dataviz are the main features for this release.
### Enhancements
- Dataviz storage usage ([xo-web#311](https://github.com/vatesfr/xo-web/issues/311))
- Heatmap in health view ([xo-web#329](https://github.com/vatesfr/xo-web/issues/329))
- SSO for SAML and other providers ([xo-web#327](https://github.com/vatesfr/xo-web/issues/327))
- Better UI for ACL objects attribution ([xo-web#320](https://github.com/vatesfr/xo-web/issues/320))
- Refresh the browser after an update ([xo-web#318](https://github.com/vatesfr/xo-web/issues/318))
- Clean CSS and Flexbox usage ([xo-web#239](https://github.com/vatesfr/xo-web/issues/239))
### Bug fixes
- Admin only accessible views ([xo-web#328](https://github.com/vatesfr/xo-web/issues/328))
- Hide "base copy" VDIs ([xo-web#324](https://github.com/vatesfr/xo-web/issues/324))
- ACLs on VIFs for non-admins ([xo-web#322](https://github.com/vatesfr/xo-web/issues/322))
- Updater display problems ([xo-web#313](https://github.com/vatesfr/xo-web/issues/313))
## **4.3.0** (2015-07-22)
Scheduler for rolling backups
### Enhancements
- Rolling backup scheduler ([xo-web#278](https://github.com/vatesfr/xo-web/issues/278))
- Clean snapshots of removed VMs ([xo-web#301](https://github.com/vatesfr/xo-web/issues/301))
### Bug fixes
- VM export ([xo-web#307](https://github.com/vatesfr/xo-web/issues/307))
- Remove VM VDIs ([xo-web#303](https://github.com/vatesfr/xo-web/issues/303))
- Pagination fails ([xo-web#302](https://github.com/vatesfr/xo-web/issues/302))
## **4.2.0** (2015-06-29)
Huge performance boost, scheduler for rolling snapshots and backward compatibility for XS 5.x series
### Enhancements
- Rolling snapshots scheduler ([xo-web#176](https://github.com/vatesfr/xo-web/issues/176))
- Huge perf boost ([xen-api#1](https://github.com/julien-f/js-xen-api/issues/1))
- Backward compatibility ([xo-web#296](https://github.com/vatesfr/xo-web/issues/296))
### Bug fixes
- VDI attached on a VM missing in SR view ([xo-web#294](https://github.com/vatesfr/xo-web/issues/294))
- Better VM creation process ([xo-web#292](https://github.com/vatesfr/xo-web/issues/292))
## **4.1.0** (2015-06-10)
Add the drag'n drop support from VM live migration, better ACLs groups UI.
### Enhancements
- Drag'n drop VM in tree view for live migration ([xo-web#277](https://github.com/vatesfr/xo-web/issues/277))
- Better group view with objects ACLs ([xo-web#276](https://github.com/vatesfr/xo-web/issues/276))
- Hide non-visible objects ([xo-web#272](https://github.com/vatesfr/xo-web/issues/272))
### Bug fixes
- Convert to template displayed when the VM is not halted ([xo-web#286](https://github.com/vatesfr/xo-web/issues/286))
- Lost some data when refresh some views ([xo-web#271](https://github.com/vatesfr/xo-web/issues/271))
- Suspend button don't trigger any permission message ([xo-web#270](https://github.com/vatesfr/xo-web/issues/270))
- Create network interfaces shouldn't call xoApi directly ([xo-web#269](https://github.com/vatesfr/xo-web/issues/269))
- Don't plug automatically a disk or a VIF if the VM is not running ([xo-web#287](https://github.com/vatesfr/xo-web/issues/287))
## **4.0.2** (2015-06-01)
An issue in `xo-server` with the password of default admin account and also a UI fix.
### Bug fixes
- Cannot modify admin account ([xo-web#265](https://github.com/vatesfr/xo-web/issues/265))
- Password field seems to keep empty/reset itself after 1-2 seconds ([xo-web#264](https://github.com/vatesfr/xo-web/issues/264))
## **4.0.1** (2015-05-30)
An issue with the updater in HTTPS was left in the *4.0.0*. This patch release fixed
it.
### Bug fixes
- allow updater to work in HTTPS ([xo-web#266](https://github.com/vatesfr/xo-web/issues/266))
## **4.0.0** (2015-05-29)
[Blog post of this release](https://xen-orchestra.com/blog/xen-orchestra-4-0).
## Enhancements
### Enhancements
- advanced ACLs ([xo-web#209](https://github.com/vatesfr/xo-web/issues/209))
- xenserver update management ([xo-web#174](https://github.com/vatesfr/xo-web/issues/174) & [xo-web#259](https://github.com/vatesfr/xo-web/issues/259))
@@ -18,7 +561,7 @@
- new mapped collection([xo-server#47](https://github.com/vatesfr/xo-server/issues/47))
- resource location in ACL view ([xo-web#245](https://github.com/vatesfr/xo-web/issues/245))
## Bug fixes
### Bug fixes
- wrong calulation of RAM amounts ([xo-web#51](https://github.com/vatesfr/xo-web/issues/51))
- checkbox not aligned ([xo-web#253](https://github.com/vatesfr/xo-web/issues/253))
@@ -31,7 +574,7 @@
A few bugs hve made their way into *3.9.0*, this minor release fixes
them.
## Bug fixes
### Bug fixes
- correctly keep the VM guest metrics up to date ([xo-web#172](https://github.com/vatesfr/xo-web/issues/172))
- fix edition of a VM snapshot ([b04111c](https://github.com/vatesfr/xo-server/commit/b04111c79ba8937778b84cb861bb7c2431162c11))
@@ -44,7 +587,7 @@ them.
[Blog post of this release](https://xen-orchestra.com/blog/xen-orchestra-3-9).
## Enhancements
### Enhancements
- ability to manually connect/disconnect a server ([xo-web#88](https://github.com/vatesfr/xo-web/issues/88) & [xo-web#234](https://github.com/vatesfr/xo-web/issues/234))
- display the connection status of a server ([xo-web#103](https://github.com/vatesfr/xo-web/issues/103))
@@ -58,7 +601,7 @@ them.
- XO-Server sources are compiled to JS prior distribution: less bugs & faster startups ([xo-server#50](https://github.com/vatesfr/xo-server/issues/50))
- use XAPI `event.from()` instead of `event.next()` which leads to faster connection ([xo-server#52](https://github.com/vatesfr/xo-server/issues/52))
## Bug fixes
### Bug fixes
- removed servers are properly disconnected ([xo-web#61](https://github.com/vatesfr/xo-web/issues/61))
- fix VM creation with multiple interfaces ([xo-wb#229](https://github.com/vatesfr/xo-wb/issues/229))
@@ -68,7 +611,7 @@ them.
[Blog post of this release](https://xen-orchestra.com/blog/xen-orchestra-3-8).
## Enhancements
### Enhancements
- initial plugin system ([xo-server#37](https://github.com/vatesfr/xo-server/issues/37))
- new authentication system based on providers ([xo-server#39](https://github.com/vatesfr/xo-server/issues/39))
@@ -77,7 +620,7 @@ them.
- network creation on the VM page ([xo-web#216](https://github.com/vatesfr/xo-web/issues/216))
- charts on the host and SR pages ([xo-web#217](https://github.com/vatesfr/xo-web/issues/217))
## Bug fixes
### Bug fixes
- fix *Invalid parameter(s)* message on the settings page ([xo-server#49](https://github.com/vatesfr/xo-server/issues/49))
- fix mouse clicks in console ([xo-web#205](https://github.com/vatesfr/xo-web/issues/205))

28
ISSUE_TEMPLATE.md Normal file
View File

@@ -0,0 +1,28 @@
<!--
Welcome to the issue section of Xen Orchestra!
Here you can:
- report an issue
- propose an enhancement
- ask a question
The template below is only a proposition for your ticket, feel free to
change it as appropriate :)
-->
### Context
- **XO version**: XO appliance / `stable` branch / `next-release` branch
If from the sources:
- **Component**: xo-web / xo-server / *unknown*
- **Node/npm version**: *just execute `npm version`*
### Expected behavior
<!-- What you expect to happen -->
### Current behavior
<!-- What is actually happening -->

View File

@@ -1,4 +1,4 @@
# Xen Orchestra Web
# Xen Orchestra Web [![Build Status](https://travis-ci.org/vatesfr/xo-web.png?branch=master)](https://travis-ci.org/vatesfr/xo-web)
![](http://i.imgur.com/tRffA5y.png)
@@ -6,9 +6,6 @@ XO-Web is part of [Xen Orchestra](https://github.com/vatesfr/xo), a web interfac
It is a web client for [XO-Server](https://github.com/vatesfr/xo-server).
[![Dependency Status](https://david-dm.org/vatesfr/xo-web.svg?theme=shields.io)](https://david-dm.org/vatesfr/xo-web)
[![devDependency Status](https://david-dm.org/vatesfr/xo-web/dev-status.svg?theme=shields.io)](https://david-dm.org/vatesfr/xo-web#info=devDependencies)
___
## Installation
@@ -29,6 +26,31 @@ Development build:
$ npm run dev
```
### Environment
#### `NODE_ENV`
Set to *production* it disables many checks which result in increased
performance.
#### `XOA_PLAN`
- 1: Free
- 2: Starter
- 3: Enterprise
- 4: Premium
- 5: Sources
```js
if (process.env.XOA_PLAN < 5) {
console.log('included only in XOA')
}
if (process.env.XOA_PLAN > 3) {
console.log('included only in Premium and Sources')
}
```
## How to report a bug?
If you are certain the bug is exclusively related to XO-Web, you may use the [bugtracker of this repository](https://github.com/vatesfr/xo-web/issues).
@@ -38,8 +60,11 @@ Otherwise, please consider using the [bugtracker of the general repository](http
## Process for new release
```bash
# Switch to the master branch.
git checkout master
# Switch to the stable branch.
git checkout stable
# Fetches latest changes.
git pull --ff-only
# Merge changes of the next-release branch.
git merge next-release
@@ -50,12 +75,12 @@ npm version minor
# Go back to the next-release branch.
git checkout next-release
# Fetches the last changes (the merge and version bump) from master to
# Fetches the last changes (the merge and version bump) from stable to
# next-release.
git pull --fast-forward master
git merge --ff-only stable
# Push the changes on git.
git push origin master:master next-release:next-release
git push --follow-tags origin stable next-release
# Publish this release to npm.
npm publish

View File

@@ -1,180 +0,0 @@
// Must be loaded before angular.
import 'angular-file-upload'
import angular from 'angular'
import uiBootstrap from'angular-ui-bootstrap'
import uiIndeterminate from'angular-ui-indeterminate'
import uiRouter from'angular-ui-router'
import uiSelect from'angular-ui-select'
import naturalSort from 'angular-natural-sort'
import xeditable from 'angular-xeditable'
import xoDirectives from 'xo-directives'
import xoFilters from 'xo-filters'
import xoServices from 'xo-services'
import aboutState from './modules/about'
import consoleState from './modules/console'
import deleteVmsState from './modules/delete-vms'
import genericModalState from './modules/generic-modal'
import hostState from './modules/host'
import listState from './modules/list'
import loginState from './modules/login'
import navbarState from './modules/navbar'
import newSrState from './modules/new-sr'
import newVmState from './modules/new-vm'
import poolState from './modules/pool'
import settingsState from './modules/settings'
import srState from './modules/sr'
import treeState from './modules/tree'
import updater from './modules/updater'
import vmState from './modules/vm'
import '../dist/bower_components/angular-chart.js/dist/angular-chart.js'
// ===================================================================
export default angular.module('xoWebApp', [
uiBootstrap,
uiIndeterminate,
uiRouter,
uiSelect,
naturalSort,
xeditable,
xoDirectives,
xoFilters,
xoServices,
aboutState,
consoleState,
deleteVmsState,
genericModalState,
hostState,
listState,
loginState,
navbarState,
newSrState,
newVmState,
poolState,
settingsState,
srState,
treeState,
updater,
vmState,
'chart.js'
])
// Prevent Angular.js from mangling exception stack (interfere with
// source maps).
.factory('$exceptionHandler', () => function (exception) {
throw exception
})
.config(function (
$compileProvider,
$stateProvider,
$urlRouterProvider,
$tooltipProvider,
uiSelectConfig
) {
// Disable debug data to improve performance.
//
// In case of a bug, simply use `angular.reloadWithDebugInfo()` in
// the console.
//
// See https://docs.angularjs.org/guide/production
$compileProvider.debugInfoEnabled(false)
// Redirect to default state.
$stateProvider.state('index', {
url: '/',
controller: function ($state, xoApi) {
let isAdmin = xoApi.user && (xoApi.user.permission === 'admin')
$state.go(isAdmin ? 'tree' : 'list')
}
})
// Redirects unmatched URLs to `/`.
$urlRouterProvider.otherwise('/')
// Changes the default settings for the tooltips.
$tooltipProvider.options({
appendToBody: true,
placement: 'bottom'
})
uiSelectConfig.theme = 'bootstrap'
uiSelectConfig.resetSearchInput = true
})
.run(function (
$anchorScroll,
$rootScope,
$state,
editableOptions,
editableThemes,
notify,
updater,
xoApi
) {
$rootScope.$on('$stateChangeStart', function (event, state, stateParams) {
let {user} = xoApi
let loggedIn = !!user
if (state.name === 'login') {
if (loggedIn) {
event.preventDefault()
$state.go('index')
}
return
}
if (!loggedIn) {
event.preventDefault()
// FIXME: find a better way to pass info to the login controller.
$rootScope._login = { state, stateParams }
$state.go('login')
return
}
if (user.permission === 'admin') {
return
}
// The user must have the `admin` permission to access the
// settings pages.
if (/^settings\..*|tree$/.test(state.name)) {
event.preventDefault()
notify.error({
title: 'Restricted area',
message: 'You do not have the permission to view this page'
})
}
let {id} = stateParams
if (id && !xoApi.canAccess(id)) {
event.preventDefault()
notify.error({
title: 'Restricted area',
message: 'You do not have the permission to view this page'
})
}
})
// Work around UI Router bug (https://github.com/angular-ui/ui-router/issues/1509)
$rootScope.$on('$stateChangeSuccess', function () {
$anchorScroll()
})
editableThemes.bs3.inputClass = 'input-sm'
editableThemes.bs3.buttonsClass = 'btn-sm'
editableOptions.theme = 'bs3'
})
.name

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

View File

@@ -1,62 +0,0 @@
//- HTML 5 Doctype
doctype html
//- The “no-js” class will be automatically removed if JavaScript is
//- available.
html.no-js(lang="en", dir="ltr")
head
meta(charset="utf-8")
//- This file is a part of Xen Orchestra Web.
//-
//- Xen Orchestra Web is free software: you can redistribute it and/or
//- modify it under the terms of the GNU Affero General Public License
//- as published by the Free Software Foundation, either version 3 of
//- the License, or (at your option) any later version.
//-
//- Xen Orchestra Web is distributed in the hope that it will be
//- useful, but WITHOUT ANY WARRANTY; without even the implied warranty
//- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//- Affero General Public License for more details.
//-
//- You should have received a copy of the GNU Affero General Public License
//- along with Xen Orchestra Web. If not, see
//- <http://www.gnu.org/licenses/>.
//-
//- @author Olivier Lambert <olivier.lambert@vates.fr>
//- @license http://www.gnu.org/licenses/agpl-3.0-standalone.html GNU AGPLv3
//-
//- @package Xen Orchestra Web
//- Makes sure IE is using the last engine available.
meta(http-equiv="X-UA-Compatible", content="IE=edge,chrome=1")
//- Replaces the “no-js” class by the “js” class if JavaScript is
//- available.
script.
!function(d){d.className=d.className.replace(/\\bno-js\b/,'js')}(document.documentElement)
//- (To confirm.) For smartphones and tablets: sets the page
//- width to the device width and prevents the page from being
//- zoomed in when going to landscape mode.
meta(name="viewport", content="width=device-width, initial-scale=1.0")
title Xen Orchestra
meta(name="description", content="Web interface for XenServer/XAPI Hosts")
meta(name="author", content="Vates SAS")
//- Place favicon.ico and apple-touch-icon.png in the root directory
link(rel="stylesheet", href="styles/main.css")
body(
ng-app = 'xoWebApp'
)
toaster-container
//- Navigation bar.
navbar
//- Main content (managed by the router).
.view-main(ui-view = "")
script(src="bower_components/Chart.js/Chart.min.js")
script(src="app.js")

View File

@@ -1,22 +0,0 @@
import angular from 'angular'
import uiRouter from 'angular-ui-router'
import pkg from '../../../package'
// ===================================================================
export default angular.module('xoWebApp.about', [
uiRouter
])
.config(function ($stateProvider) {
$stateProvider.state('about', {
url: '/about',
controller: 'AboutCtrl',
template: require('./view')
})
})
.controller('AboutCtrl', function ($scope) {
$scope.pkg = pkg
})
// A module exports its name.
.name

View File

@@ -1,50 +0,0 @@
//- TODO: lots of stuff.
.grid
.panel.panel-default
p.page-title About Xen Orchestra
p.text-center ({{pkg.name}} {{pkg.version}})
.grid
//- Vates
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-lightbulb-o(style="color: #e25440;")
| Vates
.panel-body
p.text-center
| We are the team behind Xen Orchestra, we are Vates! We create Open Source products and we offer commercial support for Xen and Xen Orchestra. Want to know more about us? Go to our website!
p.text-center
img(src="images/arrow.png")
br
p.text-center
a.btn.btn-success(href="https://vates.fr")
i.fa.fa-hand-o-right
| Our website
//- Open Source
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-thumbs-up(style="color: #e25440;")
| Open Source
.panel-body
p.text-center
| This project is Open Source (AGPL), everyone is welcome aboard! You want a specific feature in XO? Report a bug? Go to our project website, read the FAQ and get involved in the project!
p.text-center
img(src="images/opensource.png")
br
p.text-center
a.btn.btn-info(href="https://xen-orchestra.com")
i.fa.fa-flask
| Project website
//- Pro support
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-truck(style="color: #e25440;")
| Pro Support Delivered
.panel-body
p.text-center
| Our XO Appliance can be delivered with professional support: stay relaxed, we got your back! You can also have assitance for deploying or upgrade your virtualized infrastructure through our deep understanding of Xen.
p.text-center
img(src="images/support.png")
p.text-center
a.btn.btn-primary(href="https://xen-orchestra.com/services/")
i.fa.fa-envelope
| Get services

View File

@@ -1,91 +0,0 @@
angular = require 'angular'
forEach = require('lodash.foreach')
includes = require('lodash.includes')
#=====================================================================
module.exports = angular.module 'xoWebApp.console', [
require 'angular-ui-router'
require 'angular-no-vnc'
]
.config ($stateProvider) ->
$stateProvider.state 'consoles_view',
url: '/consoles/:id'
controller: 'ConsoleCtrl'
template: require './view'
.controller 'ConsoleCtrl', ($scope, $stateParams, xoApi, xo) ->
{id} = $stateParams
{get} = xoApi
push = Array::push.apply.bind Array::push
merge = do ->
(args...) ->
result = []
for arg in args
push result, arg if arg?
result
srsByContainer = xoApi.getIndex('srsByContainer')
$scope.$watch(
-> xoApi.get id
(VM) ->
$scope.consoleUrl = null
unless xoApi.user
$scope.VDIs = []
return
$scope.VM = VM
return unless (
VM? and
VM.power_state is 'Running' and
not includes(VM.current_operations, 'clean_reboot')
)
pool = get VM.$poolId
return unless pool
$scope.consoleUrl = "./api/consoles/#{id}"
host = get VM.$container # host because the VM is running.
return unless host
# FIXME: We should filter on connected SRs (PBDs)!
SRs = []
forEach(srsByContainer[host.id], (template) =>
SRs.push(template)
return
)
forEach(srsByContainer[pool.id], (template) =>
SRs.push(template)
return
)
$scope.VDIs = do ->
VDIs = []
for SR in SRs
push VDIs, SR.VDIs if SR.content_type is 'iso'
get VDIs
cdDrive = do ->
return VBD for VBD in (get VM.$VBDs) when VBD.is_cd_drive
null
$scope.mountedIso =
if cdDrive and cdDrive.VDI and (VDI = get cdDrive.VDI)
VDI.id
else
''
)
$scope.startVM = xo.vm.start
$scope.stopVM = xo.vm.stop
$scope.rebootVM = xo.vm.restart
$scope.eject = ->
xo.vm.ejectCd id
$scope.insert = (disc_id) ->
xo.vm.insertCd id, disc_id, true
# A module exports its name.
.name

View File

@@ -1,65 +0,0 @@
.container: .panel.panel-default
//- Title
p.page-title
span.fa-stack
i.fa.fa-square-o.fa-stack-2x
i.xo-icon-console.fa-stack-1x(class = 'xo-color-{{VM.power_state | lowercase}}')
| &nbsp;
a(
class = 'xo-color-{{VM.power_state | lowercase}}'
ui-sref = 'VMs_view({id: VM.id})'
) {{VM.name_label}}
.list-group
//- Toolbar
.list-group-item: .row.text-center
.col-sm-6: .input-group
select.form-control(
ng-model = 'mountedIso'
ng-change = 'insert(mountedIso)'
ng-options = 'VDI.id as VDI.name_label group by (VDI.$SR | resolve).name_label for VDI in VDIs | orderBy:natural("name_label")'
)
.input-group-btn
button.btn.btn-default(
ng-click = 'eject()'
ng-disabled = '!mountedIso'
)
i.fa.fa-eject
.col-sm-3: button.btn.btn-default(
ng-click = 'vncRemote.sendCtrlAltDel()'
)
i.fa.fa-keyboard-o
| &nbsp;
| Ctrl+Alt+Del
//- Action panel
.col-sm-3
.btn-group
button.btn.btn-default.inversed(
ng-if = "VM.power_state == ('Running' || 'Paused')"
tooltip = "Stop VM"
type = "button"
xo-click = "stopVM(VM.id)"
)
i.fa.fa-stop.fa-fw
button.btn.btn-default.inversed(
ng-if = "VM.power_state == ('Halted')"
tooltip = "Start VM"
type = "button"
xo-click = "startVM(VM.id)"
)
i.fa.fa-play.fa-fw
button.btn.btn-default.inversed(
ng-if = "VM.power_state == ('Running' || 'Paused')"
tooltip = "Reboot VM"
type = "button"
xo-click = "rebootVM(VM.id)"
)
i.fa.fa-refresh.fa-fw
//- Console
.list-group-item
no-vnc(
url = '{{consoleUrl}}'
remote-control = 'vncRemote'
)

View File

@@ -1,63 +0,0 @@
// TODO: should be integrated xo.deleteVms()
import angular from 'angular'
import forEach from 'lodash.foreach'
import uiBootstrap from 'angular-ui-bootstrap'
import xoServices from 'xo-services'
import view from './view'
// ===================================================================
export default angular.module('xoWebApp.deleteVms', [
uiBootstrap,
xoServices
])
.controller('DeleteVmsCtrl', function (
$scope,
$modalInstance,
xoApi,
VMsIds
) {
$scope.$watchCollection(() => xoApi.get(VMsIds), function (VMs) {
$scope.VMs = VMs
})
// Do disks have to be deleted for a given VM.
let disks = $scope.disks = {}
forEach(VMsIds, id => {
disks[id] = true
})
$scope.delete = function () {
let value = []
forEach(VMsIds, id => {
value.push([id, disks[id]])
})
$modalInstance.close(value)
}
})
.service('deleteVmsModal', function ($modal, xo) {
return function (ids) {
return $modal.open({
controller: 'DeleteVmsCtrl',
template: view,
resolve: {
VMsIds: () => ids
}
}).result.then(function (toDelete) {
let promises = []
forEach(toDelete, ([id, deleteDisks]) => {
promises.push(xo.vm.delete(id, deleteDisks))
})
return promises
})
}
})
// A module exports its name.
.name

View File

@@ -1,24 +0,0 @@
form(ng-submit="delete()")
.modal-header
h3 VMs deletion
.modal-body
p
| You are going to delete the following VMs, this is a
strong dangerous action
| !
table.table
tr
th.col-sm-3 Name
th.col-sm-6 Description
th.col-sm-3 Delete disks?
tbody
tr(ng-repeat="VM in VMs | orderBy:natural('name_label') track by VM.id")
td {{VM.name_label}}
td {{VM.name_description}}
td
input(type="checkbox", ng-model="disks[VM.id]")
.modal-footer
button.btn.btn-primary(type="submit")
| Delete
button.btn.btn-warning(type="button", ng-click="$dismiss()")
| Cancel

View File

@@ -1,39 +0,0 @@
import angular from 'angular'
import uiBootstrap from 'angular-ui-bootstrap'
// ===================================================================
export default angular.module('xoWebApp.genericModal', [
uiBootstrap
])
.controller('GenericModalCtrl', function ($scope, $modalInstance, options) {
$scope.title = options.title
$scope.message = options.message
$scope.yesButtonLabel = options.yesButtonLabel || 'Ok'
$scope.noButtonLabel = options.noButtonLabel
})
.service('modal', function ($modal) {
return {
confirm: function (opts) {
const modal = $modal.open({
controller: 'GenericModalCtrl',
template: require('./view'),
resolve: {
options: function () {
return {
title: opts.title,
message: opts.message,
noButtonLabel: 'Cancel'
}
}
}
})
return modal.result
}
}
})
// A module exports its name.
.name

View File

@@ -1,11 +0,0 @@
.modal-header
h3
i.fa.fa-exclamation-triangle.text-danger
| {{title}}
.modal-body
| {{message}}
.modal-footer
button.btn.btn-primary(type="button", ng-click="$close()")
| {{yesButtonLabel}}
button.btn.btn-warning(ng-if="noButtonLabel", type="button", ng-click="$dismiss()")
| {{noButtonLabel}}

View File

@@ -1,358 +0,0 @@
angular = require 'angular'
forEach = require 'lodash.foreach'
intersection = require 'lodash.intersection'
map = require 'lodash.map'
omit = require 'lodash.omit'
sum = require 'lodash.sum'
throttle = require 'lodash.throttle'
#=====================================================================
module.exports = angular.module 'xoWebApp.host', [
require 'angular-file-upload'
require 'angular-ui-router'
]
.config ($stateProvider) ->
$stateProvider.state 'hosts_view',
url: '/hosts/:id'
controller: 'HostCtrl'
template: require './view'
.controller 'HostCtrl', (
$scope, $stateParams, $http
$upload
$window
$timeout
dateFilter
xoApi, xo, modal, notify, bytesToSizeFilter
) ->
do (
hostId = $stateParams.id
controllers = xoApi.getIndex('vmControllersByContainer')
poolPatches = xoApi.getIndex('poolPatchesByPool')
srs = xoApi.getIndex('srsByContainer')
tasks = xoApi.getIndex('runningTasksByHost')
vms = xoApi.getIndex('vmsByContainer')
) ->
Object.defineProperties($scope, {
controller: {
get: () => controllers[hostId]
},
poolPatches: {
get: () => $scope.host && poolPatches[$scope.host.$poolId]
},
sharedSrs: {
get: () => $scope.host && srs[$scope.host.$poolId]
},
srs: {
get: () => srs[hostId]
},
tasks: {
get: () => tasks[hostId]
},
vms: {
get: () => vms[hostId]
}
})
$window.bytesToSize = bytesToSizeFilter # FIXME dirty workaround to custom a Chart.js tooltip template
host = null
$scope.currentPatchPage = 1
$scope.currentLogPage = 1
$scope.currentPCIPage = 1
$scope.currentGPUPage = 1
$scope.refreshStatControl = refreshStatControl = {
baseStatInterval: 5000
baseTimeOut: 10000
period: null
running: false
attempt: 0
start: () ->
return if this.running
this.stop()
this.running = true
this._reset()
$scope.$on('$destroy', () => this.stop())
return this._trig(Date.now())
_trig: (t1) ->
if this.running
timeoutSecurity = $timeout(
() => this.stop(),
this.baseTimeOut
)
return $scope.refreshStats($scope.host.id)
.then () => this._reset()
.catch (err) =>
if !this.running || this.attempt >= 2 || $scope.host.power_state isnt 'Running' || $scope.isVMWorking($scope.host)
return this.stop()
else
this.attempt++
.finally () =>
$timeout.cancel(timeoutSecurity)
if this.running
t2 = Date.now()
return this.period = $timeout(
() => this._trig(t2),
Math.max(this.baseStatInterval - (t2 - t1), 0)
)
_reset: () ->
this.attempt = 0
stop: () ->
if this.period
$timeout.cancel(this.period)
this.running = false
return
}
$scope.$watch(
-> xoApi.get $stateParams.id
(host) ->
$scope.host = host
return unless host?
pool = $scope.pool = xoApi.get host.$poolId
SRsToPBDs = $scope.SRsToPBDs = Object.create null
for PBD in host.$PBDs
PBD = xoApi.get PBD
# If this PBD is unknown, just skips it.
continue unless PBD
SRsToPBDs[PBD.SR] = PBD
$scope.listMissingPatches($scope.host.id)
if host.power_state is 'Running'
refreshStatControl.start()
else
refreshStatControl.stop()
)
$scope.$watch('vms', (vms) =>
$scope.vCPUs = sum(vms, (vm) => vm.CPUs.number)
)
$scope.cancelTask = (id) ->
modal.confirm({
title: 'Cancel task'
message: 'Are you sure you want to cancel this task?'
}).then ->
xo.task.cancel id
$scope.destroyTask = (id) ->
modal.confirm({
title: 'Destroy task'
message: 'Are you sure you want to destroy this task?'
}).then ->
xo.task.destroy id
$scope.disconnectPBD = xo.pbd.disconnect
$scope.removePBD = xo.pbd.delete
$scope.new_sr = xo.pool.new_sr
$scope.pool_addHost = (id) ->
xo.host.attach id
$scope.pool_removeHost = (id) ->
modal.confirm({
title: 'Remove host from pool'
message: 'Are you sure you want to detach this host from its pool? It will be automatically rebooted'
}).then ->
xo.host.detach id
$scope.rebootHost = (id) ->
modal.confirm({
title: 'Reboot host'
message: 'Are you sure you want to reboot this host? It will be disabled then rebooted'
}).then ->
xo.host.restart id
$scope.enableHost = (id) ->
xo.host.enable id
notify.info {
title: 'Host action'
message: 'Host is enabled'
}
$scope.disableHost = (id) ->
modal.confirm({
title: 'Disable host'
message: 'Are you sure you want to disable this host? In disabled state, no new VMs can be started and currently active VMs on the host continue to execute.'
}).then ->
xo.host.disable id
.then ->
notify.info {
title: 'Host action'
message: 'Host is disabled'
}
$scope.restartToolStack = (id) ->
modal.confirm({
title: 'Restart XAPI'
message: 'Are you sure you want to restart the XAPI toolstack?'
}).then ->
xo.host.restartToolStack id
$scope.shutdownHost = (id) ->
modal.confirm({
title: 'Shutdown host'
message: 'Are you sure you want to shutdown this host?'
}).then ->
xo.host.stop id
$scope.saveHost = ($data) ->
{host} = $scope
{name_label, name_description, enabled} = $data
$data = {
id: host.id
}
if name_label isnt host.name_label
$data.name_label = name_label
if name_description isnt host.name_description
$data.name_description = name_description
if enabled isnt host.enabled
if host.enabled
$scope.disableHost($data.id)
else
$scope.enableHost($data.id)
# enabled is not set via the "set" method, so we remove it before send it
delete $data.enabled
xoApi.call 'host.set', $data
$scope.deleteAllLog = ->
modal.confirm({
title: 'Log deletion'
message: 'Are you sure you want to delete all the logs?'
}).then ->
for log in $scope.host.messages
console.log "Remove log #{log.id}"
xo.log.delete log.id
$scope.deleteLog = (id) ->
console.log "Remove log #{id}"
xo.log.delete id
$scope.connectPBD = (id) ->
console.log "Connect PBD #{id}"
xoApi.call 'pbd.connect', {id: id}
$scope.disconnectPBD = (id) ->
console.log "Disconnect PBD #{id}"
xoApi.call 'pbd.disconnect', {id: id}
$scope.removePBD = (id) ->
console.log "Remove PBD #{id}"
xoApi.call 'pbd.delete', {id: id}
$scope.connectPIF = (id) ->
console.log "Connect PIF #{id}"
xoApi.call 'pif.connect', {id: id}
$scope.disconnectPIF = (id) ->
console.log "Disconnect PIF #{id}"
xoApi.call 'pif.disconnect', {id: id}
$scope.removePIF = (id) ->
console.log "Remove PIF #{id}"
xoApi.call 'pif.delete', {id: id}
$scope.importVm = ($files, id) ->
file = $files[0]
notify.info {
title: 'VM import started'
message: "Starting the VM import"
}
xo.vm.import id
.then ({ $sendTo: url }) ->
return $upload.http {
method: 'POST'
url
data: file
}
.then (result) ->
throw result.status if result.status isnt 200
notify.info
title: 'VM import'
message: 'Success'
$scope.createNetwork = (name, description, pif, mtu, vlan) ->
$scope.createNetworkWaiting = true # disables form fields
notify.info {
title: 'Network creation...'
message: 'Creating the network'
}
params = {
host: $scope.host.id
name,
}
if mtu then params.mtu = mtu
if pif then params.pif = pif
if vlan then params.vlan = vlan
if description then params.description = description
xoApi.call 'host.createNetwork', params
.then ->
$scope.creatingNetwork = false
$scope.createNetworkWaiting = false
$scope.isPoolPatchApplied = (patch) ->
return true if patch.applied
hostPatch = intersection(patch.$host_patches, $scope.host.patches)
return false if not hostPatch.length
hostPatch = xoApi.get(hostPatch[0])
return hostPatch.applied
$scope.listMissingPatches = (id) ->
return xo.host.listMissingPatches id
.then (result) ->
$scope.updates = omit(result,map($scope.poolPatches,'id'))
$scope.installPatch = (id, patchUid) ->
console.log("Install patch "+patchUid+" on "+id)
notify.info {
title: 'Patch host'
message: "Patching the host, please wait..."
}
xo.host.installPatch id, patchUid
$scope.refreshStats = (id) ->
return xo.host.refreshStats id
.then (result) ->
result.cpuSeries = []
forEach result.cpus, (v,k) ->
result.cpuSeries.push 'CPU ' + k
return
result.pifSeries = []
forEach result.pifs, (v,k) ->
result.pifSeries.push '#' + Math.floor(k/2) + ' ' + if k % 2 then 'out' else 'in'
return
forEach result.date, (v,k) ->
result.date[k] = new Date(v*1000).toLocaleTimeString()
forEach result.memoryUsed, (v, k) ->
result.memoryUsed[k] = v*1024
forEach result.memory, (v, k) ->
result.memory[k] = v*1024
$scope.stats = result
$scope.statView = {
cpuOnly: false,
ramOnly: false,
netOnly: false,
loadOnly: false
}
# A module exports its name.
.name

View File

@@ -1,522 +0,0 @@
.grid
.panel.panel-default
p.page-title
i.xo-icon-host(class="xo-color-{{host.power_state | lowercase}}")
| {{host.name_label}}
small(ng-if="pool.name_label")
| (
a(ui-sref="pools_view({id: pool.id})") {{pool.name_label}}
| )
p.center {{host.bios_strings["system-manufacturer"]}} {{host.bios_strings["system-product-name"]}}
.grid
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-cogs(style="color: #e25440;")
| General
span.quick-edit(tooltip="Edit General settings", ng-click="hostSettings.$show()")
i.fa.fa-edit.fa-fw
.panel-body
form(editable-form="", name="hostSettings", onbeforesave="saveHost($data)")
dl.dl-horizontal
dt Name
dd
span(editable-text="host.name_label", e-name="name_label", e-form="hostSettings")
| {{host.name_label}}
dt Description
dd
span(editable-text="host.name_description", e-name="name_description", e-form="hostSettings")
| {{host.name_description}}
dt Enabled
dd
span(editable-select="host.enabled", e-ng-options="ap.v as ap.t for ap in [{v: true, t:'Yes'}, {v: false, t:'No'}]", e-name="enabled", e-form="hostSettings")
| {{host.enabled ? 'Yes' : 'No'}}
dt Tags
dd(ng-if="host.tags.length")
span(ng-repeat="tag in host.tags")
span.label.label-primary {{tag}}
dd(ng-if="!host.tags.length")
em No tags.
dt CPUs
dd {{host.CPUs["cpu_count"]}}x {{host.CPUs["modelname"]}}
dt Hostname
dd
| {{host.hostname}}
dt UUID
dd {{host.UUID}}
dt iQN
dd {{host.iSCSI_name}}
dt(ng-if="refreshStatControl.running && stats") vCPUs/CPUs:
dd(ng-if="refreshStatControl.running && stats") {{vCPUs}}/{{host.CPUs['cpu_count']}}
dt(ng-if="refreshStatControl.running && stats") Running VMs:
dd(ng-if="refreshStatControl.running && stats") {{vms | count}}
dt(ng-if="refreshStatControl.running && stats") RAM (used/free):
dd(ng-if="refreshStatControl.running && stats") {{host.memory.usage | bytesToSize}}/{{host.memory.size | bytesToSize}}
.btn-form(ng-show="hostSettings.$visible")
p.center
button.btn.btn-default(type="button", ng-disabled="hostSettings.$waiting", ng-click="hostSettings.$cancel()")
i.fa.fa-times
| Cancel
| &nbsp;
button.btn.btn-primary(type="submit", ng-disabled="hostSettings.$waiting")
i.fa.fa-save
| Save
.panel.panel-default
.panel-heading.panel-title
i.xo-icon-stats(style="color: #e25440;")
| Stats
.panel-body(ng-if="refreshStatControl.running && stats")
div(ng-if="statView.cpuOnly", ng-click="statView.cpuOnly = false")
p.stat-name
i.fa.fa-tachometer
| &nbsp; CPU usage
canvas.chart.chart-line.chart-stat-full(
id="bigCpu"
data="stats.cpus"
labels="stats.date"
series="stats.cpuSeries"
colours="['#0000ff', '#9999ff', '#000099', '#5555ff', '#000055']"
legend="true"
options='{responsive: true, maintainAspectRatio: false, tooltipTemplate: "<%if (label){%><%=label%>: <%}%><%= Math.round(10*value)/10 %>", multiTooltipTemplate:"<%if (datasetLabel){%><%=datasetLabel%>: <%}%><%= Math.round(10*value)/10 %>", pointDot: false, showScale: false, animation: false, datasetStrokeWidth: 0.8, scaleOverride: true, scaleSteps: 100, scaleStartValue: 0, scaleStepWidth: 1, pointHitDetectionRadius: 0}'
)
div(ng-if="statView.ramOnly", ng-click="statView.ramOnly = false")
p.stat-name
//- i.fa.fa-bar-chart
i.fa.fa-tasks
//- i.fa.fa-server
| &nbsp; RAM usage
canvas.chart.chart-line.chart-stat-full(
id="bigRam"
data="[stats.memoryUsed,stats.memory]"
labels="stats.date"
series="['Used RAM', 'Total RAM']"
colours="['#ff0000', '#ffbbbb']"
legend="true"
options=' {responsive: true, maintainAspectRatio: false, tooltipTemplate: "<%if (label){%><%=label%>: <%}%><%= bytesToSize(value) %>", multiTooltipTemplate:"<%if (datasetLabel){%><%=datasetLabel%>: <%}%><%= bytesToSize(value) %>", datasetStrokeWidth: 0.8, pointDot: false, showScale: false, scaleBeginAtZero: true, animation: false, pointHitDetectionRadius: 0}'
)
div(ng-if="statView.netOnly", ng-click="statView.netOnly = false")
p.stat-name
i.fa.fa-sitemap
| &nbsp; Network I/O
canvas.chart.chart-line.chart-stat-full(
id="bigNet"
data="stats.pifs"
labels="stats.date"
series="stats.pifSeries"
colours="['#dddd00', '#dddd77', '#777700', '#dddd55', '#555500', '#ffdd00']"
legend="true"
options=' {responsive: true, maintainAspectRatio: false, tooltipTemplate: "<%if (label){%><%=label%>: <%}%><%= bytesToSize(value) %>", multiTooltipTemplate:"<%if (datasetLabel){%><%=datasetLabel%>: <%}%><%= bytesToSize(value) %>", datasetStrokeWidth: 0.8, pointDot: false, showScale: false, scaleBeginAtZero: true, animation: false, pointHitDetectionRadius: 0}'
)
div(ng-if="statView.loadOnly", ng-click="statView.loadOnly = false")
p.stat-name
i.fa.fa-cogs
| &nbsp; Load Average
canvas.chart.chart-line.chart-stat-full(
id="bigLoad"
data="[stats.load]"
labels="stats.date"
series="['Load']"
colours="['#960094']"
legend="true"
options=' {responsive: true, maintainAspectRatio: false, multiTooltipTemplate:"<%if (datasetLabel){%><%=datasetLabel%>: <%}%><%= bytesToSize(value) %>", datasetStrokeWidth: 0.8, pointDot: false, showScale: false, scaleBeginAtZero: true, animation: false, pointHitDetectionRadius: 0}'
)
div(ng-if="!statView.netOnly && !statView.loadOnly && !statView.cpuOnly && !statView.ramOnly")
.row
.col-sm-6(ng-click="statView.cpuOnly=true")
p.stat-name
i.fa.fa-tachometer
| &nbsp; CPU usage
canvas.chart.chart-line.chart-stat-preview(
id="smallCpu"
data="stats.cpus"
labels="stats.date"
series="stats.cpuSeries"
colours="['#0000ff', '#9999ff', '#000099', '#5555ff', '#000055']"
options='{responsive: true, maintainAspectRatio: false, showTooltips: false, pointDot: false, showScale: false, animation: false, datasetStrokeWidth: 0.8, scaleOverride: true, scaleSteps: 100, scaleStartValue: 0, scaleStepWidth: 1}'
)
.col-sm-6(ng-click="statView.ramOnly=true")
p.stat-name
//- i.fa.fa-bar-chart
i.fa.fa-tasks
//- i.fa.fa-server
| &nbsp; RAM usage
canvas.chart.chart-line.chart-stat-preview(
id="smallRam"
data="[stats.memoryUsed,stats.memory]"
labels="stats.date"
series="['Used RAM', 'Total RAM']"
colours="['#ff0000', '#ffbbbb']"
options="{responsive: true, maintainAspectRatio: false, showTooltips: false, datasetStrokeWidth: 0.8, pointDot: false, showScale: false, scaleBeginAtZero: true, animation: false}"
)
.row
.col-sm-6(ng-click="statView.netOnly=true")
p.stat-name
i.fa.fa-sitemap
| &nbsp; Network I/O
canvas.chart.chart-line.chart-stat-preview(
id="smallNet"
data="stats.pifs"
labels="stats.date"
series="stats.pifSeries"
colours="['#dddd00', '#dddd77', '#777700', '#dddd55', '#555500', '#ffdd00']"
options="{responsive: true, maintainAspectRatio: false, showTooltips: false, datasetStrokeWidth: 0.8, pointDot: false, showScale: false, scaleBeginAtZero: true, animation: false}"
)
.col-sm-6(ng-click="statView.loadOnly=true")
p.stat-name
i.fa.fa-cogs
| &nbsp; Load Average
canvas.chart.chart-line.chart-stat-preview(
id="smallDisk"
data="[stats.load]"
labels="stats.date"
series="['Load']"
colours="['#960094']"
options="{responsive: true, maintainAspectRatio: false, showTooltips: false, datasetStrokeWidth: 0.8, pointDot: false, showScale: false, scaleBeginAtZero: true, animation: false}"
)
.panel-body(ng-if="!refreshStatControl.running || !stats")
.row
.col-sm-6.col-lg-4
p.stat-name CPU usage:
p.center.mid-stat {{vCPUs}}/{{host.CPUs['cpu_count']}}
.col-sm-6.col-lg-4
p.stat-name RAM used:
p.center.mid-stat {{host.memory.usage | bytesToSize}}
.col-sm-4.visible-lg
p.stat-name Running VMs:
p.center.mid-stat {{vms | count}}
.row
p.center(ng-if="refreshStatControl.running")
i.fa.fa-circle-o-notch.fa-spin.fa-2x
| &nbsp; Fetching stats...
.row.hidden-lg
.col-sm-12
br
p.stat-name {{vms | count}} running VMs
//- Action panel
.grid
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-flash(style="color: #e25440;")
| Actions
.panel-body.text-center
.grid
.grid-cell.btn-group
button.btn(tooltip="Add SR", type="button", style="width: 90%", xo-sref="SRs_new({container: host.id})")
i.xo-icon-sr.fa-2x.fa-fw
.grid-cell.btn-group
button.btn(tooltip="Add VM", type="button", style="width: 90%", xo-sref="VMs_new({container: host.id})")
i.xo-icon-vm.fa-2x.fa-fw
.grid-cell.btn-group
button.btn(tooltip="Reboot host", type="button", style="width: 90%", xo-click="rebootHost(host.id)")
i.fa.fa-refresh.fa-2x.fa-fw
.grid-cell.btn-group
button.btn(tooltip="Shutdown host", type="button", style="width: 90%", xo-click="shutdownHost(host.id)")
i.fa.fa-power-off.fa-2x.fa-fw
.grid-cell.btn-group(ng-if="host.enabled")
button.btn(tooltip="Disable host", type="button", style="width: 90%", xo-click="disableHost(host.id)")
i.fa.fa-times-circle.fa-2x.fa-fw
.grid-cell.btn-group(ng-if="!host.enabled")
button.btn(tooltip="Enable host", type="button", style="width: 90%", xo-click="enableHost(host.id)")
i.fa.fa-check-circle.fa-2x.fa-fw
.grid-cell.btn-group
button.btn(tooltip="Restart toolstack", type="button", style="width: 90%", xo-click="restartToolStack(host.id)")
i.fa.fa-retweet.fa-2x.fa-fw
.grid-cell.btn-group(ng-if="pool.name_label")
button.btn(tooltip="Remove from pool", style="width: 90%", type="button", xo-click="pool_removeHost(host.id)")
i.fa.fa-cloud-upload.fa-2x.fa-fw
.grid-cell.btn-group(ng-if="!pool.name_label")
button.btn(tooltip="Add to pool", style="width: 90%", type="button", xo-click="pool_addHost(host.id)")
i.fa.fa-cloud-download.fa-2x.fa-fw
.grid-cell.btn-group(style="margin-bottom: 0.5em")
button.btn(
tooltip="Import VM"
type="button"
style="width: 90%"
ng-file-select = 'importVm($files, host.id)'
)
i.fa.fa-upload.fa-2x.fa-fw
.grid-cell.btn-group(style="margin-bottom: 0.5em")
button.btn(
tooltip="Host console"
type="button"
style="width: 90%"
xo-sref="consoles_view({id: controller.id})"
)
i.xo-icon-console.fa-2x.fa-fw
//- TODO: Memory panel
.grid
.panel.panel-default
.panel-heading.panel-title
i.xo-icon-memory(style="color: #e25440;")
| Memory
.panel-body.text-center
.progress
.progress-bar-host(role="progressbar", aria-valuemin="0", aria-valuenow="{{controller.memory.size}}", aria-valuemax="{{host.memory.size}}", style="width: {{[controller.memory.size, host.memory.size] | percentage}}", tooltip="{{host.name_label}}: {{[controller.memory.size, host.memory.size] | percentage}}")
small {{host.name_label}}
.progress-bar.progress-bar-vm(ng-repeat="VM in vms | map | orderBy:natural('name_label') track by VM.id", role="progressbar", aria-valuemin="0", aria-valuenow="{{VM.memory.size}}", aria-valuemax="{{host.memory.size}}", style="width: {{[VM.memory.size, host.memory.size] | percentage}}", xo-sref="VMs_view({id: VM.id})", tooltip="{{VM.name_label}}: {{[VM.memory.size, host.memory.size] | percentage}}")
small {{VM.name_label}}
ul.list-inline.text-center
li Total: {{host.memory.size | bytesToSize}}
li Currently used: {{host.memory.usage | bytesToSize}}
li Available: {{host.memory.size-host.memory.usage | bytesToSize}}
//- SR panel
.grid
.panel.panel-default
.panel-heading.panel-title
i.xo-icon-sr(style="color: #e25440;")
| Storage
.panel-body
table.table.table-hover
tr
th Name
th Format
th Size
th Physical/Allocated usage
th Type
th Status
//- TODO: display PBD status for each SR of this host (connected or not)
//- Shared SR
tr(xo-sref="SRs_view({id: SR.id})", ng-repeat="SR in sharedSrs | map | orderBy:natural('name_label') track by SR.id")
td.oneliner
| {{SR.name_label}}
td {{SR.SR_type}}
td {{SR.size | bytesToSize}}
td
.progress-condensed
.progress-bar(role="progressbar", aria-valuemin="0", aria-valuenow="{{SR.usage}}", aria-valuemax="{{SR.size}}", style="width: {{[SR.physical_usage, SR.size] | percentage}}", tooltip="Physical usage: {{[SR.physical_usage, SR.size] | percentage}}")
.progress-bar.progress-bar-info(role="progressbar", aria-valuemin="0", aria-valuenow="{{SR.physical_usage}}", aria-valuemax="{{SR.size}}", style="width: {{[(SR.usage-SR.physical_usage), SR.size] | percentage}}", tooltip="Allocated: {{[(SR.usage), SR.size] | percentage}}")
td
span.label.label-primary Shared
td(ng-if="SRsToPBDs[SR.id].attached")
span.label.label-success Connected
span.pull-right.btn-group.quick-buttons
a(tooltip="Disconnect this SR", xo-click="disconnectPBD(SRsToPBDs[SR.id].id)")
i.fa.fa-unlink.fa-lg
td(ng-if="!SRsToPBDs[SR.id].attached")
span.label.label-default Disconnected
span.pull-right.btn-group.quick-buttons
a(tooltip="Reconnect this SR", xo-click="connectPBD(SRsToPBDs[SR.id].id)")
i.fa.fa-link.fa-lg
a(tooltip="Forget this SR", xo-click="removePBD(SRsToPBDs[SR.id].id)")
i.fa.fa-ban.fa-lg
//- Local SR
//- TODO: migrate to SRs and not PBDs when implemented in xo-server spec
tr(xo-sref="SRs_view({id: SR.id})", ng-repeat="SR in srs | map | orderBy:natural('name_label') track by SR.id")
td
| {{SR.name_label}}
td {{SR.SR_type}}
td {{SR.size | bytesToSize}}
td
.progress-condensed
.progress-bar(role="progressbar", aria-valuemin="0", aria-valuenow="{{SR.usage}}", aria-valuemax="{{SR.size}}", style="width: {{[SR.physical_usage, SR.size] | percentage}}", tooltip="Physical usage: {{[SR.physical_usage, SR.size] | percentage}}")
.progress-bar.progress-bar-info(role="progressbar", aria-valuemin="0", aria-valuenow="{{SR.physical_usage}}", aria-valuemax="{{SR.size}}", style="width: {{[(SR.usage-SR.physical_usage), SR.size] | percentage}}", tooltip="Allocated: {{[(SR.usage), SR.size] | percentage}}")
td
span.label.label-info Local
td(ng-if="SRsToPBDs[SR.id].attached")
span.label.label-success Connected
span.pull-right.btn-group.quick-buttons
a(tooltip="Disconnect this SR", xo-click="disconnectPBD(SRsToPBDs[SR.id].id)")
i.fa.fa-unlink.fa-lg
td(ng-if="!SRsToPBDs[SR.id].attached")
span.label.label-default Disconnected
span.pull-right.btn-group.quick-buttons
a(tooltip="Reconnect this SR", xo-click="connectPBD(SRsToPBDs[SR.id].id)")
i.fa.fa-link.fa-lg
a(tooltip="Forget this SR", xo-click="removePBD(SRsToPBDs[SR.id].id)")
i.fa.fa-ban.fa-lg
//- Networks/Interfaces panel
.grid
.panel.panel-default
.panel-heading.panel-title
i.xo-icon-network(style="color: #e25440;")
| Interfaces
.panel-body
table.table.table-hover
th.col-md-1 Device
th.col-md-1 VLAN
th.col-md-1 Address
th.col-md-2 MAC
th.col-md-1 MTU
th.col-md-1 Link status
tr(ng-repeat="PIF in host.$PIFs | resolve | orderBy:natural('name_label') track by PIF.id")
td
| {{PIF.device}}
span.label.label-primary(ng-if="PIF.management") XAPI
td
span(ng-if="PIF.vlan > -1")
| {{PIF.vlan}}
span(ng-if="PIF.vlan == -1")
| -
td.oneliner {{PIF.IP}} ({{PIF.mode}})
td.oneliner {{PIF.MAC}}
td {{PIF.MTU}}
td(ng-if="PIF.attached")
span.label.label-success Connected
span.pull-right.btn-group.quick-buttons
a(tooltip="Disconnect this interface", xo-click="disconnectPIF(PIF.id)")
i.fa.fa-unlink.fa-lg
td(ng-if="!PIF.attached")
span.label.label-default Disconnected
span.pull-right.btn-group.quick-buttons
a(tooltip="Connect this interface", xo-click="connectPIF(PIF.id)")
i.fa.fa-link.fa-lg
a(tooltip="Remove this interface", xo-click="removePIF(PIF.id)")
i.fa.fa-trash-o.fa-lg
.text-right
button.btn(type="button", ng-class = '{"btn-success": creatingNetwork, "btn-primary": !creatingNetwork}', ng-click="creatingNetwork = !creatingNetwork")
i.fa.fa-plus(ng-if = '!creatingNetwork')
i.fa.fa-minus(ng-if = 'creatingNetwork')
| Create Network
br
form.form-inline.text-right#createNetworkForm(ng-if = 'creatingNetwork', name = 'createNetworkForm', ng-submit = 'createNetwork(newNetworkName, newNetworkDescription, newNetworkPIF, newNetworkMTU, newNetworkVlan)')
fieldset(ng-attr-disabled = '{{ createNetworkWaiting ? true : undefined }}')
.form-group
label(for = 'newNetworkPIF') Interface&nbsp;
select.form-control(ng-model = 'newNetworkPIF', ng-change = 'updateMTU(newNetworkPIF)', ng-options='(PIF | resolve).device for PIF in host.$PIFs')
option(value = '', disabled) None
| &nbsp;
.form-group
label.control-label(for = 'newNetworkName') Name&nbsp;
input#newNetworkName.form-control(type = 'text', ng-model = 'newNetworkName', required)
| &nbsp;
.form-group
label.control-label(for = 'newNetworkDescription') Description&nbsp;
input#newNetworkDescription.form-control(type = 'text', ng-model = 'newNetworkDescription', placeholder= 'Network created with Xen Orchestra')
| &nbsp;
.form-group
label.control-label(for = 'newNetworkVlan') VLAN&nbsp;
input#newNetworkVlan.form-control(type = 'text', ng-model = 'newNetworkVlan', placeholder = 'Defaut: no VLAN')
| &nbsp;
.form-group
label(for = 'newNetworkMTU') MTU&nbsp;
input#newNetworkMTU.form-control(type = 'text', ng-model = 'newNetworkMTU', placeholder = 'Default: 1500')
| &nbsp;
.form-group
button.btn.btn-primary(type = 'submit')
i.fa.fa-plus-square
| Create
span(ng-if = 'createNetworkWaiting')
| &nbsp;
i.fa.fa-spin.fa-circle-o-notch
br
//- CPU and Logs panels
.grid
//- Task panel
.panel.panel-default
.panel-heading.panel-title(ng-if="tasks | isNotEmpty")
i.fa.fa-spinner.fa-pulse(style="color: #e25440;")
| Pending tasks
.panel-heading.panel-title(ng-if="tasks | isEmpty")
i.fa.fa-spinner(style="color: #e25440;")
| Pending tasks
.panel-body
p.center(ng-if="tasks | isEmpty") No recent tasks
table.table.table-hover(ng-if="tasks | isNotEmpty")
th Date
th Progress
th Name
//- TODO: working reverse order, from recent to oldest
tr(ng-repeat="task in tasks | map | orderBy:'created':true track by task.id")
td.oneliner {{task.created * 1e3 | date:'medium'}}
td
.progress-condensed
.progress-bar.progress-bar-success.progress-bar-striped.active.progress-bar-black(role="progressbar", aria-valuemin="0", aria-valuenow="{{task.progress*100}}", aria-valuemax="100", style="width: {{task.progress*100}}%", tooltip="Progress: {{task.progress*100 | number:1}}%")
| {{task.progress*100 | number:1}}%
td.oneliner
| {{task.name_label}}
span.pull-right.btn-group.quick-buttons
a(xo-click="cancelTask(task.id)")
i.fa.fa-times.fa-lg(tooltip="Cancel this task")
a(xo-click="destroyTask(task.id)")
i.fa.fa-trash-o.fa-lg(tooltip="Destroy this task")
//- Logs panel
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-comments(style="color: #e25440;")
| Logs
span.quick-edit(ng-if="host.messages | isNotEmpty", tooltip="Remove all logs", ng-click="deleteAllLog()")
i.fa.fa-trash-o.fa-fw
.panel-body
p.center(ng-if="host.messages | isEmpty") No recent logs
table.table.table-hover(ng-if="host.messages | isNotEmpty")
th Date
th Name
tr(ng-repeat="message in host.messages | map | orderBy:'-time' | slice:(5*(currentLogPage-1)):(5*currentLogPage) track by message.id")
td {{message.time*1e3 | date:"medium"}}
td
| {{message.name}}
span.pull-right.btn-group.quick-buttons
a(xo-click="deleteLog(message.id)")
i.fa.fa-trash-o.fa-lg(tooltip="Remove this log entry")
.center(ng-if = '(host.messages | count) > 5')
pagination(boundary-links="true", total-items="host.messages | count", ng-model="$parent.currentLogPage", items-per-page="5", max-size="5", class="pagination-sm", previous-text="<", next-text=">", first-text="<<", last-text=">>")
.grid
//- Patches panel
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-file-code-o(style="color: #e25440;")
| Patches
span.quick-edit(ng-click="listMissingPatches(host.id)", tooltip="Check for updates")
i.fa.fa-question-circle
.panel-body
table.table.table-hover(ng-if="poolPatches || updates")
th.col-sm-2 Name
th.col-sm-5 Description
th.col-sm-3 Applied/Released date
th.col-sm-1 Size
th.col-sm-1 Status
tr(ng-repeat="patch in updates")
td.oneliner {{patch.name}}
td.oneliner
a(href="{{patch.documentationUrl}}", target="_blank") {{patch.description}}
td.oneliner {{patch.date | date:"medium"}}
td -
td
span(ng-click="installPatch(host.id, patch.uuid)", tooltip="Click to install the patch on this host")
span.label.label-danger Missing
tr(ng-repeat="patch in poolPatches | map | slice:(5*(currentPatchPage-1)):(5*currentPatchPage)")
td.oneliner {{patch.name_label}}
td.oneliner {{patch.name_description}}
//- TODO: use a proper function for patch date, like poolPatchToHostPatch
td.oneliner {{((patch.$host_patches[0]) | resolve).time*1e3 | date:"medium"}}
td {{patch.size | bytesToSize}}
td
span(ng-if="isPoolPatchApplied(patch)")
span.label.label-success Applied
span(ng-click="installPatch(host.id, patch.id)", ng-if="!isPoolPatchApplied(patch)", tooltip="Click to apply the patch on this host")
span.label.label-warning Not applied
//- span.pull-right.btn-group.quick-buttons
//- a(xo-click="deletePatch(patch.id)")
//- i.fa.fa-trash-o.fa-lg(tooltip="Remove this patch")
.center(ng-if = '(poolPatches | count) > 5')
pagination(boundary-links="true", total-items="poolPatches | count", ng-model="$parent.currentPatchPage", items-per-page="5", max-size="5", class="pagination-sm", previous-text="<", next-text=">", first-text="<<", last-text=">>")
.grid
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-plug(style="color: #e25440;")
| PCI Devices
.panel-body
p.center(ng-if="!host.$PCIs") No PCI devices available
table.table.table-hover(ng-if="host.$PCIs")
th PCI Info
th Device Name
tr(ng-repeat="pci in host.$PCIs | resolve | orderBy:'pci_id' | slice:(5*(currentPCIPage-1)):(5*currentPCIPage) track by pci.id")
td.oneliner {{pci.pci_id}} ({{pci.class_name}})
td.oneliner {{pci.device_name}}
.center(ng-if = '(host.$PCIs | resolve).length > 5')
pagination(boundary-links="true", total-items="(host.$PCIs | resolve).length", ng-model="$parent.currentPCIPage", items-per-page="5", max-size="5", class="pagination-sm", previous-text="<", next-text=">", first-text="<<", last-text=">>")
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-desktop(style="color: #e25440;")
| GPUs
.panel-body
p.center(ng-if="host.$PGPUs.length === 0") No GPUs available
table.table.table-hover(ng-if="host.$PGPUs.length !== 0")
th Device
tr(ng-repeat="pgpu in host.$PGPUs | resolve | orderBy:'device' | slice:(5*(currentGPUPage-1)):(5*currentGPUPage) track by pgpu.id")
td.oneliner {{pgpu.device}}
.center(ng-if = '(host.$PGPUs | resolve).length > 5')
pagination(boundary-links="true", total-items="(host.$PGPUs | resolve).length", ng-model="$parent.currentGPUPage", items-per-page="5", max-size="5", class="pagination-sm", previous-text="<", next-text=">", first-text="<<", last-text=">>")

View File

@@ -1,28 +0,0 @@
angular = require 'angular'
#=====================================================================
module.exports = angular.module 'xoWebApp.isoDevice', []
.directive 'isoDevice', -> {
restrict: 'E'
template: require './view'
scope: {
isos: '='
vm: '='
}
controller: 'IsoDevice as isoDevice'
bindToController: true
}
.controller 'IsoDevice', (xo) ->
this.eject = (VM) ->
xo.vm.ejectCd VM.id
this.insert = (VM, disc_id) ->
xo.vm.insertCd VM.id, disc_id, true
return
# A module exports its name.
.name

View File

@@ -1,15 +0,0 @@
.form-inline
.form-group
.input-group
select.form-control(
ng-model = 'isoDevice.isos.mounted'
ng-change = 'isoDevice.insert(isoDevice.vm, isoDevice.isos.mounted)'
ng-options = 'iso.iso.id as iso.label group by iso.sr for iso in isoDevice.isos.opts'
)
option(value = '', disabled) -- CD Drive (empty) --
.input-group-btn
button.btn.btn-default(
ng-click = 'isoDevice.eject(isoDevice.vm)'
ng-disabled = '!isoDevice.isos.mounted'
)
i.fa.fa-eject

View File

@@ -1,33 +0,0 @@
import angular from 'angular'
import uiRouter from 'angular-ui-router'
import xoApi from 'xo-api'
import view from './view'
// ===================================================================
export default angular.module('xoWebApp.list', [
uiRouter,
xoApi
])
.config(function ($stateProvider) {
$stateProvider.state('list', {
url: '/list',
controller: 'ListCtrl as list',
template: view
})
})
.controller('ListCtrl', function (xoApi) {
this.hosts = xoApi.getView('host')
this.pools = xoApi.getView('pool')
this.SRs = xoApi.getView('SR')
this.VMs = xoApi.getView('VM')
this.hostsByPool = xoApi.getIndex('hostsByPool')
this.runningHostsByPool = xoApi.getIndex('runningHostsByPool')
this.vmsByContainer = xoApi.getIndex('vmsByContainer')
})
// A module exports its name.
.name

View File

@@ -1,164 +0,0 @@
//- TODO: print a message when no entries.
//- If it's a (named) pool.
.grid.flat-object(ng-repeat="pool in list.pools.all | xoHideUnauthorized | filter:listFilter | orderBy:natural('name_label') track by pool.id", ng-if="pool.name_label", xo-sref="pools_view({id: pool.id})")
//- Icon.
.grid-cell.flat-cell.flat-cell-type
i.xo-icon-pool
//- Properties & tags.
.grid-cell
//- Properties.
.grid
.grid-cell
.grid
.grid-cell.flat-cell.flat-cell-name
| {{pool.name_label}}
.grid-cell.flat-cell.flat-cell-description
i {{pool.name_description}}
.grid-cell.flat-cell(ng-init="default_SR = (pool.default_SR | resolve)")
div(ng-if="default_SR")
| Default SR:
a(ui-sref="SRs_view({id: default_SR.id})") {{default_SR.name_label}}
div(ng-if="!default_SR")
em No default SR.
.grid-cell.flat-cell(ng-init="master = (pool.master | resolve)")
div(ng-if="master")
| Master:
a(ui-sref="hosts_view({id: master.id})") {{master.name_label}}
div(ng-if="!master")
em Unknown master.
.grid-cell.flat-cell
div(ng-if="pool.HA_enabled")
| HA enabled
div(ng-if="!pool.HA_enabled")
| HA disabled
.grid-cell.flat-cell
| {{list.runningHostsByPool[pool.id] | count}}/{{list.hostsByPool[pool.id] | count}} hosts
//- /Properties.
//- Tags.
.grid
.grid-cell
.grid-cell.flat-cell-tag
i.fa.fa-tag
span(ng-repeat="tag in pool.tags")
span.label.label-primary {{tag}}
//- /Tags.
//- /Properties & tags.
//- /Pool.
//- If it's a host.
.grid.flat-object(ng-repeat="host in list.hosts.all | xoHideUnauthorized | filter:listFilter | orderBy:natural('name_label') track by host.id", xo-sref="hosts_view({id: host.id})")
//- Icon.
.grid-cell.flat-cell.flat-cell-type
i.xo-icon-host(class="xo-color-{{host.power_state | lowercase}}")
//- Properties & tags.
.grid-cell
//- Properties.
.grid
.grid-cell
.grid
.grid-cell.flat-cell.flat-cell-name
| {{host.name_label}}
.grid-cell.flat-cell.flat-cell-description
i {{host.name_description}}
.grid-cell.flat-cell
| Address: {{host.address}}
//- .grid-cell.flat-cell
//- | {{host.$vCPUs}} vCPUs used on {{host.CPUs["cpu_count"]}} cores
.grid-cell.flat-cell
.progress-condensed
.progress-bar(role="progressbar", aria-valuemin="0", aria-valuenow="{{100*host.memory.usage/host.memory.size}}", aria-valuemax="100", style="width: {{[host.memory.usage, host.memory.size] | percentage}}", tooltip="RAM: {{[host.memory.usage, host.memory.size] | percentage}} allocated")
| {{[host.memory.usage, host.memory.size] | percentage}}
.grid-cell.flat-cell
| {{list.vmsByContainer[host.id] | count}} VMs running
//- /Properties.
//- Tags.
.grid
.grid-cell
.grid-cell.flat-cell-tag
i.fa.fa-tag
span(ng-repeat="tag in host.tags")
span.label.label-primary {{tag}}
//- /Tags.
//- /Properties & tags.
//- /Host.
//- If it's a VM.
.grid.flat-object(ng-repeat="VM in list.VMs.all | xoHideUnauthorized | filter:listFilter | orderBy:natural('name_label') track by VM.id", xo-sref="VMs_view({id: VM.id})")
//- Icon.
.grid-cell.flat-cell.flat-cell-type
i.xo-icon-vm(class="xo-color-{{VM.power_state | lowercase}}")
//- Properties & tags.
.grid-cell
//- Properties.
.grid
.grid-cell
.grid
.grid-cell.flat-cell.flat-cell-name
| {{VM.name_label}}
.grid-cell.flat-cell.flat-cell-description
i {{VM.name_description}}
.grid-cell.flat-cell
| Address: {{VM.addresses["0/ip"]}}
.grid-cell.flat-cell
| {{VM.CPUs.number}} vCPUs
.grid-cell.flat-cell
| {{VM.memory.size | bytesToSize}} RAM
.grid-cell.flat-cell(ng-init="container = (VM.$container | resolve)")
div(ng-if="'pool' === container.type")
| Resident on:&nbsp;
a(ui-sref="pools_view({id: container.id})") {{container.name_label}}
div(ng-if="'host' === container.type", ng-init="pool = (container.$poolId | resolve)")
| Resident on:&nbsp;
a(ui-sref="hosts_view({id: container.id})") {{container.name_label}}
small(ng-if="pool.name_label")
| (
a(ui-sref="pools_view({id: pool.id})") {{pool.name_label}}
| )
//- /Properties.
//- Tags.
.grid
.grid-cell
.grid-cell.flat-cell-tag
i.fa.fa-tag
span(ng-repeat="tag in VM.tags")
span.label.label-primary {{tag}}
//- /Tags.
//- /Properties & tags.
//- /VM.
//- If it's a SR.
.grid.flat-object(ng-repeat="SR in list.SRs.all | xoHideUnauthorized | filter:listFilter | orderBy:natural('name_label') track by SR.id", xo-sref="SRs_view({id: SR.id})")
//- Icon.
.grid-cell.flat-cell.flat-cell-type
i.xo-icon-sr
//- Properties & tags.
.grid-cell
//- Properties.
.grid
.grid-cell
.grid
.grid-cell.flat-cell.flat-cell-name
| {{SR.name_label}}
.grid-cell.flat-cell.flat-cell-description
i {{SR.name_description}}
.grid-cell.flat-cell
| Usage: {{[SR.usage, SR.size] | percentage}} ({{SR.usage | bytesToSize}}/{{SR.size | bytesToSize}})
.grid-cell.flat-cell
| Type: {{SR.SR_type}}
.grid-cell.flat-cell(ng-init="container = (SR.$container | resolve)")
div(ng-if="'pool' === container.type")
strong
| Shared on
a(ui-sref="pools_view({id: container.id})") {{container.name_label}}
div(ng-if="'host' === container.type")
| Connected to&nbsp;
a(ui-sref="hosts_view({id: container.id})") {{container.name_label}}
//- /Properties.
//- Tags.
.grid
.grid-cell
.grid-cell.flat-cell-tag
i.fa.fa-tag
span(ng-repeat="tag in SR.tags")
span.label.label-primary {{tag}}
//- /Tags.
//- /Properties & tags.
//- /SR.

View File

@@ -1,65 +0,0 @@
import angular from 'angular'
import uiRouter from 'angular-ui-router'
import view from './view'
// ===================================================================
export default angular.module('xoWebApp.login', [
uiRouter
])
.config(function ($stateProvider) {
$stateProvider.state('login', {
url: '/login',
controller: 'LoginCtrl',
template: view
})
})
.controller('LoginCtrl', function ($scope, $state, $rootScope, xoApi, notify) {
const {toState, toStateParams} = (function (login) {
if (login) {
delete $rootScope._login
return {
toState: login.state.name,
toStateParams: login.stateParams
}
}
return { toState: 'index' }
})($rootScope._login)
$scope.$watch(() => xoApi.user, function (user) {
// When the user is logged in, go the wanted view, fallbacks on
// the index view if necessary.
if (user) {
$state.go(toState, toStateParams).catch(function () {
$state.go('index')
})
}
})
Object.defineProperties($scope, {
user: {
get () {
return xoApi.user
}
},
status: {
get () {
return xoApi.status
}
}
})
$scope.logIn = (...args) => {
xoApi.logIn(...args).catch(error => {
notify.warning({
title: 'Authentication failed',
message: error.message
})
})
}
})
// A module exports its name.
.name

View File

@@ -1,54 +0,0 @@
//- Hide the navbar for this view.
style.
.navbar {
display: none;
}
div.container
div.row-login
div.page-header
img(src = 'images/logo_small.png')
h2 Xen Orchestra
form.form-horizontal(
ng-submit = '$broadcast("fixAutofill"); logIn(email, password, true)'
)
fieldset
legend.login: h3 Sign in
div.form-group
div.col-sm-12
.input-group
span.input-group-addon: i.fa.fa-user.fa-fw
input.form-control.input-sm(
name = 'email'
type = 'text'
placeholder = 'Username'
ng-model = 'email'
required
fix-autofill
)
div.form-group
div.col-sm-12
.input-group
span.input-group-addon: i.fa.fa-key.fa-fw
input.form-control.input-sm(
name = 'password'
type = 'password'
placeholder = 'Password'
ng-model = 'password'
required
fix-autofill
)
div.form-group
div.col-sm-12
button.btn.btn-login.btn-block.btn-success(
id = 'login'
name = 'login'
)
i.fa.fa-sign-in
| Login
p.status(ng-if = '"disconnected" === status')
i.xo-icon-error.fa-2x(tooltip = 'You are not connected to XO-Server')
p.status(ng-if = '"connecting" === status')
i.fa.fa-refresh.fa-spin.fa-2x(tooltip = 'Connecting to XO-Server')
p.status(ng-if = '"connected" === status')
i.xo-icon-success.fa-2x(tooltip = 'You are connected to XO-Server')

View File

@@ -1,52 +0,0 @@
import angular from 'angular'
import uiRouter from 'angular-ui-router'
import updater from '../updater'
import xoServices from 'xo-services'
import view from './view'
// ===================================================================
export default angular.module('xoWebApp.navbar', [
uiRouter,
updater,
xoServices
])
.controller('NavbarCtrl', function ($state, xoApi, xo, $scope, updater) {
this.updater = updater
// TODO: It would make sense to inject xoApi in the scope.
Object.defineProperties(this, {
status: {
get: () => xoApi.status
},
user: {
get: () => xoApi.user
}
})
this.logIn = xoApi.logIn
this.logOut = function () {
xoApi.logOut()
$state.go('login')
}
// When a searched is entered, we must switch to the list view if
// necessary.
this.ensureListView = function () {
$state.go('list')
}
this.tasks = xoApi.getView('runningTasks')
})
.directive('navbar', function () {
return {
restrict: 'E',
controller: 'NavbarCtrl as navbar',
template: view,
scope: {}
}
})
// A module exports its name.
.name

View File

@@ -1,132 +0,0 @@
nav.navbar.navbar-inverse.navbar-fixed-top(role = 'navigation')
//- Brand and toggle get grouped for better mobile display
.navbar-header
//- Button used to (un)collapse on mobile display.
button.navbar-toggle(type="button", ng-init="collapsed = true", ng-click="collapsed = !collapsed")
span.sr-only Toggle navigation
span.icon-bar
span.icon-bar
span.icon-bar
//- Brand name.
a.navbar-brand(ui-sref = 'index')
img.navbar-logo(src="images/logo.png")
| Xen Orchestra
//- All navbar items are collapsed on mobile display.
.collapse.navbar-collapse(ng-class="!collapsed && 'in'")
//- Search form of the navbar.
form.navbar-form.navbar-left(role="search", style="width: 250px")
//- Forced width due to issue with `input`s (https://github.com/twbs/bootstrap/issues/9950.
.input-group
input.form-control.inverse(
type = 'text'
placeholder = ''
ng-model = '$root.listFilter'
ng-change = 'navbar.ensureListView()'
)
span.input-group-btn
button.btn.btn-search(
type = 'button'
ng-click = 'navbar.ensureListView()'
)
i.fa.fa-search
//- /Search form.
ul.nav.navbar-nav
li
a(href="https://xen-orchestra.com/#/pricing?pk_campaign=xoa_source", target="_blank", tooltip="Source version without Pro support. Use in production at your own risk.")
i.xo-icon-info.text-danger
span.hidden-sm No Pro Support!
//- Right items of the navbar.
ul.nav.navbar-nav.navbar-right
li.navbar-text(ng-if="'disconnected' === navbar.status")
i.xo-icon-error
| Disconnected from XO-Server
li.navbar-text(ng-if="'connecting' === navbar.status")
i.fa.fa-refresh.fa-spin
| Connecting to XO-Server
//- Running tasks
li.disabled(ng-if="!navbar.tasks.size", tooltip="No running tasks")
a.dropdown-toggle.inverse
i.xo-icon-task
li.dropdown(dropdown, ng-if="navbar.tasks.size")
a.dropdown-toggle.inverse(dropdown-toggle)
i.xo-icon-task
ul.dropdown-menu.inverse
li.task-menu(
ng-repeat="task in navbar.tasks.all | orderBy:natural('name_label') track by task.id"
)
a(
ui-sref="hosts_view({id: task.$host})"
tooltip = "{{task.name_label}}"
)
//- i.fa.fa-spinner.fa-fw
//- | {{task.name_label}}
.progress-condensed
.progress-bar.progress-bar-success.progress-bar-striped.active.progress-bar-black(
role = "progressbar"
aria-valuemin = "0"
aria-valuenow = "{{task.progress*100}}"
aria-valuemax = "100"
style = "width: {{task.progress*100}}%"
)
| {{task.progress*100 | number:1}}%
//- Main menu.
li.dropdown(dropdown)
a.dropdown-toggle.inverse(dropdown-toggle)
i.fa.fa-th
ul.dropdown-menu.inverse
li(
ui-sref-active = 'active'
ng-class = '{ disabled: navbar.user.permission !== "admin" }'
)
a(ui-sref = 'tree')
i.fa.fa-indent
| Tree view
li(ui-sref-active="active")
a(ui-sref="list")
i.fa.fa-align-justify
| Flat view
//- li.disabled(ui-sref-active="active")
//- a(ui-sref="graph")
//- i.fa.fa-sitemap
//- | Graphs view
li.divider
//- li.disabled
//- a
//- i.fa.fa-clock-o
//- | Scheduler
li(
ui-sref-active = 'active'
ng-class = '{ disabled: navbar.user.permission !== "admin" }'
)
a(ui-sref="settings.index")
i.fa.fa-cog
| Settings
li.divider
li(ui-sref-active="active")
a(ui-sref="about")
i.fa.fa-info-circle(style="color:#5bc0de")
| About
//- /Main menu.
li
a(ui-sref="settings.update")
i.fa.fa-question-circle.text-warning(ng-if = '!navbar.updater.state', tooltip = 'No update information available')
i.fa.fa-question-circle.text-info(ng-if = 'navbar.updater.state == "connected"', tooltip = 'Update information may be available')
i.fa.fa-check.text-success(ng-if = 'navbar.updater.state == "upToDate"', tooltip = 'Your XOA is up-to-date')
i.fa.fa-bell.text-primary(ng-if = 'navbar.updater.state == "upgradeNeeded"', tooltip = 'You need to update your XOA (new version is available)')
i.fa.fa-bell-slash.text-warning(ng-if = 'navbar.updater.state == "registerNeeded"', tooltip = 'Your XOA is not registered for updates')
i.fa.fa-exclamation-triangle.text-danger(ng-if = 'navbar.updater.state == "error"', tooltip = 'Can\'t fetch update information')
li
a(ui-sref="settings.users", tooltip="{{navbar.user.email}}")
i.fa.fa-user
span.hidden-sm {{navbar.user.email}}
li
a(ng-click = 'navbar.logOut()')
i.fa.fa-sign-out
| &nbsp;
| &nbsp;
//- /Right items.
//- /Navbar items.
//- /Navbar.

View File

@@ -1,435 +0,0 @@
import angular from 'angular'
import Bluebird from 'bluebird'
import forEach from 'lodash.foreach'
import uiRouter from 'angular-ui-router'
import view from './view'
import _indexOf from 'lodash.indexof'
// ===================================================================
export default angular.module('xoWebApp.newSr', [
uiRouter
])
.config(function ($stateProvider) {
$stateProvider.state('SRs_new', {
url: '/srs/new/:container',
controller: 'NewSrCtrl as newSr',
template: view
})
})
.controller('NewSrCtrl', function ($scope, $state, $stateParams, xo, xoApi, notify, modal, bytesToSizeFilter) {
this.reset = function (data = {}) {
this.data = {}
delete this.lockCreation
this.lock = !(
(data.srType === 'Local') &&
(data.srPath && data.srPath.path)
)
}
this.resetLists = function () {
delete this.data.nfsList
delete this.data.scsiList
delete this.lockCreation
this.lock = true
this.resetErrors()
}
this.resetErrors = function () {
delete this.data.error
}
/*
* Loads NFS paths and iScsi iqn`s
*/
this.populateSettings = function (type, server, auth, user, password) {
this.reset()
this.loading = true
server = this._parseAddress(server)
if (type === 'NFS' || type === 'NFS_ISO') {
xoApi.call('sr.probeNfs', {
host: this.container.id,
server: server.host
})
.then(response => this.data.paths = response)
.catch(error => notify.warning({
title: 'NFS Detection',
message: error.message
}))
.finally(() => this.loading = false)
} else if (type === 'iSCSI') {
let params = {
host: this.container.id
}
if (auth) {
params.chapUser = user
params.chapPassword = password
}
params.target = server.host
if (server.port) {
params.port = server.port
}
xoApi.call('sr.probeIscsiIqns', params)
.then(response => {
if (response.length > 0) {
this.data.iqns = response
} else {
notify.warning({
title: 'iSCSI Detection',
message: 'No IQNs found'
})
}
})
.catch(error => notify.warning({
title: 'iSCSI Detection',
message: error.message
}))
.finally(() => this.loading = false)
} else {
this.loading = false
}
}
/*
* Loads iScsi LUNs
*/
this.populateIScsiIds = function (iqn, auth, user, password) {
delete this.data.iScsiIds
this.loading = true
let params = {
host: this.container.id,
target: iqn.ip,
targetIqn: iqn.iqn
}
if (auth) {
params.chapUser = user
params.chapPassword = password
}
xoApi.call('sr.probeIscsiLuns', params)
.then(response => {
forEach(response, item => {
item.display = 'LUN ' + item.id + ': ' +
item.serial + ' ' + bytesToSizeFilter(item.size) +
' (' + item.vendor + ')'
})
this.data.iScsiIds = response
})
.catch(error => notify.warning({
title: 'LUNs Detection',
message: error.message
}))
.finally(() => this.loading = false)
}
this._parseAddress = function (address) {
let index = address.indexOf(':')
let port = false
let host = address
if (index > -1) {
port = address.substring(index + 1)
host = address.substring(0, index)
}
return {
host,
port
}
}
this._prepareNfsParams = function (data) {
let server = this._parseAddress(data.srServer)
let params = {
host: this.container.id,
nameLabel: data.srName,
nameDescription: data.srDesc,
server: server.host,
serverPath: data.srPath.path
}
return params
}
this._prepareScsiParams = function (data) {
let params = {
host: this.container.id,
nameLabel: data.srName,
nameDescription: data.srDesc,
target: data.srIqn.ip,
targetIqn: data.srIqn.iqn,
scsiId: data.srIScsiId.scsiId
}
let server = this._parseAddress(data.srServer)
if (server.port) {
params.port = server.port
}
if (data.srAuth) {
params.chapUser = data.srChapUser
params.chapPassword = data.srChapPassword
}
return params
}
this.createSR = function (data) {
this.lock = true
this.creating = true
let operationToPromise
switch (data.srType) {
case 'NFS':
let nfsParams = this._prepareNfsParams(data)
operationToPromise = this._checkNfsExistence(nfsParams)
.then(() => xoApi.call('sr.createNfs', nfsParams))
break
case 'iSCSI':
let scsiParams = this._prepareScsiParams(data)
operationToPromise = this._checkScsiExistence(scsiParams)
.then(() => xoApi.call('sr.createIscsi', scsiParams))
break
case 'lvm':
let device = data.srDevice.device
operationToPromise = xoApi.call('sr.createLvm', {
host: this.container.id,
nameLabel: data.srName,
nameDescription: data.srDesc,
device
})
break
case 'NFS_ISO':
case 'Local':
let server = this._parseAddress(data.srServer || '')
let path = (
data.srType === 'NFS_ISO' ?
server.host + ':' :
''
) + data.srPath.path
operationToPromise = xoApi.call('sr.createIso', {
host: this.container.id,
nameLabel: data.srName,
nameDescription: data.srDesc,
path
})
break
default:
operationToPromise = Bluebird.reject({message: 'Unhanled SR Type'})
break
}
operationToPromise
.then(id => {
$state.go('SRs_view', {id})
})
.catch(error => {
notify.error({
title: 'Storage Creation Error',
message: error.message
})
})
.finally(() => {
this.lock = false
this.creating = false
})
}
this._checkScsiExistence = function (params) {
this.resetLists()
return xoApi.call('sr.probeIscsiExists', params)
.then(response => {
if (response.length > 0) {
this.data.scsiList = response
return modal.confirm({
title: 'Previous LUN Usage',
message: 'This LUN has been previously used as a Storage by a XenServer host. All data will be lost if you choose to continue the SR creation. Are you sure?'
})
}
return true
})
}
this._checkNfsExistence = function (params) {
this.resetLists()
return xoApi.call('sr.probeNfsExists', params)
.then(response => {
if (response.length > 0) {
this.data.nfsList = response
return modal.confirm({
title: 'Previous Path Usage',
message: 'This path has been previously used as a Storage by a XenServer host. All data will be lost if you choose to continue the SR creation. Are you sure?'
})
}
return true
})
}
const hostsByPool = xoApi.getIndex('hostsByPool')
const srsByContainer = xoApi.getIndex('srsByContainer')
this._gatherConnectedUuids = function () {
const srIds = []
// Shared SRs.
forEach(srsByContainer[this.container.$poolId], sr => {
srIds.push(sr.id)
})
// Local SRs.
forEach(hostsByPool[this.container.$poolId], host => {
forEach(srsByContainer[host.id], sr => {
srIds.push(sr.id)
})
})
return srIds
}
this._processSRList = function (list) {
let inUse = false
let SRs = this._gatherConnectedUuids()
forEach(list, item => {
inUse = (item.used = _indexOf(SRs, item.uuid) > -1) || inUse
})
this.lockCreation = inUse
return list
}
this.loadScsiList = function (data) {
this.resetLists()
this.loading = true
let params = this._prepareScsiParams(data)
xoApi.call('sr.probeIscsiExists', params)
.then(response => {
if (response.length > 0) {
this.data.scsiList = this._processSRList(response)
}
this.lock = !Boolean(data.srIScsiId)
})
.catch(error => {
notify.error({
title: 'iSCSI Error',
message: error.message
})
})
.finally(() => this.loading = false)
}
this.loadNfsList = function (data) {
this.resetLists()
let server = this._parseAddress(data.srServer)
xoApi.call('sr.probeNfsExists', {
host: this.container.id,
server: server.host,
serverPath: data.srPath.path
})
.then(response => {
if (response.length > 0) {
this.data.scsiList = this._processSRList(response)
}
this.lock = !Boolean(data.srPath.path)
})
.catch(error => {
notify.error({
title: 'NFS error',
message: error.message
})
})
}
this.reattachNfs = function (uuid, {name, nameError}, {desc, descError}, iso) {
this._reattach(uuid, 'nfs', {name, nameError}, {desc, descError}, iso)
}
this.reattachIScsi = function (uuid, {name, nameError}, {desc, descError}) {
this._reattach(uuid, 'iscsi', {name, nameError}, {desc, descError})
}
this._reattach = function (uuid, type, {name, nameError}, {desc, descError}, iso = false) {
this.resetErrors()
let method = 'sr.reattach' + (iso ? 'Iso' : '')
if (nameError || descError) {
this.data.error = {
name: nameError,
desc: descError
}
notify.warning({
title: 'Missing parameters',
message: 'Complete the General section information, please'
})
} else {
this.lock = true
this.attaching = true
xoApi.call(method, {
host: this.container.id,
uuid,
nameLabel: name,
nameDescription: desc,
type
})
.then(id => {
$state.go('SRs_view', {id})
})
.catch(error => notify.error({
title: 'reattach',
message: error.message
})
)
.finally(() => {
this.lock = false
this.attaching = false
})
}
}
this.reset()
$scope.$watch(() => xoApi.get($stateParams.container), container => {
this.container = container
})
})
// A module exports its name.
.name

View File

@@ -1,183 +0,0 @@
.grid
.panel.panel-default
p.page-title
i.xo-icon-sr
| Add SR on&nbsp;
a(ng-if="'pool' === newSr.container.type", ui-sref="pools_view({id: newSr.container.id})")
| {{newSr.container.name_label}}
a(ng-if="'host' === newSr.container.type", ui-sref="hosts_view({id: newSr.container.id})")
| {{newSr.container.name_label}}
form.form-horizontal(name = 'srForm' ng-submit="newSr.createSR(formData)")
.grid
//- Choose SR type panel
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-info-circle(style="color: #e25440;")
| General
.panel-body
.form-group
label.col-sm-3.control-label Type
.col-sm-9
select.form-control(ng-change = 'newSr.reset(formData)', ng-model = 'formData.srType', name = 'srType', ng-required = 'true')
option(value="") -- Choose a type of SR --
optgroup(label="VDI SR")
option(value="NFS") NFS
option(value="iSCSI") iSCSI
option(value="lvm") Local LVM
optgroup(label="ISO SR")
option(value="Local") Local
option(value="NFS_ISO") NFS ISO
.form-group(ng-class = '{"has-error": newSr.data.error.name}')
label.col-sm-3.control-label Name
.col-sm-9
input.form-control(type="text", placeholder="", name = 'srName', ng-model = 'formData.srName', ng-required = 'true')
.form-group(ng-class = '{"has-error": newSr.data.error.desc}')
label.col-sm-3.control-label Description
.col-sm-9
input.form-control(type="text", placeholder="SR Created by Xen Orchestra", name = 'srDesc', ng-model = 'formData.srDesc', ng-required = 'true')
//- Choose SR details
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-cogs(style="color: #e25440;")
| Settings
.panel-body
.form-group(ng-if = 'formData.srType === "NFS" || formData.srType === "iSCSI" || formData.srType === "NFS_ISO"')
label.col-sm-3.control-label
| Server
span(ng-if = 'formData.srType === "iSCSI"')
| &nbsp;(auth&nbsp;
input(type = 'checkbox', ng-model = 'formData.srAuth')
| &nbsp;)
.col-sm-9
.input-group
input.form-control(type="text", placeholder='address{{ formData.srType === "iSCSI" ? "[:port]" : "" }}', name = 'srServer', ng-model = 'formData.srServer', required)
span.input-group-btn
button.btn.btn-default(type = 'button', ng-click = 'newSr.populateSettings(formData.srType, formData.srServer, formData.srAuth, formData.srChapUser, formData.srChapPassword)')
i.fa.fa-search
//- For Local LVM
.form-group(ng-if = 'formData.srType === "lvm"')
label.col-sm-3.control-label Device
.col-sm-9
input.form-control(
ng-if = 'formData.srType === "lvm"'
type = 'text'
name = 'srDevice'
ng-model = 'formData.srDevice.device'
placeholder = 'Device, e.g /dev/sda...'
ng-change = 'newSr.lock = !formData.srDevice.device'
required
)
.form-group(ng-if = 'newSr.data.paths || formData.srType === "Local"')
label.col-sm-3.control-label Path
.col-sm-9
//- For NFS
select.form-control(
ng-if = 'newSr.data.paths'
name = 'srPath'
ng-change = 'newSr.loadNfsList(formData)'
ng-model = 'formData.srPath'
ng-options = 'item.path for item in newSr.data.paths', required)
option(value = '', disabled) -- Choose path --
//- For Local
input.form-control(
ng-if = 'formData.srType === "Local"'
type = 'text'
name = 'srPath'
ng-model = 'formData.srPath.path'
ng-change = 'newSr.lock = !formData.srPath.path'
required
)
//- For iScsi
.form-group(ng-if = 'formData.srType === "iSCSI"')
.col-sm-9.col-sm-offset-3.form-inline(ng-if = 'formData.srAuth')
label.sr-only(for = 'chapUser') User
input#chapUser.form-control(type = 'text', ng-model = 'formData.srChapUser', placeholder = 'user', ng-required = 'formData.srAuth')
| &ensp;
label.sr-only(for = 'chapUser') Password
input#chapPassword.form-control(type = 'password', ng-model = 'formData.srChapPassword', placeholder = 'password', ng-required = 'formData.srAuth')
.form-group(ng-if = 'newSr.data.iqns')
label.col-sm-3.control-label IQN
.col-sm-9
select.form-control(ng-change = 'newSr.populateIScsiIds(formData.srIqn, formData.srAuth, formData.srChapUser, formData.srChapPassword)', name = 'srIqn', ng-model = 'formData.srIqn', ng-options = '(item.iqn + " (" + item.ip + ")") for item in newSr.data.iqns', required)
option(value = '', disabled) -- Choose IQN --
.form-group(ng-if = 'newSr.data.iScsiIds')
label.col-sm-3.control-label LUN
.col-sm-9
select.form-control(name = 'srIScsiId', ng-change = 'newSr.loadScsiList(formData)', ng-model = 'formData.srIScsiId', ng-options = 'item.display for item in newSr.data.iScsiIds', required)
option(value = '', disabled) -- Choose LUN --
.form-group.text-center(ng-if = 'newSr.loading')
i.fa.fa-circle-o-notch.fa-spin.fa-2x
.grid(ng-if = 'newSr.data.nfsList && newSr.data.nfsList.length > 0')
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-eye(style="color: #e25440;")
| NFS storage use
.panel-body
table.table.table-condensed
tr
th.text-center Storage UUID
th
tr(ng-repeat = 'nfsSr in newSr.data.nfsList')
td.text-center {{ nfsSr.uuid }}
td.text-center(ng_if = '!nfsSr.used')
button.btn.btn-sm.btn-primary(type = 'button', ng-class = '{disabled: newSr.lock}', ng-click = 'newSr.reattachNfs(nfsSr.uuid, {name: formData.srName, nameError: srForm.srName.$error.required}, {desc: formData.srDesc, descError: srForm.srDesc.$error.required}, "NFS_ISO" === formData.srType)') Reattach
td.text-center(ng_if = 'nfsSr.used', ng-class = '{disabled: newSr.lock}')
button.btn.btn-sm.btn-danger(ui-sref = 'SRs_view({id: nfsSr.uuid})', ng-class = '{disabled: newSr.lock}')
i.fa.fa-eye
| In use
p.text-center(ng-if = 'newSr.attaching')
i.fa.fa-circle-o-notch.fa-spin.fa-2x
.grid(ng-if = 'newSr.data.scsiList && newSr.data.scsiList.length > 0')
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-eye(style="color: #e25440;")
| iSCSI storage use
.panel-body
table.table.table-condensed
tr
th.text-center Storage UUID
th
tr(ng-repeat = 'scsiSr in newSr.data.scsiList')
td.text-center {{ scsiSr.uuid }}
td.text-center(ng_if = '!scsiSr.used')
button.btn.btn-sm.btn-primary(type = 'button', ng-class = '{disabled: newSr.lock}', ng-click = 'newSr.reattachIScsi(scsiSr.uuid, {name: formData.srName, nameError: srForm.srName.$error.required}, {desc: formData.srDesc, descError: srForm.srDesc.$error.required})') Reattach
td.text-center(ng_if = 'scsiSr.used')
button.btn.btn-sm.btn-danger(ui-sref = 'SRs_view({id: scsiSr.uuid})', ng-class = '{disabled: newSr.lock}')
i.fa.fa-eye
| In use
p.text-center(ng-if = 'newSr.attaching')
i.fa.fa-circle-o-notch.fa-spin.fa-2x
//- Summary
.grid
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-flag-checkered(style="color: #e25440;")
| Summary
.panel-body
.grid
.grid-cell
p.stat-name
| Name:
p.center.big {{formData.srName}}
.grid-cell
p.stat-name
| Type:
p.center.big {{formData.srType}}
.grid-cell
div(ng-if = 'formData.srType === "iSCSI"')
p.stat-name Size
p.center.big {{formData.srIScsiId.size | bytesToSize}}
div(ng-if = 'formData.srType === "NFS"')
p.stat-name Path
p.center.big {{formData.srPath.path}}
p.center
button.btn.btn-lg.btn-primary(type="submit", ng-disabled = 'newSr.lock || newSr.lockCreation')
i.fa.fa-play
| &nbsp;Create SR&nbsp;
i.fa.fa-circle-o-notch.fa-spin(ng-if = 'newSr.creating')

View File

@@ -1,264 +0,0 @@
angular = require 'angular'
cloneDeep = require 'lodash.clonedeep'
forEach = require 'lodash.foreach'
#=====================================================================
module.exports = angular.module 'xoWebApp.newVm', [
require 'angular-ui-router'
]
.config ($stateProvider) ->
$stateProvider.state 'VMs_new',
url: '/vms/new/:container'
controller: 'NewVmsCtrl'
template: require './view'
.controller 'NewVmsCtrl', (
$scope, $stateParams, $state
xoApi, xo
bytesToSizeFilter, sizeToBytesFilter
notify
) ->
{get} = xoApi
removeItems = do ->
splice = Array::splice.call.bind Array::splice
(array, index, n) -> splice array, index, n ? 1
merge = do ->
push = Array::push.apply.bind Array::push
(args...) ->
result = []
for arg in args
push result, arg if arg?
result
pool = default_SR = null
do (
networks = xoApi.getIndex('networksByPool')
) ->
Object.defineProperties($scope, {
networks: {
get: () => pool && networks[pool.id]
}
})
srsByContainer = xoApi.getIndex('srsByContainer')
vmTemplatesByContainer = xoApi.getIndex('vmTemplatesByContainer')
$scope.$watch(
-> get $stateParams.container
(container) ->
$scope.container = container
# If the container was not found, no need to continue.
return unless container?
if container.type is 'host'
host = container
pool = (get container.$poolId) ? {}
else
host = {}
pool = container
default_SR = get pool.default_SR
default_SR = if default_SR
default_SR.id
else
''
# Computes the list of templates.
templates = $scope.templates = []
forEach(vmTemplatesByContainer[host.id], (template) =>
templates.push(template)
return
)
forEach(vmTemplatesByContainer[pool.id], (template) =>
templates.push(template)
return
)
# Computes the list of srs.
SRs = []
forEach(srsByContainer[host.id], (template) =>
SRs.push(template)
return
)
forEach(srsByContainer[pool.id], (template) =>
SRs.push(template)
return
)
# Computes the list of ISO SRs.
$scope.ISO_SRs = (SR for SR in SRs when SR.content_type is 'iso')
# Computes the list of writable SRs.
$scope.writable_SRs = (SR for SR in SRs when SR.content_type isnt 'iso')
)
$scope.availableMethods = {}
$scope.CPUs = ''
$scope.installation_cdrom = ''
$scope.installation_method = ''
$scope.installation_network = ''
$scope.memory = ''
$scope.name_description = ''
$scope.name_label = ''
$scope.template = ''
$scope.VDIs = []
$scope.VIFs = []
$scope.isDiskTemplate = false
$scope.addVIF = do ->
id = 0
->
$scope.VIFs.push {
id: id++
network: ''
}
$scope.addVIF()
$scope.removeVIF = (index) -> removeItems $scope.VIFs, index
$scope.moveVDI = (index, direction) ->
{VDIs} = $scope
newIndex = index + direction
[VDIs[index], VDIs[newIndex]] = [VDIs[newIndex], VDIs[index]]
$scope.removeVDI = (index) -> removeItems $scope.VDIs, index
VDI_id = 0
$scope.addVDI = ->
$scope.VDIs.push {
id: VDI_id++
bootable: false
size: ''
SR: default_SR
type: 'system'
}
# When the selected template changes, updates other variables.
$scope.$watch 'template', (template) ->
return unless template
{install_methods} = template.template_info
availableMethods = $scope.availableMethods = Object.create null
for method in install_methods
availableMethods[method] = true
if install_methods.length is 1 # FIXME: does not work with network.
$scope.installation_method = install_methods[0]
else
delete $scope.installation_method
VDIs = $scope.VDIs = cloneDeep template.template_info.disks
# if the template has no config disk
# nor it's Other install media (specific case)
# then do NOT display disk and network panel
if VDIs.length is 0 and template.name_label isnt 'Other install media'
$scope.isDiskTemplate = true
$scope.VIFs.length = 0
else $scope.isDiskTemplate = false
for VDI in VDIs
VDI.id = VDI_id++
VDI.size = bytesToSizeFilter VDI.size
VDI.SR or= default_SR
$scope.createVM = ->
{
CPUs
installation_cdrom
installation_method
installation_network
memory
name_description
name_label
template
VDIs
VIFs
} = $scope
# Does not edit the displayed data directly.
VDIs = cloneDeep VDIs
for VDI, index in VDIs
# Removes the dummy identifier used for AngularJS.
delete VDI.id
# Adds the device number based on the index.
VDI.device = "#{index}"
# Transforms the size from human readable format to bytes.
VDI.size = sizeToBytesFilter VDI.size
# TODO: handles invalid values.
# Does not edit the displayed data directly.
VIFs = cloneDeep VIFs
for VIF in VIFs
# Removes the dummy identifier used for AngularJS.
delete VIF.id
# Removes the MAC address if empty.
if 'MAC' of VIF
VIF.MAC = VIF.MAC.trim()
delete VIF.MAC unless VIF.MAC
if installation_method is 'cdrom'
installation = {
method: 'cdrom'
repository: installation_cdrom
}
else if installation_network
matches = /^(http|ftp|nfs)/i.exec installation_network
throw new Error 'invalid network URL' unless matches
installation = {
method: matches[1].toLowerCase()
repository: installation_network
}
else
installation = undefined
data = {
installation
name_label
template: template.id
VDIs
VIFs
}
# TODO:
# - disable the form during creation
# - indicate the progress of the operation
notify.info {
title: 'VM creation'
message: 'VM creation started'
}
xoApi.call('vm.create', data).then (id) ->
# If nothing to sets, just stops.
return id unless CPUs or name_description or memory
data = {
id
}
data.CPUs = +CPUs if CPUs
if name_description
data.name_description = name_description
if memory
memory = sizeToBytesFilter memory
# FIXME: handles invalid entries.
data.memory = memory
xoApi.call('vm.set', data).then -> id
.then (id) ->
$state.go 'VMs_view', { id }
.catch (error) ->
notify.error {
title: 'VM creation'
message: 'The creation failed'
}
console.log error
# A module exports its name.
.name

View File

@@ -1,220 +0,0 @@
.grid
.panel.panel-default
p.page-title
i.xo-icon-vm
| Create VM on&nbsp;
a(ng-if="'pool' === container.type", ui-sref="pools_view({id: container.id})")
| {{container.name_label}}
a(ng-if="'host' === container.type", ui-sref="hosts_view({id: container.id})")
| {{container.name_label}}
//- Add server panel
form.form-horizontal(ng-submit="createVM()")
.grid
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-info-circle(style="color: #e25440;")
| VM info
.panel-body
.form-group
label.col-sm-3.control-label Template
.col-sm-9
select.form-control(ng-model="template", ng-options="template.name_label for template in templates | orderBy:natural('name_label') track by template.id", required="")
.form-group
label.col-sm-3.control-label Name
.col-sm-9
input.form-control(type="text", placeholder="Name of your new VM", required="", ng-model="name_label")
.form-group
label.col-sm-3.control-label Description
.col-sm-9
input.form-control(type="text", placeholder="Optional description of you new VM", ng-model="name_description")
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-dashboard(style="color: #e25440;")
| Performances
.panel-body
.form-group
label.col-sm-3.control-label vCPUs
.col-sm-9
input.form-control(type="text", placeholder="{{template.CPUs.number}}", ng-model="CPUs")
.form-group
label.col-sm-3.control-label RAM
.col-sm-9
input.form-control(type="text", placeholder="{{template.memory.size | bytesToSize}}", ng-model="memory")
.grid(ng-if="isDiskTemplate")
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-info-circle(style="color: #e25440;")
| Template info
.panel-body
p.center This template will create automatically a VM with:
.col-md-6
ul(ng-repeat="VIF in template.VIFs | resolve | orderBy:natural('device') track by VIF.id")
li Interface \#{{VIF.device}} (MTU {{VIF.MTU}}) on {{(VIF.$network | resolve).name_label}}
.col-md-6
ul(ng-repeat = 'VBD in (template.$VBDs | resolve) track by VBD.id')
li Disk {{(VBD.VDI | resolve).name_label}} ({{(VBD.VDI | resolve).size | bytesToSize}}) on {{((VBD.VDI | resolve).$SR | resolve).name_label}}
.grid(ng-if="!isDiskTemplate")
//- Install panel
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-download(style="color: #e25440;")
| Install settings
.panel-body
.form-group(ng-show="availableMethods.cdrom")
label.col-sm-3.control-label ISO/DVD
.col-sm-9
.input-group
span.input-group-addon
input(
type = 'radio'
name = 'installation_method'
ng-model = '$parent.installation_method'
value = 'cdrom'
required
)
select.form-control.disabled(
ng-disabled="'cdrom' !== installation_method"
ng-model="$parent.installation_cdrom"
required
)
option(value = '') Please select
optgroup(ng-repeat="SR in ISO_SRs | orderBy:natural('name_label') track by SR.id", ng-if="SR.VDIs.length", label="{{SR.name_label}}")
option(ng-repeat="VDI in SR.VDIs | resolve | orderBy:natural('name_label') track by VDI.id", ng-value="VDI.id")
| {{VDI.name_label}}
.form-group(ng-show="availableMethods.http || availableMethods.ftp || availableMethods.nfs")
label.col-sm-3.control-label Network
.col-sm-9
.input-group
span.input-group-addon
input(
type = 'radio'
name = 'installation_method'
ng-model = '$parent.installation_method'
value = 'network'
required
)
input.form-control(type="text", ng-disabled="'network' !== installation_method", placeholder="e.g: http://ftp.debian.org/debian", ng-model="$parent.installation_network")
//- <div class="form-group"> FIXME
//- <label class="col-sm-3 control-label">Home server</label>
//- <div class="col-sm-9">
//- <select class="form-control">
//- <option>Default (auto)</option>
//- </select>
//- </div>
//- </div>
//- Interface panel
.panel.panel-default
.panel-heading.panel-title
i.xo-icon-network(style="color: #e25440;")
| Interfaces
.panel-body
table.table.table-hover
tr
th MAC
th Network
th.col-md-1 &#160;
//- Buttons
tr(ng-repeat="VIF in VIFs track by VIF.id")
td
input.form-control(type="text", ng-model="VIF.MAC", ng-pattern="/^\s*[0-9a-f]{2}(:[0-9a-f]{2}){5}\s*$/i", placeholder="00:00:00:00:00")
td
select.form-control(
ng-options = 'network.id as network.name_label for network in networks | orderBy:natural("name_label") track by network.id'
ng-model = 'VIF.network'
required
)
option(value = '') Please select
td
.pull-right
button.btn.btn-default(type="button", ng-click="removeVIF($index)", title="Remove this interface")
i.fa.fa-times
.btn-form
p.center
.btn-form
p.center
button.btn.btn-success(type="button", ng-click="addVIF()")
i.fa.fa-plus
| Add interface
//- end of misc and interface panel
//- Disk panel
.grid(ng-if="!isDiskTemplate")
.panel.panel-default
.panel-heading.panel-title
i.xo-icon-sr(style="color: #e25440;")
| Disks
.panel-body
table.table.table-hover
tr
th.col-md-2 SR
th.col-md-1 Bootable?
th.col-md-2 Size
th.col-md-2 Name
th.col-md-4 Description
th.col-md-1 &#160;
//- Buttons
tr(ng-repeat="VDI in VDIs track by VDI.id")
td
select.form-control(ng-model="VDI.SR", ng-options="SR.id as (SR.name_label + ' (' + (SR.size - SR.usage | bytesToSize) + ' free)') for SR in (writable_SRs | orderBy:natural('name_label'))")
td.text-center
input(type="checkbox", ng-model="VDI.bootable")
td
input.form-control(type="text", ng-model="VDI.size", required="")
td
input.form-control(type="text", placeholder="Name of this virtual disk", ng-model="VDI.name_label")
td
input.form-control(type="text", placeholder="Description of this virtual disk", ng-model="VDI.name_description")
td
.btn-group
button.btn.btn-default(type="button", ng-click="moveVDI($index, -1)", ng-disabled="$first", title="Move this disk up")
i.fa.fa-chevron-up
button.btn.btn-default(type="button", ng-click="moveVDI($index, 1)", ng-disabled="$last", title="Move this disk down")
i.fa.fa-chevron-down
.pull-right
button.btn.btn-default(type="button", ng-click="removeVDI($index)", title="Remove this disk")
i.fa.fa-times
.btn-form
p.center
.btn-form
p.center
button.btn.btn-success(type="button", ng-click="addVDI()")
i.fa.fa-plus
| Add disk
//- Confirmation panel
.grid
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-flag-checkered(style="color: #e25440;")
| Summary
.panel-body
.grid
.grid-cell
p.center.big {{name_label}}
| &nbsp;
span.small(ng-if="template.name_label") ({{template.name_label}})
.grid
.grid-cell
//- p.stat-name vCPUs
p.center.big(tooltip="vCPUs")
| {{CPUs || template.CPUs.number || 0}}x&nbsp;
i.xo-icon-cpu
.grid-cell
//- p.stat-name RAM
p.center.big(tooltip="RAM")
| {{(memory) || (template.memory.size | bytesToSize)}}&nbsp;
i.xo-icon-memory
.grid-cell
//- p.stat-name Disks
p.center.big(tooltip="Disks")
| {{(VDIs.length) || (template.$VBDs.length) || 0}}x&nbsp;
i.fa.fa-hdd-o
.grid-cell
//- p.stat-name Interfaces
p.center.big(tooltip="Network interfaces")
| {{(VIFs.length) || (template.VIFs.length) || 0}}x&nbsp;
i.xo-icon-network
p.center
button.btn.btn-lg.btn-primary(type="submit")
i.fa.fa-play
| Create VM

View File

@@ -1,107 +0,0 @@
import angular from 'angular'
import forEach from 'lodash.foreach'
import uiRouter from 'angular-ui-router'
import view from './view'
// ===================================================================
export default angular.module('xoWebApp.pool', [
uiRouter
])
.config(function ($stateProvider) {
$stateProvider.state('pools_view', {
url: '/pools/:id',
controller: 'PoolCtrl',
template: view
})
})
.controller('PoolCtrl', function ($scope, $stateParams, xoApi, xo, modal) {
{
const {id} = $stateParams
const hostsByPool = xoApi.getIndex('hostsByPool')
const runningHostsByPool = xoApi.getIndex('runningHostsByPool')
const srsByContainer = xoApi.getIndex('srsByContainer')
Object.defineProperties($scope, {
hosts: {
get: () => hostsByPool[id]
},
runningHosts: {
get: () => runningHostsByPool[id]
},
srs: {
get: () => srsByContainer[id]
}
})
}
$scope.$watch(() => xoApi.get($stateParams.id), function (pool) {
$scope.pool = pool
})
$scope.currentLogPage = 1
$scope.savePool = function ($data) {
let {pool} = $scope
let {name_label, name_description} = $data
$data = {
id: pool.id
}
if (name_label !== pool.name_label) {
$data.name_label = name_label
}
if (name_description !== pool.name_description) {
$data.name_description = name_description
}
xoApi.call('pool.set', $data)
}
$scope.deleteAllLog = function () {
return modal.confirm({
title: 'Log deletion',
message: 'Are you sure you want to delete all the logs?'
}).then(function () {
// TODO: return all promises.
forEach($scope.pool.messages, function (message) {
xo.log.delete(message.id)
console.log('Remove log', message.id)
})
})
}
$scope.deleteLog = function (id) {
console.log('Remove log', id)
return xo.log.delete(id)
}
// $scope.patchPool = ($files, id) ->
// file = $files[0]
// xo.pool.patch id
// .then ({ $sendTo: url }) ->
// return $upload.http {
// method: 'POST'
// url
// data: file
// }
// .progress throttle(
// (event) ->
// percentage = (100 * event.loaded / event.total)|0
// notify.info
// title: 'Upload patch'
// message: "#{percentage}%"
// 6e3
// )
// .then (result) ->
// throw result.status if result.status isnt 200
// notify.info
// title: 'Upload patch'
// message: 'Success'
})
// A module exports its name.
.name

View File

@@ -1,152 +0,0 @@
//- TODO: lots of stuff.
.grid
.panel.panel-default
p.page-title
i.xo-icon-pool
| {{pool.name_label}}
.grid
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-cogs(style="color: #e25440;")
| General
span.quick-edit(tooltip="Edit General settings", ng-click="poolSettings.$show()")
i.fa.fa-edit.fa-fw
.panel-body
form(editable-form="", name="poolSettings", onbeforesave="savePool($data)")
dl.dl-horizontal
dt Name
dd
span(editable-text="pool.name_label", e-name="name_label", e-form="poolSettings")
| {{pool.name_label}}
dt Description
dd
span(editable-text="pool.name_description", e-name="name_description", e-form="poolSettings")
| {{pool.name_description}}
dt Master
dd(ng-repeat="master in [pool.master] | resolve")
a(ui-sref="hosts_view({id: master.id})")
| {{master.name_label}}
dt Tags
dd
span(ng-repeat="tag in pool.tags")
span.label.label-primary {{tag}}
dt(ng-if="pool.default_SR") Default SR
dd(ng-if="pool.default_SR", ng-init="default_SR = (pool.default_SR | resolve)")
a(ui-sref="SRs_view({id: default_SR.id})") {{default_SR.name_label}}
dt HA
dd
| {{pool.HA_enabled}}
dt UUID
dd {{pool.UUID}}
.btn-form(ng-show="poolSettings.$visible")
p.center
button.btn.btn-default(type="button", ng-disabled="poolSettings.$waiting", ng-click="poolSettings.$cancel()")
i.fa.fa-times
| Cancel
| &nbsp;
button.btn.btn-primary(type="submit", ng-disabled="poolSettings.$waiting")
i.fa.fa-save
| Save
.panel.panel-default
.panel-heading.panel-title
i.xo-icon-stats(style="color: #e25440;")
| Stats
.row
.col-sm-6.col-lg-4
p.stat-name Hosts:
p.center.big-stat {{hosts | count}}
.col-sm-6.col-lg-4
p.stat-name Running:
p.center.big-stat {{runningHosts | count}}
//- Action panel
.grid
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-flash(style="color: #e25440;")
| Actions
.panel-body
.grid-cell.text-center
.grid
.grid-cell.btn-group
button.btn(tooltip="Add SR", type="button", style="width: 90%", disabled)
i.xo-icon-sr.fa-2x.fa-fw
.grid-cell.btn-group
button.btn(tooltip="Add VM", type="button", style="width: 90%", xo-sref="VMs_new({container: pool.id})")
i.xo-icon-vm.fa-2x.fa-fw
.grid-cell.btn-group
button.btn(tooltip="Patch the pool", type="button", style="width: 90%", ng-file-select = "patchPool($files, pool.id)")
i.fa.fa-file-code-o.fa-2x.fa-fw
.grid-cell.btn-group
button.btn(tooltip="Add Host", type="button", style="width: 90%")
i.xo-icon-host.fa-2x.fa-fw
.grid-cell.btn-group
button.btn(tooltip="Disconnect", type="button", style="width: 90%; margin-bottom: 0.5em")
i.fa.fa-unlink.fa-2x.fa-fw
//- Hosts panel
.grid
.panel.panel-default
.panel-heading.panel-title
i.xo-icon-host(style="color: #e25440;")
| Hosts
.panel-body
table.table.table-hover.table-condensed
th Name
th.col-md-4 Description
th.col-md-6 Memory
tr(xo-sref="hosts_view({id: host.id})", ng-repeat="host in hosts | map | orderBy:natural('name_label') track by host.id")
td.oneliner {{host.name_label}}
td.oneliner {{host.name_description}}
td
.progress-condensed
.progress-bar(role="progressbar", aria-valuemin="0", aria-valuenow="{{host.memory.usage}}", aria-valuemax="{{host.memory.size}}", style="width: {{[host.memory.usage, host.memory.size] | percentage}}")
//- Shared SR panel
.grid
.panel.panel-default
.panel-heading.panel-title
i.xo-icon-sr(style="color: #e25440;")
| Shared SR
.panel-body
table.table.table-hover
th Name
th Description
th Type
th Size
th.col-md-4 Physical/Allocated usage
tr(
ng-repeat="SR in srs | map | orderBy:natural('name_label') track by SR.id"
xo-sref="SRs_view({id: SR.id})"
)
td.oneliner {{SR.name_label}}
td.oneliner {{SR.name_description}}
td {{SR.SR_type}}
td {{SR.size | bytesToSize}}
td
.progress-condensed
.progress-bar(role="progressbar", aria-valuemin="0", aria-valuenow="{{SR.usage}}", aria-valuemax="{{SR.size}}", style="width: {{[SR.physical_usage, SR.size] | percentage}}", tooltip="Physical usage: {{[SR.physical_usage, SR.size] | percentage}}")
.progress-bar.progress-bar-info(role="progressbar", aria-valuemin="0", aria-valuenow="{{SR.physical_usage}}", aria-valuemax="{{SR.size}}", style="width: {{[(SR.usage-SR.physical_usage), SR.size] | percentage}}", tooltip="Allocated: {{[(SR.usage), SR.size] | percentage}}")
//- Logs panel
.grid
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-comments(style="color: #e25440;")
| Logs
span.quick-edit(ng-if="pool.messages | isNotEmpty", tooltip="Remove all logs", xo-click="deleteAllLog()")
i.fa.fa-trash-o.fa-fw
.panel-body
p.center(ng-if="pool.messages | isEmpty") No recent logs
table.table.table-hover(ng-if="pool.messages | isNotEmpty")
th Date
th Name
tr(ng-repeat="message in pool.messages | map | orderBy:'-time' | slice:(5*(currentLogPage-1)):(5*currentLogPage) track by message.id")
td {{message.time*1e3 | date:"medium"}}
td
| {{message.name}}
span.pull-right.btn-group.quick-buttons
a(xo-click="deleteLog(message.id)")
i.fa.fa-trash-o.fa-lg(tooltip="Remove this log entry")
.center(ng-if = '(pool.messages | count) > 5')
pagination(boundary-links="true", total-items="pool.messages | count", ng-model="$parent.currentLogPage", items-per-page="5", max-size="5", class="pagination-sm", previous-text="<", next-text=">", first-text="<<", last-text=">>")

View File

@@ -1,98 +0,0 @@
import angular from 'angular'
import uiRouter from 'angular-ui-router'
import uiSelect from 'angular-ui-select'
import filter from 'lodash.filter'
import xoApi from 'xo-api'
import xoServices from 'xo-services'
import view from './view'
export default angular.module('settings.acls', [
uiRouter,
uiSelect,
xoApi,
xoServices
])
.config(function ($stateProvider) {
$stateProvider.state('settings.acls', {
controller: 'SettingsAcls as ctrl',
url: '/acls',
resolve: {
acls (xo) {
return xo.acl.get()
},
users (xo) {
return xo.user.getAll()
},
groups (xo) {
return xo.group.getAll()
},
roles (xo) {
return xo.role.getAll()
}
},
template: view
})
})
.controller('SettingsAcls', function ($scope, acls, users, groups, roles, xoApi, xo) {
this.acls = acls
this.users = users
{
let usersById = this.usersById = Object.create(null)
for (let user of users) {
usersById[user.id] = user
}
let groupsById = this.groupsById = Object.create(null)
for (let group of groups) {
groupsById[group.id] = group
}
let rolesById = this.rolesById = Object.create(null)
for (let role of roles) {
rolesById[role.id] = role
}
}
this.roles = roles
this.groups = groups
this.entities = this.users.concat(this.groups)
this.objects = xoApi.all
let refreshAcls = () => {
xo.acl.get().then(acls => {
this.acls = acls
})
}
this.getUser = (id) => {
for (let user of this.users) {
if (user.id === id) {
return user
}
}
}
this.addAcl = () => {
xo.acl.add(this.subject.id, this.object.id, this.role.id).then(refreshAcls)
this.subject = this.object = this.role = null
}
this.removeAcl = (subject, object, role) => {
xo.acl.remove(subject, object, role).then(refreshAcls)
}
})
.filter('selectHighLevel', () => {
const HIGH_LEVEL_OBJECTS = {
pool: true,
host: true,
VM: true,
SR: true
}
let isHighLevel = (object) => HIGH_LEVEL_OBJECTS[object.type]
return (objects) => filter(objects, isHighLevel)
})
.name

View File

@@ -1,95 +0,0 @@
.grid
.panel.panel-default
p.page-title
i.fa.fa-key(style="color: #e25440;")
| ACLs
.grid
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-plus-circle(style="color: #e25440;")
| Create
.panel-body.text-center
form(
ng-submit = 'ctrl.addAcl()'
)
.form-group
ui-select(
ng-model = 'ctrl.subject'
)
ui-select-match(
placeholder = 'Choose a user or group'
)
div
span(ng-if = '$select.selected.email')
i.fa.fa-fw.fa-user
| {{$select.selected.email}}
span(ng-if = '$select.selected.name')
i.fa.fa-fw.fa-users
| {{$select.selected.name}}
ui-select-choices(
repeat = 'entity in ctrl.entities | filter:{ permission: "!admin" } | filter:$select.search'
)
div
span(ng-if = 'entity.email')
i.fa.fa-fw.fa-user
| {{entity.email}}
span(ng-if = 'entity.name')
i.fa.fa-fw.fa-users
| {{entity.name}}
.form-group
ui-select(
ng-model = 'ctrl.object'
)
ui-select-match(
placeholder = 'Choose an object'
)
div
i(class = 'xo-icon-{{$select.selected.type | lowercase}}')
| {{$select.selected.name_label}}
ui-select-choices(
repeat = 'object in ctrl.objects | selectHighLevel | filter:$select.search | orderBy:["type", "name_label"]'
)
div
i(class = 'xo-icon-{{object.type | lowercase}}')
| {{object.name_label}}
span(ng-if="(object.type === 'SR' || object.type === 'VM') && object.$container")
| ({{(object.$container | resolve).name_label}})
.form-group
ui-select(
ng-model = 'ctrl.role'
)
ui-select-match(
placeholder = 'Choose a role'
)
div
i(class = 'xo-icon-{{$select.selected.type | lowercase}}')
| {{$select.selected.name}}
ui-select-choices(
repeat = 'role in ctrl.roles | filter:$select.search | orderBy:"name"'
)
div
i(class = 'xo-icon-{{role.type | lowercase}}')
| {{role.name}}
button.btn.btn-success
i.fa.fa-plus
| Create
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-street-view(style="color: #e25440;")
| Manage
.panel-body
table.table.table-hover
tr
th User
th Object
th Role
th
tr(ng-repeat = 'acl in ctrl.acls')
td {{ ctrl.usersById[acl.subject].email || ctrl.groupsById[acl.subject].name }}
td {{(acl.object | resolve).name_label}}
td {{ ctrl.rolesById[acl.action].name }}
td
button.btn.btn-sm.btn-danger(ng-click = 'ctrl.removeAcl(acl.subject, acl.object, acl.action)')
i.fa.fa-trash

View File

@@ -1,161 +0,0 @@
import angular from 'angular'
import uiRouter from 'angular-ui-router'
import uiSelect from 'angular-ui-select'
import uiEvent from 'angular-ui-event'
import xoApi from 'xo-api'
import xoServices from 'xo-services'
import view from './view'
export default angular.module('settings.groups', [
uiRouter,
uiSelect,
uiEvent,
xoApi,
xoServices
])
.config(function ($stateProvider) {
$stateProvider.state('settings.groups', {
controller: 'SettingsGroups as ctrl',
url: '/groups',
resolve: {
users (xo) {
return xo.user.getAll()
},
groups (xo) {
return xo.group.getAll()
}
},
template: view
})
})
.controller('SettingsGroups', function ($scope, $interval, users, groups, xoApi, xo) {
this.uiCollapse = Object.create(null)
this.addedUsers = []
this.users = users
this.userEmails = Object.create(null)
this.users.forEach(user => {
this.userEmails[user.id] = user.email
})
this.groups = groups
const selectedGroups = this.selectedGroups = {}
this.newGroups = []
const refreshUsers = () => {
xo.user.getAll().then(users => {
this.users = users
this.userEmails = Object.create(null)
this.users.forEach(user => {
this.userEmails[user.id] = user.email
})
})
}
const refreshGroups = () => {
let editing = this._editingGroup
for (let groupId in this.uiCollapse) {
editing = editing || this.uiCollapse[groupId]
}
if (!editing) {
xo.group.getAll().then(groups => this.groups = groups)
}
}
const interval = $interval(() => {
refreshUsers()
refreshGroups()
}, 5e3)
$scope.$on('$destroy', () => {
$interval.cancel(interval)
})
this.addGroup = () => {
this.newGroups.push({
// Fake (unique) id needed by Angular.JS
id: Math.random()
})
}
this.addGroup()
this.saveGroups = () => {
const newGroups = this.newGroups
const groups = this.groups
const updateGroups = []
for (let i = 0, len = groups.length; i < len; i++) {
const group = groups[i]
const {id} = group
if (selectedGroups[id]) {
delete selectedGroups[id]
xo.group.delete(id)
} else {
xo.group.set(group)
updateGroups.push(group)
}
}
for (let i = 0, len = newGroups.length; i < len; i++) {
const group = newGroups[i]
const {name} = group
if (!name) {
continue
}
xo.group.create({name})
.then(function (id) {
group.id = id
group.users = []
})
updateGroups.push(group)
}
this.groups = updateGroups
this.newGroups.length = 0
this.addGroup()
}
this.addUserToGroup = (group, index) => {
group.users.push(this.addedUsers[index].id)
delete this.addedUsers[index]
}
this.flagUserRemoval = (group, index, remove) => {
group.removals || (group.removals = {})
group.removals[group.users[index]] = remove
}
this.saveGroup = (group) => {
const users = []
group.users.forEach(user => {
let remove = group.removals && group.removals[user]
if (!remove) {
users.push(user)
}
})
group.removals && delete group.removals
xo.group.setUsers(group.id, users)
.then(() => {
group.users = users
this.uiCollapse[group.id] = false
})
}
this.editingGroup = editing => {
this._editingGroup = editing
}
})
.filter('notInGroup', function () {
return function (users, group) {
const filtered = []
users.forEach(user => {
if (!group.users || group.users.indexOf(user.id) === -1) {
filtered.push(user)
}
})
return filtered
}
})
.name

View File

@@ -1,63 +0,0 @@
.grid
.panel.panel-default
p.page-title
i.fa.fa-users(style="color: #e25440;")
| Groups
.grid
.panel.panel-default
form(ng-submit="ctrl.saveGroups()", autocomplete="off").panel-body
table.table.table-hover
tr
th.col-md-5 Name
th.col-md-5 Manage
th.col-md-2.text-center
i.fa.fa-trash-o.fa-lg(tooltip="Remove group")
tr(ng-repeat="group in ctrl.groups | orderBy:natural('id') track by group.id")
td
input.form-control(type="text", ng-model="group.name", ui-event = '{focus: "ctrl.editingGroup(true)", blur: "ctrl.editingGroup(false)"}')
td
button.btn.btn-info(type = 'button', ng-click = 'ctrl.uiCollapse[group.id] = !ctrl.uiCollapse[group.id]')
| Users&nbsp;
span.badge {{ group.users.length || "" }}
| &nbsp;
i.fa(ng-class = '{"fa-chevron-down": !ctrl.uiCollapse[$index], "fa-chevron-up": ctrl.uiCollapse[$index]}')
br
br
div(collapse = '!ctrl.uiCollapse[group.id]')
ul.list-group(ng-if = '!group.users.length')
li.list-group-item.disabled: em (empty)
ul.list-group(ng-if = 'group.users.length')
li.list-group-item(ng-repeat = 'user in group.users')
span(ng-if = '!removeUser') {{ ctrl.userEmails[user] }}&nbsp;
del(ng-if = 'removeUser') {{ ctrl.userEmails[user] }}&nbsp;
span.pull-right
label
input.hidden(type = 'checkbox', ng-model = 'removeUser', ng-change = 'ctrl.flagUserRemoval($parent.group, $index, removeUser)')
| &nbsp;
i.fa.fa-trash-o(tooltip="Remove user from group")
p.form-inline
select.form-control(ng-model = 'ctrl.addedUsers[$index]', ng-options = 'addedUser.email for addedUser in ctrl.users | notInGroup:group | orderBy:natural("email") track by addedUser.id')
| &nbsp;
button.btn.btn-success.btn-sm(type="button", ng-click="ctrl.addUserToGroup(group, $index)")
i.fa.fa-plus
button.btn.btn-info(type="button", ng-click = 'ctrl.saveGroup(group)')
i.fa.fa-save
| Save
td.text-center
input(type="checkbox", ng-model="ctrl.selectedGroups[group.id]")
tr(ng-repeat="group in ctrl.newGroups")
td
input.form-control(
type = "text"
ng-model = "group.name"
placeholder = "name"
)
td &#160;
td &#160;
p.text-center
button.btn.btn-primary(type="submit")
i.fa.fa-save
| Save
| &nbsp;
button.btn.btn-success(type="button", ng-click="ctrl.addGroup()")
i.fa.fa-plus

View File

@@ -1,37 +0,0 @@
import angular from 'angular'
import uiRouter from 'angular-ui-router'
import acls from './acls'
import groups from './groups'
import servers from './servers'
import update from './update'
import users from './users'
import view from './view'
export default angular.module('settings', [
uiRouter,
acls,
groups,
servers,
update,
users
])
.config(function ($stateProvider) {
$stateProvider.state('settings', {
abstract: true,
template: view,
url: '/settings'
})
// Redirect to default sub-state.
$stateProvider.state('settings.index', {
url: '',
controller: function ($state) {
$state.go('settings.servers')
}
})
})
.name

View File

@@ -1,123 +0,0 @@
import angular from 'angular'
import uiRouter from 'angular-ui-router'
import uiSelect from 'angular-ui-select'
import xoApi from 'xo-api'
import xoServices from 'xo-services'
import view from './view'
export default angular.module('settings.servers', [
uiRouter,
uiSelect,
xoApi,
xoServices
])
.config(function ($stateProvider) {
$stateProvider.state('settings.servers', {
controller: 'SettingsServers as ctrl',
url: '/servers',
resolve: {
servers (xo) {
return xo.server.getAll()
}
},
template: view
})
})
.controller('SettingsServers', function ($scope, $interval, servers, xoApi, xo, notify) {
this.servers = servers
const selected = this.selectedServers = {}
const newServers = this.newServers = []
const refreshServers = () => {
xo.server.getAll().then(servers => {
this.servers = servers
})
}
const interval = $interval(refreshServers, 10e3)
$scope.$on('$destroy', () => {
$interval.cancel(interval)
})
this.connectServer = (id) => {
notify.info({
title: 'Server connect',
message: 'Connecting the server...'
})
xo.server.connect(id).catch(error => {
notify.error({
title: 'Server connection error',
message: error.message
})
})
}
this.disconnectServer = (id) => {
notify.info({
title: 'Server disconnect',
message: 'Disconnecting the server...'
})
xo.server.disconnect(id)
}
this.addServer = () => {
newServers.push({
// Fake (unique) id needed by Angular.JS
id: Math.random(),
status: 'connecting'
})
}
this.addServer()
this.saveServers = () => {
const newServers = this.newServers
const servers = this.servers
const updateServers = []
for (let i = 0, len = servers.length; i < len; i++) {
const server = servers[i]
const {id} = server
if (selected[id]) {
delete selected[id]
xo.server.remove(id)
} else {
if (!server.password) {
delete server.password
}
xo.server.set(server)
delete server.password
updateServers.push(server)
}
}
for (let i = 0, len = newServers.length; i < len; i++) {
const server = newServers[i]
const {host, username, password} = server
if (!host) {
continue
}
xo.server.add({
host,
username,
password,
autoConnect: false
}).then(function (id) {
server.id = id
xo.server.connect(id).catch(error => {
notify.error({
title: 'Server connection error',
message: error.message
})
})
})
delete server.password
updateServers.push(server)
}
this.servers = updateServers
this.newServers.length = 0
this.addServer()
}
})
.name

View File

@@ -1,80 +0,0 @@
.grid
.panel.panel-default
p.page-title
i.fa.fa-cloud(style="color: #e25440;")
| Servers
.grid
.panel.panel-default
//- .panel-heading.panel-title
//- i.fa.fa-cloud(style="color: #e25440;")
//- | Connections
form(ng-submit="ctrl.saveServers()", autocomplete="off").panel-body
table.table.table-hover
tr
th.col-md-5 Host
th.col-md-2 User
th.col-md-3 Password
th.col-md-1.text.center Actions
th.col-md-1.text-center
i.fa.fa-trash-o.fa-lg(tooltip="Forget server")
tr(ng-repeat="server in ctrl.servers | orderBy:natural('host') track by server.id")
td
.input-group
span.input-group-addon(ng-if="server.status === 'connected'")
i.fa.fa-check-circle.fa-lg.text-success(tooltip="Connected")
span.input-group-addon(ng-if="server.status === 'disconnected'")
i.fa.fa-times-circle.fa-lg.text-danger(tooltip="Disconnected")
span.input-group-addon(ng-if="server.status === 'connecting'")
i.fa.fa-cog.fa-lg.fa-spin(tooltip="Connecting...")
input.form-control(type="text", ng-model="server.host")
td
input.form-control(type="text", ng-model="server.username")
td
input.form-control(type="password", ng-model="server.password", placeholder="Fill to change the password")
td.text-center
button.btn.btn-default(
ng-if="server.status === 'disconnected'",
type="button",
ng-click="ctrl.connectServer(server.id)",
tooltip="Reconnect this server"
)
i.fa.fa-link
button.btn.btn-danger(
ng-if="server.status === 'connected'",
type="button",
ng-click="ctrl.disconnectServer(server.id)"
tooltip="Disconnect this server"
)
i.fa.fa-unlink
td.text-center
input(type="checkbox", ng-model="ctrl.selectedServers[server.id]")
tr(ng-repeat="server in ctrl.newServers")
td
input.form-control(
type = "text"
ng-model = "server.host"
placeholder = "address[:port]"
)
td
input.form-control(
type = "text"
ng-model = "server.username"
ng-required = "server.host"
placeholder = "user"
)
td
input.form-control(
type="password"
ng-model="server.password"
ng-required = "server.host"
placeholder="password"
)
td &#160;
td &#160;
p.text-center
button.btn.btn-primary(type="submit")
i.fa.fa-save
| Save
| &nbsp;
button.btn.btn-success(type="button", ng-click="ctrl.addServer()")
i.fa.fa-plus

View File

@@ -1,93 +0,0 @@
import angular from 'angular'
import uiRouter from 'angular-ui-router'
import _assign from 'lodash.assign'
import ansiUp from 'ansi_up'
import updater from '../../updater'
import xoApi from 'xo-api'
import xoServices from 'xo-services'
import {AuthenticationFailed} from '../../updater'
import view from './view'
export default angular.module('settings.update', [
uiRouter,
updater,
xoApi,
xoServices
])
.config(function ($stateProvider) {
$stateProvider.state('settings.update', {
controller: 'SettingsUpdate as ctrl',
url: '/update',
onExit: updater => {
updater.removeAllListeners('end')
},
template: view
})
})
.filter('ansitohtml', function ($sce) {
return function (input) {
return $sce.trustAsHtml(ansiUp.ansi_to_html(input))
}
})
.controller('SettingsUpdate', function (xoApi, xo, updater, notify) {
this.updater = updater
this.updater.isRegistered()
.then(() => this.updater.on('end', () => {
if (this.updater.state === 'registerNeeded' && this.updater.registerState !== 'unregistered' && this.updater.registerState !== 'error') {
this.updater.isRegistered()
}
}))
.catch(err => console.error(err))
this.updater.getConfiguration()
.then(configuration => this.configuration = _assign({}, configuration))
.catch(error => notify.error({
title: 'XOA Updater',
message: error.message
}))
this.registerXoa = (email, password) => {
this.regPwd = ''
this.updater.register(email, password)
.then(() => this.updater.update())
.catch(AuthenticationFailed, () => {})
}
this.update = () => {
this.updater.update()
.catch(error => notify.error({
title: 'XOA Updater',
message: error.message
}))
}
this.upgrade = () => {
this.updater.upgrade()
.catch(error => notify.error({
title: 'XOA Updater',
message: error.message
}))
}
this.configure = (host, port) => {
const config = {}
config.proxyHost = host && host.trim() || null
config.proxyPort = port && port.trim() || null
return this.updater.configure(config)
.then(configuration => this.configuration = _assign({}, configuration))
.catch(error => notify.error({
title: 'XOA Updater',
message: error.message
}))
.finally(() => this.update())
}
this.valid = trial => {
return trial && trial.end && Date.now() < trial.end
}
})
.name

View File

@@ -1,112 +0,0 @@
.grid
.panel.panel-default
p.page-title
i.fa.fa-refresh(style="color: #e25440;")
| Update
.grid
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-globe(style="color: #e25440;")
| Status
.panel-body
p(ng-if = '!ctrl.updater.state')
a.btn.btn-warning: i.fa.fa-question-circle(ng-if = '!ctrl.updater.state', tooltip = 'No update information available')
| &nbsp;No update information available&nbsp;
a.btn.btn-default(ng-class = '{disabled: ctrl.updater.isConnected}', ng-click = 'ctrl.update()')
i.fa.fa-refresh(ng-class = '{"fa-spin": ctrl.updater.isConnected}')
.form-group(ng-if = 'ctrl.updater.state && ctrl.updater.state === "registerNeeded"')
a.btn.btn-warning(ng-if = 'ctrl.updater.state === "registerNeeded"'): i.fa.fa-bell-slash(tooltip = 'Your XOA is not registered for updates')
| &nbsp;Registration needed&nbsp;
button.btn.btn-default(ng-if = 'ctrl.updater.registerState === "registered"', ng-click = 'ctrl.updater.update()', ng-class = '{disabled: ctrl.updater.updating || ctrl.updater.upgrading}'): i.fa.fa-refresh(ng-class = '{"fa-spin": ctrl.updater.updating || ctrl.updater.upgrading}')
.form-group(ng-if = 'ctrl.updater.state && ctrl.updater.state !== "registerNeeded"')
a.btn.btn-info(ng-if = 'ctrl.updater.state === "connected"'): i.fa.fa-question-circle(tooltip = 'Update information may be available')
a.btn.btn-success(ng-if = 'ctrl.updater.state === "upToDate"'): i.fa.fa-check(tooltip = 'Your XOA is up-to-date')
a.btn.btn-primary(ng-if = 'ctrl.updater.state === "upgradeNeeded"'): i.fa.fa-bell(tooltip = 'You need to update your XOA (new version is available)')
a.btn.btn-danger(ng-if = 'ctrl.updater.state === "error"'): i.fa.fa-exclamation-triangle(tooltip = 'Can\'t fetch update information')
| &nbsp;
button#update.btn.btn-info(type = 'button', ng-click = 'ctrl.update()', ng-class = '{disabled: ctrl.updater.updating || ctrl.updater.upgrading}')
| Check for updates&nbsp;
i.fa.fa-refresh(ng-class = '{"fa-spin": ctrl.updater.updating}')
| &nbsp;
button#upgrade.btn.btn-primary(ng-if = 'ctrl.updater.state === "upgradeNeeded"', type = 'button', ng-click = 'ctrl.upgrade()', ng-class = '{disabled: ctrl.updater.updating || ctrl.updater.upgrading}')
| Upgrade&nbsp;
i.fa.fa-cog(ng-class = '{"fa-spin": ctrl.updater.upgrading}')
div
p(ng-repeat = 'entry in ctrl.updater._log')
span(ng-class = '{"text-danger": entry.level === "error", "text-muted": entry.level === "info", "text-warning": entry.level === "warning", "text-success": entry.level === "success"}') {{ entry.date }}
| &nbsp;:&nbsp;
span(ng-bind-html = 'entry.message | ansitohtml')
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-pencil(style="color: #e25440;")
| Registration
.panel-body.text-center
.text-warning(ng-if = '!ctrl.updater.state || ctrl.updater.registerState === "unknown"')
| No registration information available.
br
span.big-stat
i.fa.fa-exclamation-triangle.text-warning
div(ng-if = 'ctrl.updater.state && ctrl.updater.registerState === "error"')
.text-danger Can't fetch registration information.
br
span.big-stat
i.fa.fa-exclamation-triangle.text-danger
br
.text-danger {{ ctrl.updater.registerError }}
br
button.btn.btn-default(type = 'button', ng-click = 'ctrl.updater.isRegistered()')
i.fa.fa-refresh
| Refresh
form(ng-if = 'ctrl.updater.state && ctrl.updater.registerState === "unregistered"', ng-submit = 'ctrl.registerXoa(ctrl.regEmail, ctrl.regPwd)')
p.form-static-control XOA is not registered.
p.small Your xen-orchestra.com email and password
.form-group
.input-group
span.input-group-addon: i.fa.fa-envelope-o.fa-fw
label.sr-only(for = 'regEmail') Email
input#regEmail.form-control(type = 'email', placeholder = 'Email', ng-model = 'ctrl.regEmail', required)
.form-group
.input-group
span.input-group-addon: i.fa.fa-key.fa-fw
label.sr-only(for = 'regPwd') Email
input#regPwd.form-control(type = 'password', placeholder = 'Password', ng-model = 'ctrl.regPwd', required)
.form-group
button.btn.btn-primary(type = 'submit')
i.fa.fa-check
| Register
p.form-static-control.text-danger {{ ctrl.updater.registerError }}
p(ng-if = 'ctrl.updater.state && ctrl.updater.registerState === "registered"')
| Your Xen Orchestra appliance is registered to
span.text-success {{ ctrl.updater.token.registrationEmail }}
| .
br
span.big-stat
i.fa.fa-check-circle.text-success
.grid
.grid-cell(ng-if = 'ctrl.updater.state && ctrl.configuration')
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-cogs(style="color: #e25440;")
| Settings
.panel-body
form.form-inline(ng-submit = 'ctrl.configure(ctrl.configuration.proxyHost, ctrl.configuration.proxyPort)')
fieldset
h4
i.fa.fa-globe
| Proxy settings
p If you need a proxy to access the Internet
.form-group
label.control-label Host:&nbsp;
input.form-control(type = 'text', ng-model = 'ctrl.configuration.proxyHost', placeholder = 'myproxy.example.org')
| &nbsp;
| &nbsp;
.form-group
label.control-label Port:&nbsp;
input.form-control(type = 'text', ng-model = 'ctrl.configuration.proxyPort', placeholder = '3128')
| &nbsp;
| &nbsp;
| &nbsp;
.form-group
button.btn.btn-primary(type = 'submit')
i.fa.fa-floppy-o
| Save

View File

@@ -1,122 +0,0 @@
import angular from 'angular'
import uiRouter from 'angular-ui-router'
import uiSelect from 'angular-ui-select'
import uiEvent from 'angular-ui-event'
import xoApi from 'xo-api'
import xoServices from 'xo-services'
import view from './view'
export default angular.module('settings.users', [
uiRouter,
uiSelect,
uiEvent,
xoApi,
xoServices
])
.config(function ($stateProvider) {
$stateProvider.state('settings.users', {
controller: 'SettingsUsers as ctrl',
url: '/users',
resolve: {
users (xo) {
return xo.user.getAll()
}
},
template: view
})
})
.controller('SettingsUsers', function ($scope, $interval, users, xoApi, xo) {
this.users = users
this.permissions = [
{
label: 'User',
value: 'none'
},
{
label: 'Admin',
value: 'admin'
}
]
const selected = this.selectedUsers = {}
this.newUsers = []
const refreshUsers = () => {
if (!this._editingUser) {
xo.user.getAll().then(users => {
this.users = users
this.userEmails = Object.create(null)
this.users.forEach(user => {
this.userEmails[user.id] = user.email
})
})
}
}
const interval = $interval(() => {
refreshUsers()
}, 5e3)
$scope.$on('$destroy', () => {
$interval.cancel(interval)
})
this.addUser = () => {
this.newUsers.push({
// Fake (unique) id needed by Angular.JS
id: Math.random(),
permission: 'none'
})
}
this.addUser()
this.saveUsers = () => {
const newUsers = this.newUsers
const users = this.users
const updateUsers = []
for (let i = 0, len = users.length; i < len; i++) {
const user = users[i]
const {id} = user
if (selected[id]) {
delete selected[id]
xo.user.delete(id)
} else {
if (!user.password) {
delete user.password
}
xo.user.set(user)
delete user.password
updateUsers.push(user)
}
}
for (let i = 0, len = newUsers.length; i < len; i++) {
const user = newUsers[i]
const {email, permission, password} = user
if (!email) {
continue
}
xo.user.create({
email,
permission,
password
}).then(function (id) {
user.id = id
})
delete user.password
updateUsers.push(user)
}
this.users = updateUsers
this.newUsers.length = 0
this.userEmails = Object.create(null)
this.users.forEach(user => {
this.userEmails[user.id] = user.email
})
this.addUser()
}
})
.name

View File

@@ -1,55 +0,0 @@
.grid
.panel.panel-default
p.page-title
i.fa.fa-user(style="color: #e25440;")
| Users
.grid
.panel.panel-default
//- .panel-heading.panel-title
//- i.fa.fa-users(style="color: #e25440;")
//- | Users
form(ng-submit="ctrl.saveUsers()", autocomplete="off").panel-body
table.table.table-hover
tr
th.col-md-4 Email
th.col-md-4 Permissions
th.col-md-3 Password
th.col-md-1.text-center
i.fa.fa-trash-o.fa-lg(tooltip="Remove user")
tr(ng-repeat="user in ctrl.users | orderBy:natural('id') track by user.id")
td
input.form-control(type="text", ng-model="user.email", ui-event = '{focus: "ctrl.editingUser(true)", blur: "ctrl.editingUser(false)"}')
td
select.form-control(ng-options="p.value as p.label for p in ctrl.permissions", ng-model="user.permission", ui-event = '{focus: "ctrl.editingUser(true)", blur: "ctrl.editingUser(false)"}')
td
input.form-control(type="password", ng-model="user.password", placeholder="Fill to change the password", ui-event = '{focus: "ctrl.editingUser(true)", blur: "ctrl.editingUser(false)"}')
td.text-center
input(type="checkbox", ng-model="ctrl.selectedUsers[user.id]")
tr(ng-repeat="user in ctrl.newUsers")
td
input.form-control(
type = "text"
ng-model = "user.email"
placeholder = "email"
)
td
select.form-control(
ng-options = "p.value as p.label for p in ctrl.permissions"
ng-model = "user.permission"
ng-required = "user.email"
)
td
input.form-control(
type = "password"
ng-model = "user.password"
ng-required = "user.email"
placeholder = "password"
)
td &#160;
p.text-center
button.btn.btn-primary(type="submit")
i.fa.fa-save
| Save
| &nbsp;
button.btn.btn-success(type="button", ng-click="ctrl.addUser()")
i.fa.fa-plus

View File

@@ -1,23 +0,0 @@
.grid(style = 'height: 100%')
//- Side menu
.settings-menu
ul.nav
li
a(ui-sref = '.servers', ui-sref-active = 'active')
i.fa.fa-fw.fa-cloud.fa-menu
span.menu-entry Servers
a(ui-sref = '.users')
i.fa.fa-fw.fa-user.fa-menu
span.menu-entry Users
a(ui-sref = '.groups')
i.fa.fa-fw.fa-users.fa-menu
span.menu-entry Groups
a(ui-sref = '.acls')
i.fa.fa-fw.fa-key.fa-menu
span.menu-entry ACLs
a(ui-sref = '.update')
i.fa.fa-fw.fa-refresh.fa-menu
span.menu-entry Update
//- Content
div.settings-content(ui-view = '')

View File

@@ -1,192 +0,0 @@
import angular from 'angular'
import forEach from 'lodash.foreach'
import isEmpty from 'lodash.isempty'
import uiRouter from 'angular-ui-router'
import Bluebird from 'bluebird'
import view from './view'
// ===================================================================
export default angular.module('xoWebApp.sr', [
uiRouter
])
.config(function ($stateProvider) {
$stateProvider.state('SRs_view', {
url: '/srs/:id',
controller: 'SrCtrl',
template: view
})
})
.controller('SrCtrl', function ($scope, $stateParams, $state, $q, notify, xoApi, xo, modal, $window, bytesToSizeFilter) {
$window.bytesToSize = bytesToSizeFilter // FIXME dirty workaround to custom a Chart.js tooltip template
$scope.currentLogPage = 1
$scope.currentVDIPage = 1
let {get} = xoApi
$scope.$watch(() => xoApi.get($stateParams.id), function (SR) {
$scope.SR = SR
})
$scope.saveSR = function ($data) {
let {SR} = $scope
let {name_label, name_description} = $data
$data = {
id: SR.id
}
if (name_label !== SR.name_label) {
$data.name_label = name_label
}
if (name_description !== SR.name_description) {
$data.name_description = name_description
}
return xoApi.call('sr.set', $data)
}
$scope.deleteVDI = function (id) {
console.log('Delete VDI', id)
return modal.confirm({
title: 'VDI deletion',
message: 'Are you sure you want to delete this VDI? This operation is irreversible.'
}).then(function () {
return xo.vdi.delete(id)
})
}
$scope.disconnectVBD = function (id) {
console.log('Disconnect VBD', id)
return xoApi.call('vbd.disconnect', {id: id})
}
$scope.connectPBD = function (id) {
console.log('Connect PBD', id)
return xoApi.call('pbd.connect', {id: id})
}
$scope.disconnectPBD = function (id) {
console.log('Disconnect PBD', id)
return xoApi.call('pbd.disconnect', {id: id})
}
$scope.reconnectAllHosts = function () {
// TODO: return a Bluebird.all(promises).
for (let id of $scope.SR.$PBDs) {
let pbd = xoApi.get(id)
xoApi.call('pbd.connect', {id: pbd.id})
}
}
$scope.disconnectAllHosts = function () {
return modal.confirm({
title: 'Disconnect hosts',
message: 'Are you sure you want to disconnect all hosts to this SR?'
}).then(function () {
for (let id of $scope.SR.$PBDs) {
let pbd = xoApi.get(id)
xoApi.call('pbd.disconnect', {id: pbd.id})
console.log(pbd.id)
}
})
}
$scope.rescanSr = function (id) {
console.log('Rescan SR', id)
return xoApi.call('sr.scan', {id: id})
}
$scope.removeSR = function (id) {
console.log('Remove SR', id)
return modal.confirm({
title: 'SR deletion',
message: 'Are you sure you want to delete this SR? This operation is irreversible.'
}).then(function () {
return Bluebird.map($scope.SR.$PBDs, pbdId => {
let pbd = xoApi.get(pbdId)
return xoApi.call('pbd.disconnect', { id: pbd.id })
})
}).then(function () {
return xoApi.call('sr.destroy', {id: id})
}).then(function () {
$state.go('index')
notify.info({
title: 'SR remove',
message: 'SR is removed'
})
})
}
$scope.forgetSR = function (id) {
console.log('Forget SR', id)
return modal.confirm({
title: 'SR forget',
message: 'Are you sure you want to forget this SR? No VDI on this SR will be removed.'
}).then(function () {
return Bluebird.map($scope.SR.$PBDs, pbdId => {
let pbd = xoApi.get(pbdId)
return xoApi.call('pbd.disconnect', { id: pbd.id })
})
}).then(function () {
return xoApi.call('sr.forget', {id: id})
}).then(function () {
$state.go('index')
notify.info({
title: 'SR forget',
message: 'SR is forgotten'
})
})
}
$scope.saveDisks = function (data) {
// Group data by disk.
let disks = {}
forEach(data, function (value, key) {
let i = key.indexOf('/')
let id = key.slice(0, i)
let prop = key.slice(i + 1)
;(disks[id] || (disks[id] = {}))[prop] = value
})
let promises = []
forEach(disks, function (attributes, id) {
// Keep only changed attributes.
let disk = get(id)
forEach(attributes, function (value, name) {
if (value === disk[name]) {
delete attributes[name]
}
})
if (!isEmpty(attributes)) {
// Inject id.
attributes.id = id
// Ask the server to update the object.
promises.push(xoApi.call('vdi.set', attributes))
}
})
return $q.all(promises)
}
})
// A module exports its name.
.name

View File

@@ -1,211 +0,0 @@
.grid
.panel.panel-default
p.page-title
i.xo-icon-sr
| {{SR.name_label}}
.grid
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-cogs(style="color: #e25440;")
| General
span.quick-edit(tooltip="Edit General settings", ng-click="srSettings.$show()")
i.fa.fa-edit.fa-fw
.panel-body
form(editable-form="", name="srSettings", onbeforesave="saveSR($data)")
dl.dl-horizontal
dt Name
dd
span(editable-text="SR.name_label", e-name="name_label", e-form="srSettings")
| {{SR.name_label}}
dt Description
dd
span(editable-text="SR.name_description", e-name="name_description", e-form="srSettings")
| {{SR.name_description}}
dt Content type:
dd {{SR.SR_type}}
dt Tags
dd(ng-if="SR.tags.length")
span(ng-repeat="tag in SR.tags")
span.label.label-primary {{tag}}
dd(ng-if="!SR.tags.length")
em No tags.
dt Shared
div(ng-repeat="container in [SR.$container] | resolve")
dd(ng-if="'pool' === container.type")
| Yes (
a(ui-sref="pools_view({id: container.id})") {{container.name_label}}
| )
dd(ng-if="'host' === container.type") No
dt Size
dd {{SR.size | bytesToSize}}
dt UUID
dd {{SR.UUID}}
.btn-form(ng-show="srSettings.$visible")
p.center
button.btn.btn-default(type="button", ng-disabled="srSettings.$waiting", ng-click="srSettings.$cancel()")
i.fa.fa-times
| Cancel
| &nbsp;
button.btn.btn-primary(type="submit", ng-disabled="srSettings.$waiting")
i.fa.fa-save
| Save
.panel.panel-default
.panel-heading.panel-title
i.xo-icon-stats(style="color: #e25440;")
| Stats
.panel-body
.row
.col-sm-6.col-lg-4
p.stat-name Physical Alloc:
canvas.stat-simple(id="doughnut", class="chart chart-doughnut", data="[(SR.physical_usage), (SR.size - SR.physical_usage)]", labels="['Used', 'Free']", options='{tooltipTemplate: "<%if (label){%><%=label%>: <%}%><%= bytesToSize(value) %>"}')
.col-sm-6.col-lg-4
p.stat-name Virtual Alloc:
canvas.stat-simple(id="doughnut", class="chart chart-doughnut", data="[(SR.usage), (SR.size - SR.usage)]", labels="['Used', 'Free']", options='{tooltipTemplate: "<%if (label){%><%=label%>: <%}%><%= bytesToSize(value) %>"}')
.col-sm-4.visible-lg
p.stat-name VDIs:
p.center.big-stat {{SR.VDIs.length}}
.row.hidden-lg
.col-sm-12
br
p.stat-name {{SR.VDIs.length}} VDIs
//- Action panel
.grid
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-flash(style="color: #e25440;")
| Actions
.panel-body.text-center
.grid
.grid-cell.btn-group
button.btn(tooltip="Rescan all the VDI", type="button", style="width: 90%", ng-click="rescanSr(SR.id)")
i.fa.fa-refresh.fa-2x.fa-fw
.grid-cell.btn-group
button.btn(tooltip="Reconnect all hosts", type="button", style="width: 90%", ng-click="reconnectAllHosts()")
i.fa.fa-retweet.fa-2x.fa-fw
.grid-cell.btn-group
button.btn(tooltip="Disconnect all hosts", type="button", style="width: 90%", xo-click="disconnectAllHosts()")
i.fa.fa-power-off.fa-2x.fa-fw
.grid-cell.btn-group
button.btn(tooltip="Forget SR", type="button", style="width: 90%", xo-click="forgetSR(SR.id)")
i.fa.fa-2x.fa-fw.fa-ban
.grid-cell.btn-group
button.btn(tooltip="Remove SR", type="button", style="width: 90%", xo-click="removeSR(SR.id)")
i.fa.fa-2x.fa-trash-o
//- TODO: Space panel
.grid
.panel.panel-default
.panel-heading.panel-title
i.xo-icon-memory(style="color: #e25440;")
| VDI Map
.panel-body
.progress
.progress-bar.progress-bar-vm(ng-if="((VDI.size/SR.size)*100) > 0.5", ng-repeat="VDI in SR.VDIs | resolve | orderBy:natural('name_label') track by VDI.id", role="progressbar", aria-valuemin="0", aria-valuenow="{{VDI.size}}", aria-valuemax="{{SR.size}}", style="width: {{[VDI.size, SR.size] | percentage}}", tooltip="{{VDI.name_label}} ({{[VDI.size, SR.size] | percentage}})")
//- display the name only if it fits in its progress bar
span(ng-if="VDI.name_label.length < ((VDI.size/SR.size)*100)") {{VDI.name_label}}
ul.list-inline.text-center
li Total: {{SR.size | bytesToSize}}
li Currently used: {{SR.usage | bytesToSize}}
li Available: {{SR.size-SR.usage | bytesToSize}}
//- TODO: VDIs.
.grid
form(name = "disksForm" editable-form = '' onbeforesave = 'saveDisks($data)').panel.panel-default
.panel-heading.panel-title
i.fa.fa-hdd-o(style="color: #e25440;")
| Virtual disks
span.quick-edit(tooltip="Edit disks", ng-click="disksForm.$show()")
i.fa.fa-edit.fa-fw
span.quick-edit(tooltip="Rescan", ng-click="rescanSr(SR.id)")
i.fa.fa-refresh.fa-fw
.panel-body
table.table.table-hover
tr
th Name
th Description
th Size
th Virtual Machine:
tr(ng-repeat="VDI in SR.VDIs | resolve | orderBy:natural('name_label') | slice:(10*(currentVDIPage-1)):(10*currentVDIPage)")
td.oneliner
span(
editable-text="VDI.name_label"
e-name = '{{VDI.id}}/name_label'
)
| {{VDI.name_label}} &nbsp;
span.label.label-info(ng-if="VDI.$snapshot_of") snapshot
td.oneliner
span(
editable-text="VDI.name_description"
e-name = '{{VDI.id}}/name_description'
)
| {{VDI.name_description}}
td
//- FIXME: should be editable, but the server needs first
//- to accept a human readable string.
| {{VDI.size | bytesToSize}}
td.oneliner {{((VDI.$VBD | resolve).VM | resolve).name_label}}
span.pull-right.btn-group.quick-buttons
a(ng-if="(VDI.$VBD | resolve).attached", xo-click="disconnectVBD(VBD.id)")
i.fa.fa-unlink.fa-lg(tooltip="Disconnect this disk")
a(ng-if="!(VDI.$VBD | resolve).attached", xo-click="deleteVDI(VDI.id)")
i.fa.fa-trash-o.fa-lg(tooltip="Destroy this disk")
//- TODO: Ability to create new VDIs.
.center(ng-if = '(SR.VDIs | resolve).length > 10')
pagination(boundary-links="true", total-items="(SR.VDIs | resolve).length", ng-model="$parent.currentVDIPage", items-per-page="10", max-size="5", class="pagination-sm", previous-text="<", next-text=">", first-text="<<", last-text=">>")
.btn-form(ng-show="disksForm.$visible")
p.center
button.btn.btn-default(
type="reset"
ng-disabled="disksForm.$waiting"
ng-click="disksForm.$cancel()"
)
i.fa.fa-times
| Cancel
| &nbsp;
button.btn.btn-primary(
type="submit"
ng-disabled="disksForm.$waiting"
)
i.fa.fa-save
| Save
//- /VDIs.
//- Hosts.
.grid
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-link(style="color: #e25440;")
| Connected hosts
span.quick-edit(tooltip="Reconnect all hosts", ng-click="reconnectAllHosts()")
i.fa.fa-plus-square.fa-fw
.panel-body
table.table.table-hover
th Name
th Status
tr(ng-repeat="PBD in SR.$PBDs | resolve", xo-sref="hosts_view({id: (PBD.host | resolve).id})")
td {{(PBD.host | resolve).name_label}}
td(ng-if="PBD.attached")
span.label.label-success Connected
span.pull-right.btn-group.quick-buttons
a(xo-click="disconnectPBD(PBD.id)")
i.fa.fa-unlink.fa-lg(tooltip="Disconnect to this host")
td(ng-if="!PBD.attached")
span.label.label-default Disconnected
span.pull-right.btn-group.quick-buttons
a(xo-click="connectPBD(PBD.id)")
i.fa.fa-link.fa-lg(tooltip="Reconnect to this host")
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-comments(style="color: #e25440;")
| Logs
.panel-body
p.center(ng-if="SR.messages | isEmpty") No recent logs
table.table.table-hover(ng-if="SR.messages | isNotEmpty")
th.col-md-1 Date
th.col-md-1 Name
tr(ng-repeat="message in SR.messages | map | orderBy:'-time' | slice:(5*(currentLogPage-1)):(5*currentLogPage) track by message.id")
td {{message.time*1e3 | date:"medium"}}
td
| {{message.name}}
a.quick-remove(tooltip="Remove log")
i.fa.fa-trash-o.fa-fw
.center(ng-if = '(SR.messages | count) > 5')
pagination(boundary-links="true", total-items="SR.messages | count", ng-model="$parent.currentLogPage", items-per-page="5", max-size="5", class="pagination-sm", previous-text="<", next-text=">", first-text="<<", last-text=">>")
//- /Hosts.

View File

@@ -1,256 +0,0 @@
angular = require 'angular'
forEach = require 'lodash.foreach'
throttle = require 'lodash.throttle'
#=====================================================================
module.exports = angular.module 'xoWebApp.tree', [
require 'angular-file-upload'
require 'angular-ui-router'
require 'xo-api'
require 'xo-services'
require '../delete-vms'
]
.config ($stateProvider) ->
$stateProvider.state 'tree',
url: '/tree'
controller: 'TreeCtrl'
template: require './view'
.controller 'TreeCtrl', (
$scope
$upload
dateFilter
deleteVmsModal
modal
notify
xo
xoApi
) ->
$scope.stats = xoApi.stats
$scope.hosts = xoApi.getView('hosts')
$scope.hostsByPool = xoApi.getIndex('hostsByPool')
$scope.pools = xoApi.getView('pools')
VMs = $scope.VMs = xoApi.getView('VM')
$scope.runningVms = xoApi.getView('runningVms')
$scope.runningVmsByPool = xoApi.getIndex('runningVmsByPool')
$scope.vmsByPool = xoApi.getIndex('vmsByPool')
$scope.vmsByContainer = xoApi.getIndex('vmsByContainer')
$scope.vmControllersByContainer = xoApi.getIndex('vmControllersByContainer')
$scope.srsByContainer = xoApi.getIndex('srsByContainer')
$scope.pool_disconnect = xo.pool.disconnect
$scope.new_sr = xo.pool.new_sr
$scope.pool_addHost = (id) ->
xo.host.attach id
$scope.enableHost = (id) ->
xo.host.enable id
notify.info {
title: 'Host action'
message: 'Host is enabled'
}
$scope.disableHost = (id) ->
modal.confirm({
title: 'Disable host'
message: 'Are you sure you want to disable this host? In disabled state, no new VMs can be started and currently active VMs on the host continue to execute.'
}).then ->
xo.host.disable id
.then ->
notify.info {
title: 'Host action'
message: 'Host is disabled'
}
$scope.pool_removeHost = (id) ->
modal.confirm({
title: 'Remove host from pool'
message: 'Are you sure you want to detach this host from its pool? It will be automatically rebooted'
}).then ->
xo.host.detach id
$scope.rebootHost = (id) ->
modal.confirm({
title: 'Reboot host'
message: 'Are you sure you want to reboot this host? It will be disabled then rebooted'
}).then ->
xo.host.restart id
$scope.restartToolStack = (id) ->
modal.confirm({
title: 'Restart XAPI'
message: 'Are you sure you want to restart the XAPI toolstack?'
}).then ->
xo.host.restartToolStack id
$scope.shutdownHost = (id) ->
modal.confirm({
title: 'Shutdown host'
message: 'Are you sure you want to shutdown this host?'
}).then ->
xo.host.stop id
$scope.startHost = (id) ->
xo.host.start id
$scope.startVM = xo.vm.start
$scope.stopVM = xo.vm.stop
$scope.force_stopVM = (id) -> xo.vm.stop id, true
$scope.rebootVM = xo.vm.restart
$scope.force_rebootVM = (id) -> xo.vm.restart id, true
$scope.suspendVM = (id) -> xo.vm.suspend id, true
$scope.resumeVM = (id) -> xo.vm.resume id, true
$scope.migrateVM = (id, hostId) ->
(xo.vm.migrate id, hostId).catch (error) ->
modal.confirm
title: 'VM migrate'
message: 'This VM can\'t be migrated with Xen Motion to this host because they don\'t share any storage. Do you want to try a Xen Storage Motion?'
.then ->
notify.info {
title: 'VM migration'
message: 'The migration process started'
}
xo.vm.migratePool {
id
target_host_id: hostId
}
$scope.snapshotVM = (id) ->
vm = xoApi.get(id)
date = dateFilter Date.now(), 'yyyy-MM-ddTHH:mmZ'
snapshot_name = "#{vm.name_label}_#{date}"
xo.vm.createSnapshot id, snapshot_name
# check if there is any operation pending on a VM
$scope.isVMWorking = (VM) ->
return true for _ of VM.current_operations
false
$scope.deleteVMs = ->
{selected_VMs} = $scope
deleteVmsModal (id for id, selected of selected_VMs when selected)
# VMs checkboxes.
do ->
# This map marks which VMs are selected.
selected_VMs = $scope.selected_VMs = Object.create null
# Number of selected VMs.
$scope.n_selected_VMs = 0
# This is the master checkbox.
# Three states: true/false/null
$scope.master_selection = false
# Wheter all VMs are selected.
$scope.all = false
# Whether no VMs are selected.
$scope.none = true
# Updates `all`, `none` and `master_selection` when necessary.
$scope.$watch 'n_selected_VMs', (n) ->
$scope.all = (VMs.size is n)
$scope.none = (n is 0)
# When the master checkbox is clicked from indeterminate
# state, it should go to unchecked like Gmail.
$scope.master_selection = (n isnt 0)
make_matcher = (sieve) ->
(item) ->
for key, val of sieve
return false unless item[key] is val
true
$scope.selectVMs = (sieve) ->
if (sieve is true) or (sieve is false)
forEach(VMs.all, (VM) ->
selected_VMs[VM.id] = sieve
return
)
$scope.n_selected_VMs = if sieve then VMs.size else 0
return
matcher = make_matcher sieve
n = 0
forEach(VMs.all, (VM) ->
if (selected_VMs[VM.id] = matcher(VM))
++n
return
)
$scope.n_selected_VMs = n
$scope.updateVMSelection = (id) ->
if selected_VMs[id]
++$scope.n_selected_VMs
else
--$scope.n_selected_VMs
$scope.bulkAction = (action, args...) ->
fn = $scope[action]
unless angular.isFunction fn
throw new Error "invalid action #{action}"
for id, selected of selected_VMs
fn id, args... if selected
# Unselects all VMs.
$scope.selectVMs false
$scope.importVm = ($files, id) ->
file = $files[0]
notify.info {
title: 'VM import started'
message: "Starting the VM import"
}
xo.vm.import id
.then ({ $sendTo: url }) ->
return $upload.http {
method: 'POST'
url
data: file
}
.then (result) ->
throw result.status if result.status isnt 200
notify.info
title: 'VM import'
message: 'Success'
$scope.patchPool = ($files, id) ->
file = $files[0]
xo.pool.patch id
.then ({ $sendTo: url }) ->
return $upload.http {
method: 'POST'
url
data: file
}
.progress throttle(
(event) ->
percentage = (100 * event.loaded / event.total)|0
notify.info
title: 'Upload patch'
message: "#{percentage}%"
6e3
)
.then (result) ->
throw result.status if result.status isnt 200
notify.info
title: 'Upload patch'
message: 'Success'
# A module exports its name.
.name

View File

@@ -1,412 +0,0 @@
//- @todo Remove code duplication for the VMs listing by using a macro.
.sub-bar
.grid
.grid-cell.overview
//- Stats
i(tooltip="{{pools.size}} pools").hidden-xs
i.small {{pools.size}}x
| &nbsp;
i.xo-icon-pool
| &nbsp;
| &nbsp;
i(tooltip="{{hosts.size}} hosts").hidden-xs
i.small {{hosts.size}}x
| &nbsp;
i.xo-icon-host
| &nbsp;
| &nbsp;
i(tooltip="{{runningVms.size}} of {{VMs.size}} VMs running")
i.small {{runningVms.size}}x
| &nbsp;
i.xo-icon-vm
| &nbsp;
| &nbsp;
i(tooltip="{{stats.$vCPUs}} vCPUs used of {{stats.$CPUs}} CPUs")
i.small {{stats.$vCPUs}}x
| &nbsp;
i.xo-icon-cpu
| &nbsp;
| &nbsp;
i(tooltip="{{stats.$memory.usage | bytesToSize}} RAM allocated of {{stats.$memory.size | bytesToSize}}")
i.small {{stats.$memory.usage | bytesToSize}}
| &nbsp;
i.xo-icon-memory
.grid-cell
.btn-group.before-action-bar.dropdown(dropdown)
a.btn.navbar-btn.btn-default.dropdown-toggle.inversed(dropdown-toggle)
input.inverse(
type="checkbox",
ng-model="master_selection",
ng-change="selectVMs(master_selection)",
ui-indeterminate="!(all || none)", stop-event="click"
)
| &nbsp;
i.fa.fa-caret-down
ul.dropdown-menu.inverse(role="menu")
li(ng-repeat="power_state in ['Halted', 'Running']")
a(ng-click="selectVMs({power_state: power_state})")
i.fa-fw(class="xo-icon-{{power_state | lowercase}}")
| {{power_state}}
li.divider
li(
ng-if="hosts.size"
ng-repeat="host in hosts.all | map | orderBy:natural('name_label') track by host.id"
)
a(ng-click="selectVMs({$container: host.id})")
i.xo-icon-host.fa-fw
| On {{host.name_label}}
.action-bar(ng-if="!none")
| &nbsp;
.btn-group
button.btn.navbar-btn.btn-default.inversed(tooltip="Stop VM", type="button", ng-click="bulkAction('stopVM')")
i.fa.fa-stop
button.btn.navbar-btn.btn-default.inversed(tooltip="Start VM", type="button", ng-click="bulkAction('startVM')")
i.fa.fa-play
button.btn.navbar-btn.btn-default.inversed(tooltip="Reboot VM", type="button", ng-click="bulkAction('rebootVM')")
i.fa.fa-refresh
| &nbsp;
.btn-group.dropdown(dropdown)
button.btn.navbar-btn.btn-default.dropdown-toggle.inversed(
dropdown-toggle
tooltip="Migrate VM"
type="button"
)
i.fa.fa-share
| &nbsp;
i.fa.fa-caret-down
ul.dropdown-menu.inverse(role="menu")
li(ng-repeat="host in hosts.all | map | orderBy:natural('name_label') track by host.id")
a(ng-click="bulkAction('migrateVM', host.id)")
i.xo-icon-host.fa-fw
| To {{host.name_label}}
| &nbsp;
.btn-group.dropdown(dropdown)
button.btn.navbar-btn.btn-default.dropdown-toggle.inversed(
dropdown-toggle
type="button"
)
| More
| &nbsp;
i.fa.fa-caret-down
ul.dropdown-menu.inverse(role="menu")
li
a(ng-click="bulkAction('suspendVM')")
i.fa.fa-pause.fa-fw
| Suspend
li
a(ng-click="bulkAction('resumeVM')")
i.fa.fa-play.fa-fw
| Resume
li
a(ng-click="bulkAction('force_rebootVM')")
i.fa.fa-bolt.fa-fw
| Force reboot
li
a(ng-click="bulkAction('force_stopVM')")
i.fa.fa-power-off.fa-fw
| Force shutdown
li.divider
li
a(ng-click="bulkAction('snapshotVM')")
i.xo-icon-snapshot.fa-fw
| Take a snapshot
li
a(ng-click="deleteVMs()")
i.fa.fa-trash-o.fa-fw
| Delete
//- FIXME: Ugly trick to force the pools to be under the sub bar.
//- Add +7px to the 50px for having some space before the first pool.
div(style="margin-top: 57px; visibility: hidden; height: 0") .
//- If we haven't any data
div(ng-if="!pools.size")
.grid
.panel.panel-default.text-center
h1 Welcome on Xen Orchestra!
h3 It seems you aren't connected to any Xen server:
br
a.btn.btn-success.big(ui-sref="settings.index")
i.fa.fa-plus-circle
| Add server
br
br
br
p You can add a new host anytime by clicking on the menu icon "
i.fa.fa-th
| " and choose "
i.fa.fa-cog
| Settings"
p Enjoy Xen Orchestra!
//- If we have data
div(ng-if="pools.size")
//- Contains a pool and all its children (hosts).
.grid.pool-block(
ng-repeat="pool in pools.all | map | orderBy:[natural('name_label'), 'id'] track by pool.id"
)
//- Pseudo pool if it is not a named pool.
//- .grid-cell.grid--gutters.pool-cell(ng-if="!pool.name_label")
//- p.center(style="margin-top: 2em;") No pool connected
//- Contains information about the pool if it is a named pool.
.grid-cell.grid--gutters.pool-cell.hidden-xs
//- Header (name + dropdown menu).
.dropdown.dropdown-pool(dropdown)
a.pool-name(ui-sref="pools_view({id: pool.id})")
span(ng-if="pool.name_label")
| {{pool.name_label}}
span.text-muted(ng-if="!pool.name_label")
| {{(pool.master | resolve).name_label}}
a.dropdown-toggle(ng-if="pool.name_label", dropdown-toggle)
| &nbsp;
i.fa.fa-caret-down.big-caret
ul.dropdown-menu.left(role="menu")
//- TODO: remove until handled this properly
//- li
//- a(xo-sref="SRs_new({container: pool.id})")
//- i.xo-icon-sr.fa-fw
//- | Add SR
li
a(xo-sref="VMs_new({container: pool.id})")
i.xo-icon-vm.fa-fw
| Create VM
//- TODO: solve the "a" problem for ng-file-select
li(ng-file-select="patchPool($files, pool.id)")
a
i.fa.fa-file-code-o.fa-fw
| Patch
li.divider
li
a.disabled(xo-click="pool_disconnect(pool.id)")
i.fa.fa-unlink.fa-fw
| Disconnect
//- /Header.
//- Stats & SRs list.
div
//- Stats.
ul.list-unstyled.stats
li
i(tooltip="{{hostsByPool[pool.id] | count}} hosts connected")
i.small {{hostsByPool[pool.id] | count}}x
| &nbsp;
i.xo-icon-host
| &nbsp;
| &nbsp;
i(tooltip="{{runningVmsByPool[pool.id] | count}} of {{vmsByPool[pool.id] | count}} VMs running")
i.small {{runningVmsByPool[pool.id] | count}}x
| &nbsp;
i.xo-icon-vm
li(ng-if="pool.master")
| Master:
| &nbsp;
a(ui-sref="hosts_view({id: (pool.master | resolve).id})") {{(pool.master | resolve).name_label}}
//- /Stats.
//- SRs.
div(ng-if="!(srsByContainer[pool.id] | isEmpty)")
p.center.small-caps SRs:
table.table.table-hover.table-condensed
tr(ng-repeat="SR in srsByContainer[pool.id] | map | orderBy:natural('name_label') track by SR.id", xo-sref="SRs_view({id: SR.id})")
td.col-md-6.sr-name.no-border(ng-class="{'default-sr': SR.id === pool.default_SR}", title="{{SR.name_label}}")
i.xo-icon-sr
| {{SR.name_label}}
td.col-md-6.right.no-border
.progress.progress-small(tooltip="Disk: {{[SR.usage, SR.size] | percentage}} allocated")
.progress-bar(role="progressbar", aria-valuenow="{{100*SR.usage/SR.size}}", aria-valuemin="0", aria-valuemax="100", style="width: {{[SR.usage, SR.size] | percentage}}")
//- Contains all the hosts of this pool.
.grid-cell.grid--gutters.hosts-vms-cells
//- Contains a host and all its children (VMs).
.grid(ng-repeat="host in hostsByPool[pool.id] | map | orderBy:natural('name_label') track by host.id")
//- Contains information about the host.
.grid-cell.grid--gutters.host-cell
//- Header (name + dropdown menu).
.dropdown.dropdown-pool(dropdown)
a.host-name(ui-sref="hosts_view({id: host.id})")
| {{host.name_label}}
a.dropdown-toggle(dropdown-toggle)
| &nbsp;
i.fa.fa-caret-down
ul.dropdown-menu.left(role="menu")
li
a(xo-sref="SRs_new({container: host.id})")
i.xo-icon-sr.fa-fw
| Add SR
li
a(xo-sref="VMs_new({container: host.id})")
i.xo-icon-vm.fa-fw
| Create VM
//- TODO: solve the "a" problem for ng-file-select
li(ng-file-select="importVm($files, host.id)")
a
i.fa.fa-upload.fa-fw
| Import VM
li.divider
li
a(ng-repeat="controller in [vmControllersByContainer[host.id]] track by controller.id", xo-sref="consoles_view({id: controller.id})")
i.xo-icon-console.fa-fw
| Console
li(ng-if="!host.enabled")
a(xo-click="enableHost(host.id)")
i.fa.fa-check-circle.fa-fw
| Enable
li(ng-if="host.enabled")
a(xo-click="disableHost(host.id)")
i.fa.fa-times-circle.fa-fw
| Disable
li
a(xo-click="rebootHost(host.id)")
i.fa.fa-refresh.fa-fw
| Reboot
li(ng-if="host.power_state === 'Halted'")
a(xo-click="startHost(host.id)")
i.fa.fa-power-off.fa-fw
| Start
li(ng-if="host.power_state === 'Running'")
a(xo-click="shutdownHost(host.id)")
i.fa.fa-power-off.fa-fw
| Shutdown
li
a(xo-click="restartToolStack(host.id)")
i.fa.fa-retweet.fa-fw
| Restart toolstack
li(ng-if="pool.name_label")
a(xo-click="pool_removeHost(host.id)")
i.fa.fa-cloud-upload.fa-fw
| Remove from pool
li(ng-if="!pool.name_label")
a(xo-click="pool_addHost(host.id)")
i.fa.fa-cloud-download.fa-fw
| Add to pool
//- /Header.
//- Stats.
ul.list-unstyled.stats
//- Warning icon if host is halted or disabled
li.text-danger(ng-if="host.power_state === 'Halted'")
i.fa.fa-warning
| Halted
li.text-warning(ng-if="!host.enabled && host.power_state === 'Running'")
i.fa.fa-warning
| Disabled
//- Memory
li(ng-if="host.power_state === 'Running' && host.enabled")
i.xo-icon-memory.i-progress
.progress.progress-small(tooltip="RAM: {{[host.memory.usage, host.memory.size] | percentage}} allocated")
.progress-bar(role="progressbar", aria-valuenow="{{100*host.memory.usage/host.memory.size}}", aria-valuemin="0", aria-valuemax="100", style="width: {{[host.memory.usage, host.memory.size] | percentage}}")
//- Host address
li.text-muted.substats
i.xo-icon-network
| {{host.address}}
//- Contains all the VMs of this host.
.grid-cell.grid--gutters.vm-cell
//- If no VMs, fill the space with a message.
.vms-notice(ng-if="vmsByContainer[host.id] | isEmpty")
//- | Host halted.
p(ng-if="host.power_state === 'Halted'")
| Host halted.
div(ng-if="host.power_state === 'Running'")
p(ng-if="!host.enabled")
| Host disabled.
p(ng-if="host.enabled")
| No VMs on this host.
//- /Message if no VMs.
//- TODO: comment
.table-responsive(ng-if="!(vmsByContainer[host.id] | isEmpty)")
table.table.table-hover.table-condensed
//- Contains a VM.
tr(ng-repeat="VM in vmsByContainer[host.id] | map | orderBy:natural('name_label') track by VM.id", xo-sref="VMs_view({id: VM.id})")
//- Handle used for drag & drop.
td.grab
//- Checkbox used for selection.
td.select-vm
input(type="checkbox", ng-model="selected_VMs[VM.id]", ng-change="updateVMSelection(VM.id)")
//- Power state
td.vm-power-state
i.xo-icon-working(ng-if="isVMWorking(VM)", tooltip="{{VM.power_state}} and {{(VM.current_operations | map)[0]}}")
i(class="xo-icon-{{VM.power_state | lowercase}}",ng-if="!isVMWorking(VM)", tooltip="{{VM.power_state}}")
//- VM name.
td.vm-name.col-xs-8.col-sm-2.col-md-2
p.vm {{VM.name_label}}
//- Quick actions.
td.vm-quick-buttons.col-md-2.hidden-xs
.quick-buttons
a(tooltip="Shutdown VM", xo-click="stopVM(VM.id)")
i.fa.fa-stop
a(tooltip="Start VM", xo-click="startVM(VM.id)")
i.fa.fa-play
a(tooltip="Reboot VM", xo-click="rebootVM(VM.id)")
i.fa.fa-refresh
a(tooltip="VM Console", xo-sref="consoles_view({id: VM.id})")
i.xo-icon-console
//- Description.
td.vm-description.col-md-4.hidden-xs
i(class="xo-icon-{{VM.os_version.distro | osFamily}}",ng-if="VM.os_version.distro", tooltip="{{VM.os_version.name}}")
| &nbsp;
i.fa.fa-fw(ng-if="!VM.os_version.distro")
| {{VM.name_description}}
//- Metrics.
//- Memory
td.vm-memory-stat.col-md-2.hidden-xs
.cpu
| {{VM.memory.size | bytesToSize}}
i.xo-icon-docker.fa-fw(ng-if="VM.docker", tooltip="Docker enabled")
i.fa.fa-fw(ng-if="VM.PV_drivers && !VM.docker")
i.xo-icon-info.fa-fw(ng-if="!VM.PV_drivers", tooltip="Xen tools not installed")
//- /Metrics.
//- Address.
td.text-muted.text-right.col-md-2.hidden-xs
| {{VM.addresses["0/ip"]}}
//- Contains a pseudo-host which contains all VMs not in any hosts.
.grid(ng-if="!(vmsByPool[pool.id] | isEmpty)")
//- This is where the information about a host would be displayed.
.grid-cell.host-cell
//- Contains all the VMs of this pool.
.grid.grid-cell.vm-cell
//- TODO: comment
.table-responsive
table.table.table-hover.table-condensed
//- Contains a VM.
tr(ng-repeat="VM in vmsByContainer[pool.id] | map | orderBy:natural('name_label') track by VM.id", xo-sref="VMs_view({id: VM.id})")
//- Handle used for drag & drop.
td.grab
//- Checkbox used for selection.
td.select-vm
input(type="checkbox", ng-model="selected_VMs[VM.id]", ng-change="updateVMSelection(VM.id)")
//- Power state
td.vm-power-state
i.xo-icon-working(ng-if="isVMWorking(VM)", tooltip="{{VM.power_state}} and {{(VM.current_operations | map)[0]}}")
i(class="xo-icon-{{VM.power_state | lowercase}}",ng-if="!isVMWorking(VM)", tooltip="{{VM.power_state}}")
//- VM name.
td.vm-name.col-xs-8.col-sm-2.col-md-2
p.vm {{VM.name_label}}
//- Quick actions.
td.vm-quick-buttons.col-md-2.hidden-xs
.quick-buttons
a(tooltip="Shutdown VM", xo-click="stopVM(VM.id)")
i.fa.fa-stop
a(ng-if="VM.power_state == 'Suspended'", tooltip="Resume VM", xo-click="resumeVM(VM.id)")
i.fa.fa-play
a(ng-if="VM.power_state != 'Suspended'", tooltip="Start VM", xo-click="startVM(VM.id)")
i.fa.fa-play
a(tooltip="Reboot VM", xo-click="rebootVM(VM.id)")
i.fa.fa-refresh
a(tooltip="VM Console")
i.xo-icon-console
//- Description.
td.vm-description.col-md-4.hidden-xs
i(class="xo-icon-{{VM.os_version.distro | osFamily}}",ng-if="VM.os_version.distro", tooltip="{{VM.os_version.name}}")
| &nbsp;
i.fa.fa-fw(ng-if="!VM.os_version.distro")
| {{VM.name_description}}
//- Metrics.
//- Memory
td.vm-memory-stat.col-md-2.hidden-xs
.cpu
| {{VM.memory.size | bytesToSize}}
i.xo-icon-docker.fa-fw(ng-if="VM.docker", tooltip="Docker enabled")
i.fa.fa-fw(ng-if="VM.PV_drivers && !VM.docker")
i.xo-icon-info.fa-fw(ng-if="!VM.PV_drivers", tooltip="Xen tools not installed")
//- /Metrics.
//- Address.
td.text-muted.text-right.col-md-2.hidden-xs
| {{VM.addresses["0/ip"]}}
//- /Pseudo host containing VMs not on any hosts.
//- /Hosts of this pool.
//- /Pool with its children.

View File

@@ -1,343 +0,0 @@
import * as format from '@julien-f/json-rpc/format'
import angular from 'angular'
import Bluebird from 'bluebird'
import makeError from 'make-error'
import parse from '@julien-f/json-rpc/parse'
import WebSocket from 'ws'
import {EventEmitter} from 'events'
const calls = {}
function jsonRpcCall (socket, method, params = {}) {
const req = format.request(method, params)
const reqId = req.id
socket.send(JSON.stringify(req))
let waiter = {}
const promise = new Bluebird((resolve, reject) => {
waiter.resolve = resolve
waiter.reject = reject
})
calls[reqId] = waiter
return promise
}
function jsonRpcNotify (socket, method, params = {}) {
return Bluebird.resolve(socket.send(JSON.stringify(format.notification(method, params))))
}
function getCurrentUrl () {
if (typeof window === 'undefined') {
throw new Error('cannot get current URL')
}
return String(window.location)
}
function adaptUrl (url, port = null) {
const matches = /^http(s?):\/\/([^\/:]*(?::[^\/]*)?)(?:[^:]*)?$/.exec(url)
if (!matches || !matches[2]) {
throw new Error('current URL not recognized')
}
return 'ws' + matches[1] + '://' + matches[2] + '/api/updater'
}
function blockXoaAccess (xoaState) {
return xoaState.state === 'untrustedTrial'
}
export const NotRegistered = makeError('NotRegistered')
export const AuthenticationFailed = makeError('AuthenticationFailed')
export default angular.module('updater', [
// notify
])
.factory('updater', function ($interval, $timeout) {
class Updater extends EventEmitter {
constructor () {
super()
this._log = []
this._lastRun = 0
this._lowState = null
this.state = null
this.registerState = 'uknown'
this.registerError = ''
this._connection = null
this.isConnected = false
this.updating = false
this.upgrading = false
this.token = null
}
update () {
this.emit('updating')
this.updating = true
return this._update(false)
}
upgrade () {
this.emit('upgrading')
this.upgrading = true
return this._update(true)
.return(true)
}
_open () {
if (this._connection) {
return this._connection
} else {
this._connection = new Bluebird((resolve, reject) => {
const socket = new WebSocket(adaptUrl(getCurrentUrl()))
const middle = new EventEmitter()
this.isConnected = true
const timeout = $timeout(() => {
middle.emit('reconnect_failed')
}, 4000)
socket.onmessage = ({data}) => {
const message = parse(data)
if (message.type === 'response' && message.id !== undefined) {
if (calls[message.id]) {
if (message.result) {
calls[message.id].resolve(message.result)
} else {
calls[message.id].reject(message.error)
}
delete calls[message.id]
}
} else {
middle.emit(message.method, message.params)
}
}
socket.onclose = () => {
middle.emit('disconnect')
}
middle.on('connected', ({message}) => {
$timeout.cancel(timeout)
this.log('success', message)
this.state = 'connected'
resolve(socket)
if (!this.updating) {
this.update()
}
this.emit('connected', message)
})
middle.on('print', ({content}) => {
Array.isArray(content) || (content = [content])
content.forEach(elem => this.log('info', elem))
this.emit('print', content)
})
middle.on('end', end => {
this._lowState = end
switch (this._lowState.state) {
case 'xoa-up-to-date':
case 'xoa-upgraded':
case 'updater-upgraded':
this.state = 'upToDate'
break
case 'xoa-upgrade-needed':
case 'updater-upgrade-needed':
this.state = 'upgradeNeeded'
break
case 'register-needed':
this.state = 'registerNeeded'
break
case 'error':
this.state = 'error'
break
default:
this.state = null
}
this.log(end.level, end.message)
this._lastRun = Date.now()
this.upgrading = this.updating = false
this.emit('end', end)
if (this._lowState.state === 'updater-upgraded') {
this.update()
}
this.xoaState()
})
middle.on('warning', warning => {
this.log('warning', warning.message)
this.emit('warning', warning)
})
middle.on('server-error', error => {
this.log('error', error.message)
this._lowState = error
this.state = 'error'
this.upgrading = this.updating = false
this.emit('error', error)
})
middle.on('disconnect', () => {
this._lowState = null
this.state = null
this.upgrading = this.updating = false
this.log('warning', 'Lost connection with xoa-updater')
this.emit('disconnect')
middle.emit('reconnect_failed') // No reconnecting attempts implemented so far
})
middle.on('reconnect_failed', () => {
this.isConnected = false
middle.removeAllListeners()
socket.close()
this._connection = null
const message = 'xoa-updater could not be reached'
this._xoaStateError({message})
reject(new Error(message))
this.log('error', message)
this.emit('reconnect_failed')
})
})
return this._connection
}
}
isRegistered () {
return this._open()
.then(socket => {
return jsonRpcCall(socket, 'isRegistered')
.then(token => {
if (token.registrationToken === undefined) {
throw new NotRegistered('Your Xen Orchestra Appliance is not registered')
} else {
this.registerState = 'registered'
this.token = token
return token
}
})
})
.catch(NotRegistered, () => this.registerState = 'unregistered')
.catch(error => {
this.registerError = error.message
this.registerState = 'error'
})
}
register (email, password) {
return this._open()
.then(socket => {
return jsonRpcCall(socket, 'register', {email, password})
.then(token => {
this.registerState = 'registered'
this.token = token
return token
})
})
.catch(error => {
if (error.code && error.code === 1) {
this.registerError = 'Authentication failed'
throw new AuthenticationFailed('Authentication failed')
} else {
this.registerError = error.message
this.registerState = 'error'
}
})
}
xoaState () {
return this._open()
.then(socket => {
return jsonRpcCall(socket, 'xoaState')
.then(state => {
this._xoaState = state
this._xoaStateTS = Date.now()
return state
})
})
.catch(error => this._xoaStateError(error))
}
_xoaStateError (error) {
this._xoaState = {
state: 'ERROR',
message: error.message
}
this._xoaStateTS = Date.now()
return this._xoaState
}
_update (upgrade = false) {
return this._open()
.tap(() => this.log('info', 'Start ' + (upgrade ? 'upgrading' : 'updating' + '...')))
.then(socket => jsonRpcNotify(socket, 'update', {upgrade}))
}
start () {
if (!this._xoaState) {
this.xoaState()
}
if (!this._interval) {
this._interval = $interval(() => this.run(), 60 * 60 * 1000)
return this.run()
} else {
return Bluebird.resolve()
}
}
stop () {
if (this._interval) {
$interval.cancel(this._interval)
delete this._interval
}
}
run () {
if (Date.now() - this._lastRun < 24 * 60 * 60 * 1000) {
return Bluebird.resolve()
} else {
return this.update()
}
}
isStarted () {
return this._interval !== null
}
log (level, message) {
const date = new Date()
this._log.unshift({
date: date.toLocaleString(),
level,
message
})
while (this._log.length > 10) {
this._log.pop()
}
}
getConfiguration () {
return this._open()
.then(socket => {
return jsonRpcCall(socket, 'getConfiguration')
.then(configuration => this._configuration = configuration)
})
}
configure (config) {
return this._open()
.then(socket => {
return jsonRpcCall(socket, 'configure', config)
.then(configuration => this._configuration = configuration)
})
}
}
return new Updater()
})
.run(function (updater, $rootScope, $state, xoApi) {
updater.start()
.catch(() => {})
$rootScope.$on('$stateChangeStart', function (event, state) {
if (Date.now() - updater._xoaStateTS > (60 * 60 * 1000)) {
updater.xoaState()
}
let {user} = xoApi
let loggedIn = !!user
if (!loggedIn || !updater._xoaState || state.name === 'settings.update') {
return
} else if (blockXoaAccess(updater._xoaState)) {
event.preventDefault()
$state.go('settings.update')
}
})
})
.name

View File

@@ -1,766 +0,0 @@
angular = require 'angular'
forEach = require 'lodash.foreach'
isEmpty = require 'lodash.isempty'
_difference = require 'lodash.difference'
_sortBy = require 'lodash.sortby'
isoDevice = require('../iso-device')
#=====================================================================
module.exports = angular.module 'xoWebApp.vm', [
require 'angular-ui-router',
require 'angular-ui-bootstrap'
isoDevice
]
.config ($stateProvider) ->
$stateProvider.state 'VMs_view',
url: '/vms/:id'
controller: 'VmCtrl'
template: require './view'
.controller 'VmCtrl', (
$scope, $state, $stateParams, $location, $q
xoApi, xo
sizeToBytesFilter, bytesToSizeFilter
modal
$window
$timeout
dateFilter
notify
) ->
$window.bytesToSize = bytesToSizeFilter # FIXME dirty workaround to custom a Chart.js tooltip template
{get} = xoApi
merge = do ->
push = Array::push.apply.bind Array::push
(args...) ->
result = []
for arg in args
push result, arg if arg?
result
$scope.currentLogPage = 1
$scope.currentSnapPage = 1
$scope.currentPCIPage = 1
$scope.currentGPUPage = 1
$scope.refreshStatControl = refreshStatControl = {
baseStatInterval: 5000
baseTimeOut: 10000
period: null
running: false
attempt: 0
start: () ->
return if this.running
this.stop()
this.running = true
this._reset()
$scope.$on('$destroy', () => this.stop())
return this._trig(Date.now())
_trig: (t1) ->
if this.running
timeoutSecurity = $timeout(
() => this.stop(),
this.baseTimeOut
)
return $scope.refreshStats($scope.VM.id)
.then () => this._reset()
.catch (err) =>
if !this.running || this.attempt >= 2 || $scope.VM.power_state isnt 'Running' || $scope.isVMWorking($scope.VM)
return this.stop()
else
this.attempt++
.finally () =>
$timeout.cancel(timeoutSecurity)
if this.running
t2 = Date.now()
return this.period = $timeout(
() => this._trig(t2),
Math.max(this.baseStatInterval - (t2 - t1), 0)
)
_reset: () ->
this.attempt = 0
stop: () ->
if this.period
$timeout.cancel(this.period)
this.running = false
return
}
$scope.hosts = xoApi.getView('hosts')
networksByPool = xoApi.getIndex('networksByPool')
srsByContainer = xoApi.getIndex('srsByContainer')
$scope.$watch(
-> get $stateParams.id, 'VM'
(VM) ->
$scope.VM = VM
return unless VM?
# For the edition of this VM.
$scope.memorySize = bytesToSizeFilter VM.memory.size
$scope.bootParams = parseBootParams($scope.VM.boot.order)
# build VDI list of this VM
mountedIso = ''
VDIs = []
for VBD in VM.$VBDs
oVbd = get VBD
continue unless oVbd
oVdi = get oVbd.VDI
continue unless oVdi
VDIs.push oVdi if oVdi and not oVbd.is_cd_drive
if oVbd.is_cd_drive and oVdi # "Load" the cd drive
mountedIso = oVdi.id
$scope.VDIs = _sortBy(VDIs, (value) -> (get resolveVBD(value))?.position);
container = get VM.$container
if container.type is 'host'
host = container
pool = (get container.$poolId) ? {}
else
host = {}
pool = container
$scope.networks = networksByPool[pool.id]
# Computes the list of srs.
SRs = $scope.SRs = []
forEach(srsByContainer[host.id], (template) =>
SRs.push(template)
return
)
forEach(srsByContainer[pool.id], (template) =>
SRs.push(template)
return
)
# compute writable accessible SR from this VM
$scope.writable_SRs = (SR for SR in SRs when SR.content_type isnt 'iso')
prepareDiskData mountedIso
if VM.power_state is 'Running' && !($scope.isVMWorking($scope.VM))
refreshStatControl.start()
else
refreshStatControl.stop()
)
descriptor = (obj) ->
return obj.name_label + (if obj.name_description.length then ' - ' + obj.name_description else '')
prepareDiskData = (mounted) ->
# For populating adding position choice
unfreePositions = [];
maxPos = 0;
# build VDI list of this VM
for VBD in $scope.VM.$VBDs
oVbd = get VBD
oVdi = get oVbd?.VDI
if oVdi?
unfreePositions.push parseInt oVbd.position
maxPos = if (oVbd.position > maxPos) then parseInt oVbd.position else maxPos
# $scope.vdiFreePos = _difference([0..++maxPos], unfreePositions)
$scope.maxPos = maxPos
$scope.VDIOpts = []
ISOOpts = []
for SR in $scope.SRs
if 'iso' isnt SR.SR_type
for rVdi in SR.VDIs
oVdi = get rVdi
$scope.VDIOpts.push({
sr: descriptor(SR),
label: descriptor(oVdi),
vdi: oVdi
})
else
for rIso in SR.VDIs
oIso = get rIso
ISOOpts.push({
sr: SR.name_label,
label: descriptor(oIso),
iso: oIso
})
$scope.isoDeviceData = {
opts: ISOOpts
mounted
}
parseBootParams = (params) ->
texts = {
c: 'Hard-Drive',
d: 'DVD-Drive',
n: 'Network'
}
bootParams = []
i = 0
if params
while (i < params.length)
char = params.charAt(i++)
bootParams.push({
e: char,
t: texts[char],
v: true
})
delete texts[char]
for key, text of texts
bootParams.push({
e: key,
t: text,
v: false
})
return bootParams
$scope.bootMove = (index, move) ->
tmp = $scope.bootParams[index + move]
$scope.bootParams[index + move] = $scope.bootParams[index]
$scope.bootParams[index] = tmp
$scope.saveBootParams = (id, bootParams) ->
if $scope.savingBootOrder
return
$scope.savingBootOrder = true
paramString = ''
forEach(bootParams, (boot) -> boot.v && paramString += boot.e)
return xoApi.call 'vm.bootOrder', {vm: id, order: paramString}
.finally () ->
$scope.savingBootOrder = false
$scope.bootReordering = false
$scope.refreshStats = (id) ->
return xo.vm.refreshStats id
.then (result) ->
result.cpuSeries = []
forEach result.cpus, (v,k) ->
result.cpuSeries.push 'CPU ' + k
return
result.vifSeries = []
forEach result.vifs, (v,k) ->
result.vifSeries.push '#' + Math.floor(k/2) + ' ' + if k % 2 then 'out' else 'in'
return
result.xvdSeries = []
forEach result.xvds, (v,k) ->
# 97 is ascii code of 'a'
result.xvdSeries.push 'xvd' + String.fromCharCode(Math.floor(k/2) + 97, ) + ' ' + if k % 2 then 'write' else 'read'
return
forEach result.date, (v,k) ->
result.date[k] = new Date(v*1000).toLocaleTimeString()
$scope.stats = result
$scope.startVM = (id) ->
xo.vm.start id
notify.info {
title: 'VM starting...'
message: 'Start VM'
}
$scope.stopVM = (id) ->
xo.vm.stop id
notify.info {
title: 'VM shutdown...'
message: 'Gracefully shutdown the VM'
}
$scope.force_stopVM = (id) ->
xo.vm.stop id, true
notify.info {
title: 'VM force shutdown...'
message: 'Force shutdown the VM'
}
$scope.rebootVM = (id) ->
xo.vm.restart id
notify.info {
title: 'VM reboot...'
message: 'Gracefully reboot the VM'
}
$scope.force_rebootVM = (id) ->
xo.vm.restart id, true
notify.info {
title: 'VM reboot...'
message: 'Force reboot the VM'
}
$scope.suspendVM = (id) ->
xo.vm.suspend id, true
notify.info {
title: 'VM suspend...'
message: 'Suspend the VM'
}
$scope.resumeVM = (id) ->
xo.vm.resume id, true
notify.info {
title: 'VM resume...'
message: 'Resume the VM'
}
$scope.migrateVM = (id, hostId) ->
(xo.vm.migrate id, hostId).catch (error) ->
modal.confirm
title: 'VM migrate'
message: 'This VM can\'t be migrated with Xen Motion to this host because they don\'t share any storage. Do you want to try a Xen Storage Motion?'
.then ->
notify.info {
title: 'VM migration'
message: 'The migration process started'
}
xo.vm.migratePool {
id
target_host_id: hostId
}
$scope.destroyVM = (id) ->
modal.confirm
title: 'VM deletion'
message: 'Are you sure you want to delete this VM? (including its disks)'
.then ->
# FIXME: provides a way to not delete its disks.
xo.vm.delete id, true
.then ->
$state.go 'index'
notify.info {
title: 'VM deletion'
message: 'VM is removed'
}
$scope.saveSnapshot = (id, $data) ->
snapshot = get (id)
result = {
id: snapshot.id
name_label: $data
}
if $data isnt snapshot.name_label
result.name_label = $data
xoApi.call 'vm.set', result
$scope.saveVM = ($data) ->
{VM} = $scope
{CPUs, memory, name_label, name_description, high_availability, auto_poweron} = $data
$data = {
id: VM.id
}
if memory isnt $scope.memorySize and (memory = sizeToBytesFilter memory)
$data.memory = memory
$scope.memorySize = bytesToSizeFilter memory
if CPUs isnt VM.CPUs.number
$data.CPUs = +CPUs
if name_label isnt VM.name_label
$data.name_label = name_label
if name_description isnt VM.name_description
$data.name_description = name_description
if high_availability isnt VM.high_availability
$data.high_availability = high_availability
if auto_poweron isnt VM.auto_poweron
$data.auto_poweron = auto_poweron
xoApi.call 'vm.set', $data
#-----------------------------------------------------------------
# Disks
#-----------------------------------------------------------------
# TODO: implement in XO-Server.
$scope.moveDisk = (index, direction) ->
{VDIs} = $scope
newIndex = index + direction
[VDIs[index], VDIs[newIndex]] = [VDIs[newIndex], VDIs[index]]
return
migrateDisk = (id, sr_id) ->
return modal.confirm({
title: 'Disk migration'
message: 'Are you sure you want to migrate (move) this disk to another SR?'
}).then ->
notify.info {
title: 'Disk migration'
message: 'Disk migration started'
}
xo.vdi.migrate id, sr_id
return
$scope.saveDisks = (data) ->
# Group data by disk.
disks = {}
forEach data, (value, key) ->
i = key.indexOf '/'
(disks[key.slice 0, i] ?= {})[key.slice i + 1] = value
return
promises = []
# Handle SR change.
forEach disks, (attributes, id) ->
disk = get id
if attributes.$SR isnt disk.$SR
promises.push (migrateDisk id, attributes.$SR)
return
forEach disks, (attributes, id) ->
# Keep only changed attributes.
disk = get id
forEach attributes, (value, name) ->
delete attributes[name] if value is disk[name]
return
unless isEmpty attributes
# Inject id.
attributes.id = id
# Ask the server to update the object.
promises.push xoApi.call 'vdi.set', attributes
return
# Handle Position changes
vbds = xoApi.get($scope.VM.$VBDs)
notFreePositions = Object.create(null)
forEach vbds, (vbd) ->
if vbd.is_cd_drive
notFreePositions[vbd.position] = null
position = 0
forEach $scope.VDIs, (vdi) ->
oVbd = get(resolveVBD(vdi))
unless oVbd
return
while position of notFreePositions
++position
if +oVbd.position isnt position
promises.push(
xoApi.call('vbd.set', {
id: oVbd.id,
position: String(position)
})
)
++position
return $q.all promises
.catch (err) ->
console.log(err);
notify.error {
title: 'saveDisks'
message: err
}
$scope.deleteDisk = (id) ->
modal.confirm({
title: 'Disk deletion'
message: 'Are you sure you want to delete this disk? This operation is irreversible'
}).then ->
xoApi.call 'vdi.delete', {id: id}
return
return
#-----------------------------------------------------------------
# returns the id of the VBD that links the VDI to the VM
$scope.resolveVBD = resolveVBD = (vdi) ->
if not vdi?
return
for vbd in vdi.$VBDs
rVbd = vbd if (get vbd).VM is $scope.VM.id
return rVbd || null
$scope.disconnectVBD = (vdi) ->
id = resolveVBD(vdi)
if id?
console.log "Disconnect VBD #{id}"
xo.vbd.disconnect id
$scope.connectVBD = (vdi) ->
id = resolveVBD(vdi)
if id?
console.log "Connect VBD #{id}"
xo.vbd.connect id
$scope.deleteVBD = (vdi) ->
id = resolveVBD(vdi)
if id?
console.log "Delete VBD #{id}"
modal.confirm({
title: 'VBD deletion'
message: 'Are you sure you want to delete this VM disk attachment (the disk will NOT be destroyed)?'
}).then ->
xo.vbd.delete id
$scope.connectVIF = (id) ->
console.log "Connect VIF #{id}"
xo.vif.connect id
$scope.disconnectVIF = (id) ->
console.log "Disconnect VIF #{id}"
xo.vif.disconnect id
$scope.deleteVIF = (id) ->
console.log "Delete VIF #{id}"
modal.confirm({
title: 'VIF deletion'
message: 'Are you sure you want to delete this Virtual Interface (VIF)?'
}).then ->
xo.vif.delete id
$scope.cloneVM = (id, vm_name, full_copy) ->
clone_name = "#{vm_name}_clone"
console.log "Copy VM #{id} #{clone_name} with full copy at #{full_copy}"
notify.info {
title: 'Clone creation'
message: 'Clone creation started'
}
xo.vm.clone id, clone_name, full_copy
$scope.snapshotVM = (id, vm_name) ->
date = dateFilter Date.now(), 'yyyy-MM-ddTHH:mmZ'
snapshot_name = "#{vm_name}_#{date}"
console.log "Snapshot #{snapshot_name} from VM #{id}"
notify.info {
title: 'Snapshot creation'
message: 'Snapshot creation started'
}
xo.vm.createSnapshot id, snapshot_name
$scope.exportVM = (id) ->
console.log "Export VM #{id}"
notify.info {
title: 'VM export'
message: 'VM export started'
}
xo.vm.export id
.then ({$getFrom: url}) ->
window.open url
$scope.convertVM = (id) ->
console.log "Convert VM #{id}"
modal.confirm({
title: 'VM to template'
message: 'Are you sure you want to convert this VM into a template?'
}).then ->
xo.vm.convert id
$scope.deleteSnapshot = (id) ->
console.log "Delete snapshot #{id}"
modal.confirm({
title: 'Snapshot deletion'
message: 'Are you sure you want to delete this snapshot? (including its disks)'
}).then ->
# FIXME: provides a way to not delete its disks.
xo.vm.delete id, true
$scope.connectPci = (id, pciId) ->
console.log "Connect PCI device "+pciId+" on VM "+id
xo.vm.connectPci id, pciId
$scope.disconnectPci = (id) ->
xo.vm.disconnectPci id
$scope.deleteAllLog = ->
modal.confirm({
title: 'Log deletion'
message: 'Are you sure you want to delete all the logs?'
}).then ->
forEach($scope.VM.messages, (log) =>
console.log "Remove log #{log.id}"
xo.log.delete log.id
return
)
$scope.deleteLog = (id) ->
console.log "Remove log #{id}"
xo.log.delete id
$scope.revertSnapshot = (id) ->
console.log "Revert snapshot to #{id}"
modal.confirm({
title: 'Revert to snapshot'
message: 'Are you sure you want to revert your VM to this snapshot? The VM will be halted and this operation is irreversible'
}).then ->
notify.info {
title: 'Reverting to snapshot'
message: 'VM revert started'
}
xo.vm.revert id
$scope.isVMWorking = (VM) ->
return false unless VM
return true for _ of VM.current_operations
false
$scope.startContainer = (VM,container) ->
console.log "Start from VM "+VM+" to container "+container
xo.docker.start VM, container
$scope.stopContainer = (VM,container) ->
console.log "Stop from VM "+VM+" to container "+container
xo.docker.stop VM, container
$scope.restartContainer = (VM,container) ->
console.log "Restart from VM "+VM+" to container "+container
xo.docker.restart VM, container
$scope.pauseContainer = (VM,container) ->
console.log "Pause from VM "+VM+" to container "+container
xo.docker.pause VM, container
$scope.resumeContainer = (VM,container) ->
console.log "Unpause from VM "+VM+" to container "+container
xo.docker.unpause VM, container
$scope.addVdi = (vdi, readonly, bootable) ->
$scope.addWaiting = true # disables form fields
position = $scope.maxPos + 1
params = {
bootable
mode : if (readonly || !isFreeForWriting(vdi)) then 'RO' else 'RW'
position: String(position)
vdi: vdi.id
vm: $scope.VM.id
}
console.log(params)
return xoApi.call 'vm.attachDisk', params
.then -> $scope.adding = false # Closes form block
.catch (err) ->
console.log(err);
notify.error {
title: 'vm.attachDisk'
message: err
}
.finally ->
$scope.addWaiting = false
$scope.isConnected = isConnected = (vdi) -> (get resolveVBD(vdi))?.attached
$scope.isFreeForWriting = isFreeForWriting = (vdi) ->
free = true
for vbd in vdi.$VBDs
oVbd = get vbd
free = free && (!oVbd?.attached || oVbd?.read_only)
return free
$scope.createVdi = (name, size, sr, bootable, readonly) ->
$scope.createVdiWaiting = true # disables form fields
position = $scope.maxPos + 1
params = {
name
size: String(size)
sr
}
# console.log(params)
return xoApi.call 'disk.create', params
.then (diskUuid) ->
params = {
bootable,
mode: if readonly then 'RO' else 'RW'
position: String(position)
vdi: diskUuid
vm: $scope.VM.id
}
# console.log(params)
return xoApi.call 'vm.attachDisk', params
.then -> $scope.creatingVdi = false # Closes form block
.catch (err) ->
console.log(err);
notify.error {
title: 'Attach Disk'
message: err
}
.catch (err) ->
console.log(err);
notify.error {
title: 'Create Disk'
message: err
}
.finally ->
$scope.createVdiWaiting = false
$scope.updateMTU = (network) ->
$scope.newInterfaceMTU = network.MTU
$scope.createInterface = (network, mtu, automac, mac) ->
$scope.createVifWaiting = true # disables form fields
position = 0
forEach $scope.VM.VIFs, (vf) ->
int = get vf
position = if int?.device > position then (get vf)?.device else position
position++
params = {
vm: $scope.VM.id
network: network.id
position: String(position) # TODO
mtu: String(mtu) || String(network.mtu)
}
if !automac
params.mac = mac
# console.log(params)
return xoApi.call 'vm.createInterface', params
.then (id) ->
$scope.creatingVif = false
# console.log(id)
xoApi.call 'vif.connect', {id}
.catch (err) ->
console.log(err);
notify.error {
title: 'Create Interface'
message: err
}
.finally ->
$scope.createVifWaiting = false
$scope.statView = {
cpuOnly: false,
ramOnly: false,
netOnly: false,
diskOnly: false
}
# A module exports its name.
.name

View File

@@ -1,771 +0,0 @@
.grid
.panel.panel-default
p.page-title
i.xo-icon-vm(ng-if="isVMWorking(VM)", class="xo-color-pending", tooltip="{{VM.power_state}} and {{(VM.current_operations | map)[0]}}")
i.xo-icon-vm(class="xo-color-{{VM.power_state | lowercase}}",ng-if="!isVMWorking(VM)", tooltip="{{VM.power_state}}")
| {{VM.name_label}}
.grid
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-cogs(style="color: #e25440;")
| General
span.quick-edit(tooltip="Edit General settings", ng-click="vmSettings.$show()")
i.fa.fa-edit.fa-fw
.panel-body
form(editable-form="", name="vmSettings", onbeforesave="saveVM($data)")
dl.dl-horizontal
dt Name
dd
span(editable-text="VM.name_label", e-name="name_label", e-form="vmSettings")
| {{VM.name_label}}
dt Description
dd
span(editable-text="VM.name_description", e-name="name_description", e-form="vmSettings")
| {{VM.name_description}}
dt(ng-if="VM.power_state === 'Running' || VM.power_state === 'Paused'") Running on
dt(ng-if="VM.power_state == 'Halted' || VM.power_state === 'Suspended'") Resident on
dd(ng-repeat="container in [VM.$container] | resolve")
span(ng-if = 'container.type === "host"')
a(xo-sref="hosts_view({id: container.id})")
| {{container.name_label}}
small
span(ng-if="(container.$poolId | resolve).name_label")
| (
a(ui-sref="pools_view({id: (container.$poolId | resolve).id})") {{(container.$poolId | resolve).name_label}}
| )
a(
ng-if = 'container.type === "pool"'
xo-sref="pools_view({id: container.id})"
)
| {{container.name_label}}
dt Addresses
dd(ng-if="!VM.addresses") -
dd(ng-repeat="IP in VM.addresses") {{IP}}
dt(ng-if="!(VM.$poolId | resolve).HA_enabled") Auto Power
dd(ng-if="!(VM.$poolId | resolve).HA_enabled")
span(
editable-select="VM.auto_poweron"
e-ng-options="ap.v as ap.t for ap in [{v: true, t:'Yes'}, {v: false, t:'No'}]"
e-name="auto_poweron"
e-form="vmSettings"
)
| {{VM.auto_poweron ? 'Yes' : 'No'}}
dt(ng-if="(VM.$poolId | resolve).HA_enabled") HA
dd(ng-if="(VM.$poolId | resolve).HA_enabled")
span(
editable-checkbox="VM.high_availability"
e-name="high_availability"
e-form="vmSettings"
)
| {{VM.high_availability}}
dt vCPUs
dd
span(
editable-text="VM.CPUs.number"
e-name="CPUs"
e-form="vmSettings"
)
| {{VM.CPUs.number}}
dt RAM
dd
span(
editable-text="memorySize"
e-name="memory"
e-form="vmSettings"
)
| {{memorySize}}
dt UUID
dd {{VM.UUID}}
dt(ng-if="refreshStatControl.running && stats") Xen tools
dd(ng-if="refreshStatControl.running && stats")
span(ng-if="VM.PV_drivers", style="color:green;") Installed
span(ng-if="!VM.PV_drivers") NOT installed
dt(ng-if="refreshStatControl.running && stats && VM.os_version") OS
dd(ng-if="refreshStatControl.running && stats && VM.os_version")
| {{VM.os_version.name}} ({{VM.os_version.distro}})
dt(ng-if="refreshStatControl.running && stats && VM.os_version") Kernel
dd(ng-if="refreshStatControl.running && stats && VM.os_version")
| {{VM.os_version.uname}}
.btn-form(ng-show="vmSettings.$visible")
p.center
button.btn.btn-default(
type="button"
ng-disabled="vmSettings.$waiting"
ng-click="vmSettings.$cancel()"
)
i.fa.fa-times
| Cancel
| &nbsp;
button.btn.btn-primary(
type="submit"
ng-disabled="vmSettings.$waiting"
)
i.fa.fa-save
| Save
.panel.panel-default.panel-height.center
.panel-heading.panel-title
i.xo-icon-stats(style="color: #e25440;", xo-click="refreshStats(VM.id)")
| Stats
.panel-body-stats(ng-if="refreshStatControl.running && stats")
div(ng-if="statView.cpuOnly", ng-click="statView.cpuOnly = false")
p.stat-name
i.fa.fa-tachometer
| &nbsp; CPU usage
canvas.chart.chart-line.chart-stat-full(
id="bigCpu"
data="stats.cpus"
labels="stats.date"
series="stats.cpuSeries"
colours="['#0000ff', '#9999ff', '#000099', '#5555ff', '#000055']"
legend="true"
options='{responsive: true, maintainAspectRatio: false, tooltipTemplate: "<%if (label){%><%=label%>: <%}%><%= Math.round(10*value)/10 %>", multiTooltipTemplate:"<%if (datasetLabel){%><%=datasetLabel%>: <%}%><%= Math.round(10*value)/10 %>", pointDot: false, showScale: false, animation: false, datasetStrokeWidth: 0.8, scaleOverride: true, scaleSteps: 100, scaleStartValue: 0, scaleStepWidth: 1, pointHitDetectionRadius: 0}'
)
div(ng-if="statView.ramOnly", ng-click="statView.ramOnly = false")
p.stat-name
//- i.fa.fa-bar-chart
i.fa.fa-tasks
//- i.fa.fa-server
| &nbsp; RAM usage
canvas.chart.chart-line.chart-stat-full(
id="bigRam"
data="[stats.memoryUsed,stats.memory]"
labels="stats.date"
series="['Used RAM', 'Total RAM']"
colours="['#ff0000', '#ffbbbb']"
legend="true"
options='{responsive: true, maintainAspectRatio: false, tooltipTemplate: "<%if (label){%><%=label%>: <%}%><%= bytesToSize(value) %>", multiTooltipTemplate:"<%if (datasetLabel){%><%=datasetLabel%>: <%}%><%= bytesToSize(value) %>", datasetStrokeWidth: 0.8, pointDot: false, showScale: false, scaleBeginAtZero: true, animation: false, pointHitDetectionRadius: 0}'
)
div(ng-if="statView.netOnly", ng-click="statView.netOnly = false")
p.stat-name
i.fa.fa-sitemap
| &nbsp; Network I/O
canvas.chart.chart-line.chart-stat-full(
id="bigNet"
data="stats.vifs"
labels="stats.date"
series="stats.vifSeries"
colours="['#dddd00', '#dddd77', '#777700', '#dddd55', '#555500', '#ffdd00']"
legend="true"
options='{responsive: true, maintainAspectRatio: false, tooltipTemplate: "<%if (label){%><%=label%>: <%}%><%= bytesToSize(value) %>", multiTooltipTemplate:"<%if (datasetLabel){%><%=datasetLabel%>: <%}%><%= bytesToSize(value) %>", datasetStrokeWidth: 0.8, pointDot: false, showScale: false, scaleBeginAtZero: true, animation: false, pointHitDetectionRadius: 0}'
)
div(ng-if="statView.diskOnly", ng-click="statView.diskOnly = false")
p.stat-name
i.fa.fa-hdd-o
| &nbsp; Disk I/O
canvas.chart.chart-line.chart-stat-full(
id="bigDisk"
data="stats.xvds"
labels="stats.date"
series="stats.xvdSeries"
colours="['#00dd00', '#77dd77', '#007700', '#33dd33', '#003300']"
legend="true"
options='{responsive: true, maintainAspectRatio: false, multiTooltipTemplate:"<%if (datasetLabel){%><%=datasetLabel%>: <%}%><%= bytesToSize(value) %>", datasetStrokeWidth: 0.8, pointDot: false, showScale: false, scaleBeginAtZero: true, animation: false, pointHitDetectionRadius: 0}'
)
div(ng-if="!statView.netOnly && !statView.diskOnly && !statView.cpuOnly && !statView.ramOnly")
.row
.col-sm-6(ng-click="statView.cpuOnly=true")
p.stat-name
i.fa.fa-tachometer
| &nbsp; CPU usage
canvas.chart.chart-line.chart-stat-preview(
id="smallCpu"
data="stats.cpus"
labels="stats.date"
series="stats.cpuSeries"
colours="['#0000ff', '#9999ff', '#000099', '#5555ff', '#000055']"
options="{responsive: true, maintainAspectRatio: false, showTooltips: false, pointDot: false, showScale: false, animation: false, datasetStrokeWidth: 0.8, scaleOverride: true, scaleSteps: 100, scaleStartValue: 0, scaleStepWidth: 1}"
)
.col-sm-6(ng-click="statView.ramOnly=true")
p.stat-name
//- i.fa.fa-bar-chart
i.fa.fa-tasks
//- i.fa.fa-server
| &nbsp; RAM usage
canvas.chart.chart-line.chart-stat-preview(
id="smallRam"
data="[stats.memoryUsed,stats.memory]"
labels="stats.date"
series="['Used RAM', 'Total RAM']"
colours="['#ff0000', '#ffbbbb']"
options="{responsive: true, maintainAspectRatio: false, showTooltips: false, datasetStrokeWidth: 0.8, pointDot: false, showScale: false, scaleBeginAtZero: true, animation: false}"
)
.row
.col-sm-6(ng-click="statView.netOnly=true")
p.stat-name
i.fa.fa-sitemap
| &nbsp; Network I/O
canvas.chart.chart-line.chart-stat-preview(
id="smallNet"
data="stats.vifs"
labels="stats.date"
series="stats.vifSeries"
colours="['#dddd00', '#dddd77', '#777700', '#dddd55', '#555500', '#ffdd00']"
options="{responsive: true, maintainAspectRatio: false, showTooltips: false, datasetStrokeWidth: 0.8, pointDot: false, showScale: false, scaleBeginAtZero: true, animation: false}"
)
.col-sm-6(ng-click="statView.diskOnly=true")
p.stat-name
i.fa.fa-hdd-o
| &nbsp; Disk I/O
canvas.chart.chart-line.chart-stat-preview(
id="smallDisk"
data="stats.xvds"
labels="stats.date"
series="stats.xvdSeries"
colours="['#00dd00', '#77dd77', '#007700', '#33dd33', '#003300']"
options="{responsive: true, maintainAspectRatio: false, showTooltips: false, datasetStrokeWidth: 0.8, pointDot: false, showScale: false, scaleBeginAtZero: true, animation: false}"
)
.panel-body(ng-if="!refreshStatControl.running || !stats")
.grid
.grid-cell
p.stat-name vCPUs
p.center.big {{VM.CPUs.number}}
.grid-cell
p.stat-name RAM
p.center.big {{VM.memory.size | bytesToSize}}
.grid-cell
p.stat-name Disks
p.center.big {{VM.$VBDs.length || 0}}
br
p.center(ng-if="refreshStatControl.running")
i.fa.fa-circle-o-notch.fa-spin.fa-2x
| &nbsp; Fetching stats...
.grid
.grid-cell(ng-if="VM.os_version.distro")
p.stat-name OS:
p.center.big
i(class="xo-icon-{{VM.os_version.distro | osFamily}}",tooltip="{{VM.os_version.name}}", style="color: black;")
.grid-cell
p.stat-name Xen tools:
p.center
span(ng-if="VM.PV_drivers", style="color:green;") Installed
span(ng-if="!VM.PV_drivers") NOT installed
//- Action panel
.grid
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-flash(style="color: #e25440;")
| Actions
.panel-body.text-center
.grid
.grid-cell.btn-group(ng-if="VM.power_state == ('Running' || 'Paused')")
button.btn(tooltip="Stop VM", type="button", style="width: 90%", xo-click="stopVM(VM.id)")
i.fa.fa-stop.fa-2x.fa-fw
.grid-cell.btn-group(ng-if="VM.power_state == ('Running')")
button.btn(tooltip="Suspend VM", type="button", style="width: 90%", xo-click="suspendVM(VM.id)")
i.fa.fa-pause.fa-2x.fa-fw
.grid-cell.btn-group(ng-if="VM.power_state == ('Suspended')")
button.btn(tooltip="Resume VM", type="button", style="width: 90%", xo-click="resumeVM(VM.id)")
i.fa.fa-play.fa-2x.fa-fw
.grid-cell.btn-group(ng-if="VM.power_state == ('Halted')")
button.btn(tooltip="Start VM", type="button", style="width: 90%", xo-click="startVM(VM.id)")
i.fa.fa-play.fa-2x.fa-fw
.grid-cell.btn-group(ng-if="VM.power_state == ('Running' || 'Paused')")
button.btn(tooltip="Reboot VM", type="button", style="width: 90%", xo-click="rebootVM(VM.id)")
i.fa.fa-refresh.fa-2x.fa-fw
.grid-cell.btn-group.dropdown(
ng-if="VM.power_state == ('Running' || 'Paused')"
dropdown
)
button.btn.dropdown-toggle(
dropdown-toggle
tooltip="Migrate VM"
type="button"
style="width: 90%"
)
i.fa.fa-share.fa-2x.fa-fw
<span class="caret"></span>
ul.dropdown-menu.left(role="menu")
li(ng-repeat="host in hosts.all | orderBy:natural('name_label') track by host.id")
a(ng-click="migrateVM(VM.id, host.id)")
i.xo-icon-host.fa-fw
| To {{host.name_label}}
.grid-cell.btn-group(ng-if="VM.power_state == ('Running' || 'Paused')")
button.btn(tooltip="Force Reboot", type="button", style="width: 90%", xo-click="force_rebootVM(VM.id)")
i.fa.fa-flash.fa-2x.fa-fw
.grid-cell.btn-group(ng-if="VM.power_state == ('Running' || 'Paused')")
button.btn(tooltip="Force Shutdown", type="button", style="width: 90%", xo-click="force_stopVM(VM.id)")
i.fa.fa-power-off.fa-2x.fa-fw
.grid-cell.btn-group(ng-if="VM.power_state == ('Halted')")
button.btn(tooltip="Delete VM", type="button", style="width: 90%", xo-click="destroyVM(VM.id)")
i.fa.fa-trash-o.fa-2x.fa-fw
.grid-cell.btn-group.dropdown(
ng-if="VM.power_state == ('Halted')"
dropdown
)
button.btn.dropdown-toggle(
dropdown-toggle
tooltip="Create a clone"
style="width: 90%"
type="button"
)
i.fa.fa-files-o.fa-2x.fa-fw
<span class="caret"></span>
ul.dropdown-menu.left(role="menu")
li
a(ng-click="cloneVM(VM.id,VM.name_label,false)")
i.fa.fa-code-fork.fa-fw
| Fast clone
li
a(ng-click="cloneVM(VM.id,VM.name_label,true)")
i.xo-icon-sr.fa-fw
| Full disk copy
.grid-cell.btn-group
button.btn(tooltip="Convert to template", type="button", style="width: 90%", xo-click="convertVM(VM.id)")
i.fa.fa-thumb-tack.fa-2x.fa-fw
.grid-cell.btn-group
button.btn(tooltip="Create a snapshot", style="width: 90%", type="button", xo-click="snapshotVM(VM.id,VM.name_label)")
i.xo-icon-snapshot.fa-2x.fa-fw
.grid-cell.btn-group
button.btn(tooltip="Export the VM", style="width: 90%", type="button", xo-click="exportVM(VM.id)")
i.fa.fa-download.fa-2x.fa-fw
.grid-cell.btn-group(style="margin-bottom: 0.5em")
button.btn(tooltip="VM Console", type="button", style="width: 90%", xo-sref="consoles_view({id: VM.id})")
i.xo-icon-console.fa-2x.fa-fw
//- Docker Panel (if Docker VM)
.grid(ng-if="VM.docker")
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-ship(style="color: #e25440;")
| Docker containers
.panel-body
p.text-center(ng-if="!VM.docker.process.item") No Docker container on this VM.
table.table.table-hover(ng-if="VM.docker.process.item")
tr
th.col-sm-2 Name
th.col-sm-6 Command
th.col-sm-2 Created
th.col-sm-2 Status
tr(ng-repeat = "container in VM.docker.process.item")
td.oneliner {{container.entry.names}}
td.oneliner {{container.entry.command}}
td.oneliner {{container.entry.created*1e3 | date:"medium"}}
td(ng-if="container.entry.status === 'Up'")
span.label.label-success Running
span.pull-right.btn-group.quick-buttons
a(
tooltip="Stop this container"
xo-click="stopContainer(VM.id,container.entry.container)"
)
i.fa.fa-stop
a(
tooltip="Pause this container"
xo-click="pauseContainer(VM.id,container.entry.container)"
)
i.fa.fa-pause
a(
tooltip="Restart this container"
xo-click="restartContainer(VM.id,container.entry.container)"
)
i.fa.fa-refresh
td(ng-if="container.entry.status === 'Up (Paused)'")
span.label.label-info Paused
span.pull-right.btn-group.quick-buttons
a(
tooltip="Resume this container"
xo-click="resumeContainer(VM.id,container.entry.container)"
)
i.fa.fa-play
td(ng-if="container.entry.status !== 'Up' && container.entry.status !== 'Up (Paused)'")
span.label.label-danger Halted
span.pull-right.btn-group.quick-buttons
a(
tooltip="Start this container"
xo-click="startContainer(VM.id,container.entry.container)"
)
i.fa.fa-play
//- Disk panel
.grid
.panel.panel-default
.panel-heading.panel-title
i.xo-icon-sr(style="color: #e25440;")
| Disk
span.quick-edit(
ng-if="!disksForm.$visible"
tooltip="Edit disks"
ng-click="disksForm.$show()"
)
i.fa.fa-edit.fa-fw
span.quick-edit(
ng-if="disksForm.$visible"
tooltip="Cancel Edition"
ng-click="disksForm.$cancel()"
)
i.fa.fa-undo.fa-fw
.panel-body
form(name = "disksForm", editable-form = '', onbeforesave = 'saveDisks($data)')
table.table.table-hover
tr
th Name
th Description
th Size
th SR
th Status
th(ng-show="disksForm.$visible")
//- FIXME: ng-init seems to disrupt the implicit $watch.
tr(ng-repeat = 'VDI in VDIs track by VDI.id')
td.oneliner
span(
editable-text="VDI.name_label"
e-name = '{{VDI.id}}/name_label'
)
| {{VDI.name_label}}
td.oneliner
span(
editable-text="VDI.name_description"
e-name = '{{VDI.id}}/name_description'
)
| {{VDI.name_description}}
td
//- FIXME: should be editable, but the server needs first
//- to accept a human readable string.
| {{VDI.size | bytesToSize}}
td.oneliner
span(
editable-select="(VDI.$SR | resolve).id"
e-ng-options="SR.id as (SR.name_label + ' (' + (SR.size - SR.usage | bytesToSize) + ' free)') for SR in writable_SRs"
e-name = '{{VDI.id}}/$SR'
)
//- Are SR editable? will trigger moving VDI to the new SR
a(xo-sref="SRs_view({id: (VDI.$SR | resolve).id})")
| {{(VDI.$SR | resolve).name_label}}
td(ng-if="isConnected(VDI)")
span.label.label-success Connected
span.pull-right.btn-group.quick-buttons
a(
tooltip="Disconnect this disk"
xo-click="disconnectVBD(VDI)"
)
i.fa.fa-unlink.fa-lg
td(ng-if="!isConnected(VDI)")
span.label.label-default Disconnected
span.pull-right.btn-group.quick-buttons
a(
tooltip="Plug this disk"
ng-if="VM.power_state == ('Running' || 'Paused')"
xo-click="connectVBD(VDI)"
)
i.fa.fa-plug.fa-lg
a(
tooltip="Forget this disk"
xo-click="deleteVBD(VDI)"
)
i.fa.fa-ban.fa-lg
a(
tooltip="Remove this disk"
xo-click="deleteDisk(VDI.id)"
)
i.fa.fa-trash-o.fa-lg
td(ng-show="disksForm.$visible")
.btn-group
button.btn.btn-default(
type="button"
ng-click="moveDisk($index, -1)"
ng-disabled="$first"
title="Move this disk up"
)
i.fa.fa-chevron-up
button.btn.btn-default(
type="button"
ng-click="moveDisk($index, 1)"
ng-disabled="$last"
title="Move this disk down"
)
i.fa.fa-chevron-down
//- TODO: Ability to create new VDIs.
.btn-form(ng-show="disksForm.$visible")
p.center
button.btn.btn-default(
type="reset"
ng-disabled="disksForm.$waiting"
ng-click="disksForm.$cancel()"
)
i.fa.fa-times
| Cancel
| &nbsp;
button.btn.btn-primary(
type="submit"
ng-disabled="disksForm.$waiting"
)
i.fa.fa-save
| Save
.grid
.col-md-4
iso-device(ng-if = 'VM && isoDeviceData', vm = 'VM', isos = 'isoDeviceData')
.col-md-8.text-right
div
button.btn(type="button", ng-class = '{"btn-success": adding, "btn-primary": !adding}', ng-disabled="disksForm.$waiting", ng-click="adding = !adding;creatingVdi = false;bootReordering = false")
i.fa.fa-plus(ng-if = '!adding')
i.fa.fa-minus(ng-if = 'adding')
| Attach Disk
| &nbsp;
button.btn(type="button", ng-class = '{"btn-success": creatingVdi, "btn-primary": !creatingVdi}', ng-disabled="disksForm.$waiting", ng-click="creatingVdi = !creatingVdi;adding = false;bootReordering = false")
i.fa.fa-plus(ng-if = '!creatingVdi')
i.fa.fa-minus(ng-if = 'creatingVdi')
| New Disk
| &nbsp;
button.btn(type="button", ng-class = '{"btn-success": bootReordering, "btn-primary": !bootReordering}', ng-disabled="disksForm.$waiting", ng-click="bootReordering = !bootReordering;adding = false;creatingVdi = false")
i.fa.fa-plus(ng-if = '!bootReordering')
i.fa.fa-minus(ng-if = 'bootReordering')
| Boot order
br
form.form-inline#addDiskForm(ng-if = 'adding', name = 'addForm', ng-submit = 'addVdi(vdiToAdd.vdi, vdiReadOnly, vdiBootable)')
fieldset(ng-attr-disabled = '{{ addWaiting ? true : undefined }}')
.form-group
select#vdiToAdd.form-control(ng-model = 'vdiToAdd', ng-options = 'vdi.label group by vdi.sr for vdi in VDIOpts', required)
option(value = '', disabled) -- Choose disk --
| &nbsp;
.form-group(ng-if = 'vdiToAdd')
//- .form-group
label(for = 'vdiPosition') Position&nbsp;
select#vdiPosition.form-control(ng-model = '$parent.vdiPos', ng-options = 'vPos for vPos in vdiFreePos', required)
option(value = '', disabled) --
| &nbsp;
.checkbox
label
input(type='checkbox', ng-model = '$parent.$parent.vdiBootable')
| Bootable&nbsp;
.checkbox
label
input(ng-if = '!isFreeForWriting(vdiToAdd.vdi)', type='checkbox', ng-model = '$parent.$parent.vdiReadOnly', ng-checked = 'true', ng-disabled = 'true')
input(ng-if = 'isFreeForWriting(vdiToAdd.vdi)', type='checkbox', ng-model = '$parent.$parent.vdiReadOnly')
| Read-only&nbsp;
.form-group
button.btn.btn-primary(type = 'submit', ng-disabled="disksForm.$waiting")
| Add
span(ng-if = 'addWaiting')
| &nbsp;
i.fa.fa-spin.fa-circle-o-notch
br
form.form-inline#createDiskForm(ng-if = 'creatingVdi', name = 'createForm', ng-submit = 'createVdi(newDiskName, newDiskSize, newDiskSR, newDiskBootable, newDiskReadonly)')
fieldset(ng-attr-disabled = '{{ createWaiting ? true : undefined }}')
.form-group
//- label(for = 'newDiskName') Name&nbsp;
input#newDiskName.form-control(type = 'text', ng-model = 'newDiskName', placeholder = 'Disk Name', required)
| &nbsp;
.form-group
//- label(for = 'newDiskSize') Size&nbsp;
input#newDiskSize.form-control(type = 'text', ng-model = 'newDiskSize', required, placeholder = 'Size e.g 128MB, 8GB, 2TB...')
| &nbsp;
.form-group
//- label(for = 'newDiskSR') SR&nbsp;
select.form-control(ng-model = 'newDiskSR', required, ng-options="SR.id as (SR.name_label + ' (' + (SR.size - SR.usage | bytesToSize) + ' free)') for SR in writable_SRs")
option(value = '', disabled) Choose your SR
| &nbsp;
br
br
.checkbox
label
input(type='checkbox', ng-model = 'newDiskBootable')
| &nbsp;Bootable&nbsp;
.checkbox
label
input(type='checkbox', ng-model = 'newDiskReadonly')
| &nbsp;Read-only&nbsp;
//- .form-group
label(for = 'diskPosition') Position&nbsp;
select#diskPosition.form-control(ng-model = 'newDiskPosition', ng-options = 'vPos for vPos in vdiFreePos', required)
option(value = '', disabled) --
| &nbsp;
br
br
.form-group
button.btn.btn-primary(type = 'submit', ng-disabled="disksForm.$waiting")
i.fa.fa-plus-square
| &nbsp;Create
span(ng-if = 'createWaiting')
| &nbsp;
i.fa.fa-spin.fa-circle-o-notch
br
form(ng-if = 'bootReordering', ng-submit = 'saveBootParams(VM.id, bootParams)')
fieldset(ng-attr-disabled = '{{ savingBootOrder ? true : undefined }}')
.form-group(ng-repeat = 'elem in bootParams')
label
span(ng-class = '{"text-muted": !elem.v}') {{ elem.t }}&nbsp;
input(type = 'checkbox', ng-model = 'elem.v')
| &nbsp;
button.btn.btn-default(type = 'button', ng-click = 'bootMove($index, -1)', ng-class = '{disabled: $first}'): i.fa.fa-chevron-up
| &nbsp;
button.btn.btn-default(type = 'button', ng-click = 'bootMove($index, 1)', ng-class = '{disabled: $last}'): i.fa.fa-chevron-down
.form-group
button.btn.btn-primary(type = 'submit', ng-disabled = 'disksForm.$waiting')
i.fa.fa-database
| &nbsp;Save
//- TODO: add interface in this panel
.grid
.panel.panel-default
.panel-heading.panel-title
i.xo-icon-network(style="color: #e25440;")
| Interface
.panel-body
table.table.table-hover
th Device
th MAC
th MTU
th Network
th Link status
tr(ng-repeat="VIF in VM.VIFs | resolve | orderBy:natural('device') track by VIF.id")
td VIF \#{{VIF.device}}
td
| {{VIF.MAC}}
td
| {{VIF.MTU}}
td.oneliner
| {{(VIF.$network | resolve).name_label}}
td(ng-if="VIF.attached")
span.label.label-success Connected
span.pull-right.btn-group.quick-buttons
a(tooltip="Disconnect this interface", ng-if="VM.power_state == ('Running' || 'Paused')", xo-click="disconnectVIF(VIF.id)")
i.fa.fa-unlink.fa-lg
td(ng-if="!VIF.attached")
span.label.label-default Disconnected
span.pull-right.btn-group.quick-buttons
a(tooltip="Connect this interface", xo-click="connectVIF(VIF.id)")
i.fa.fa-link.fa-lg
a(tooltip="Remove this interface", xo-click="deleteVIF(VIF.id)")
i.fa.fa-trash-o.fa-lg
.text-right
button.btn(type="button", ng-class = '{"btn-success": creatingVif, "btn-primary": !creatingVif}', ng-click="creatingVif = !creatingVif")
i.fa.fa-plus(ng-if = '!creatingVif')
i.fa.fa-minus(ng-if = 'creatingVif')
| Create Interface
br
form.form-inline.text-right#createInterfaceForm(
ng-if = 'creatingVif'
name = 'createInterfaceForm'
ng-submit = 'createInterface(newInterfaceNetwork, newInterfaceMTU, autoMac, newInterfaceMAC)'
)
fieldset(ng-attr-disabled = '{{ createVifWaiting ? true : undefined }}')
.form-group
label(for = 'newVifNetwork') Network&nbsp;
select.form-control(
ng-options='network.name_label for network in networks'
ng-model = 'newInterfaceNetwork'
ng-change = 'updateMTU(newInterfaceNetwork)'
required
)
option(value = '', disabled) --
| &nbsp;
.form-group
fieldset(ng-attr-disabled = '{{ autoMac ? true : undefined }}')
label.control-label(for = 'newInterfaceMAC') MAC address&nbsp;
input#newInterfaceMAC.form-control(ng-class = '{hidden: autoMac}', type = 'text', ng-model = 'newInterfaceMAC', ng-required = '!autoMac')
| &nbsp;
.checkbox
label
input(type='checkbox', ng-model = 'autoMac')
| Auto-generate &nbsp;
| &nbsp;
.form-group
label(for = 'newInterfaceMTU') MTU&nbsp;
input#newInterfaceMTU.form-control(type = 'text', ng-model = 'newInterfaceMTU', required)
| &nbsp;
.form-group
button.btn.btn-primary(type = 'submit')
i.fa.fa-plus-square
| &nbsp;Create
span(ng-if = 'createVifWaiting')
| &nbsp;
i.fa.fa-spin.fa-circle-o-notch
br
//- Snap panel
.grid
form(editable-form="", name="vmSnap", oncancel="cancel()").panel.panel-default
.panel-heading.panel-title
i.xo-icon-snapshot(style="color: #e25440;")
| Snapshots
span.quick-edit(tooltip="Edit snapshots", ng-click="vmSnap.$show()")
i.fa.fa-edit.fa-fw
.panel-body
p.center(ng-if="!VM.snapshots.length") No snapshots
table.table.table-hover(ng-if="VM.snapshots.length")
th Date
th Name
tr(ng-repeat="snapshot in VM.snapshots | resolve | orderBy:'-snapshot_time' | slice:(5*(currentSnapPage-1)):(5*currentSnapPage) track by snapshot.id")
td.oneliner {{snapshot.snapshot_time*1e3 | date:"medium"}}
td.oneliner
span(editable-text="snapshot.name_label", e-name="name_label", e-form="vmSnap", onbeforesave="saveSnapshot(snapshot.id, $data)")
| {{snapshot.name_label}}
span.pull-right.btn-group.quick-buttons
a(tooltip="Export this snapshot", type="button", xo-click="exportVM(snapshot.id)")
i.fa.fa-upload.fa-lg
a(tooltip="Revert VM to this snapshot", xo-click="revertSnapshot(snapshot.id)")
i.fa.fa-undo.fa-lg
a(tooltip="Remove this snapshot", xo-click="deleteSnapshot(snapshot.id)")
i.fa.fa-trash-o.fa-lg
.center(ng-if = '(VM.snpashots | resolve).length > 5')
pagination(boundary-links="true", total-items="(VM.snpashots | resolve).length", ng-model="$parent.currentSnapPage", items-per-page="5", max-size="5", class="pagination-sm", previous-text="<", next-text=">", first-text="<<", last-text=">>")
.btn-form(ng-show="vmSnap.$visible")
p.center
button.btn.btn-default(type="button", ng-disabled="vmSnap.$waiting", ng-click="vmSnap.$cancel()")
i.fa.fa-times
| Cancel
| &nbsp;
button.btn.btn-primary(type="submit", ng-disabled="vmSnap.$waiting", ng-click="saveChanges()")
i.fa.fa-save
| Save
//- Logs panel
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-comments(style="color: #e25440;")
| Logs
span.quick-edit(ng-if="VM.messages | isNotEmpty", tooltip="Remove all logs", xo-click="deleteAllLog()")
i.fa.fa-trash-o.fa-fw
.panel-body
p.center(ng-if="VM.messages | isEmpty") No recent logs
table.table.table-hover(ng-if="VM.messages | isNotEmpty")
th Date
th Name
tr(ng-repeat="message in VM.messages | map | orderBy:'-time' | slice:(5*(currentLogPage-1)):(5*currentLogPage) track by message.id")
td.oneliner {{message.time*1e3 | date:"medium"}}
td.oneliner
| {{message.name}}
span.pull-right.btn-group.quick-buttons
a(xo-click="deleteLog(message.id)")
i.fa.fa-trash-o.fa-lg(tooltip="Remove this log entry")
.center(ng-if = '(VM.messages | count) > 5')
pagination(boundary-links="true", total-items="VM.messages | count", ng-model="$parent.currentLogPage", items-per-page="5", max-size="5", class="pagination-sm", previous-text="<", next-text=">", first-text="<<", last-text=">>")
.grid
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-plug(style="color: #e25440;")
| PCI Devices
.panel-body
p.center(ng-if="!(VM.$container | resolve).$PCIs") No PCI devices available
table.table.table-hover(ng-if="(VM.$container | resolve).$PCIs")
th PCI Info
th Device Name
th Status
tr(ng-repeat="pci in ((VM.$container | resolve).$PCIs | resolve) | orderBy:'pci_id' | slice:(5*(currentPCIPage-1)):(5*currentPCIPage) track by pci.id")
td.oneliner {{pci.pci_id}} ({{pci.class_name}})
td.oneliner {{pci.device_name}}
td(ng-if="pci.pci_id === VM.other.pci")
span.label.label-success Attached
span.pull-right.btn-group.quick-buttons
a(tooltip="Disconnect this PCI device", xo-click="disconnectPci(VM.id)")
i.fa.fa-unlink.fa-lg
td(ng-if="pci.pci_id !== VM.other.pci")
span.label.label-default Not attached
span.pull-right.btn-group.quick-buttons
a(tooltip="Connect this PCI device", xo-click="connectPci(VM.id, pci.pci_id)")
i.fa.fa-link.fa-lg
.center(ng-if = '((VM.$container | resolve).$PCIs | resolve).length > 5')
pagination(boundary-links="true", total-items="((VM.$container | resolve).$PCIs | resolve).length", ng-model="$parent.currentPCIPage", items-per-page="5", max-size="5", class="pagination-sm", previous-text="<", next-text=">", first-text="<<", last-text=">>")
.panel.panel-default
.panel-heading.panel-title
i.fa.fa-desktop(style="color: #e25440;")
| vGPUs
.panel-body
p.center(ng-if="!VM.$VGPus") No vGPUs available
table.table.table-hover(ng-if="VM.$VGPus")
th Device
th Status
tr(ng-repeat="vgpu in VM.$VGPUs | resolve | orderBy:'device' | slice:(5*(currentGPUPage-1)):(5*currentGPUPage) track by vgpu.id")
td.oneliner {{vgpu.device}}
td(ng-if="vgu.currentlyAttached")
span.label.label-success Attached
td(ng-if="!vgu.currentlyAttached")
span.label.label-default Not attached
.center(ng-if = '(VM.$VGPUs | resolve).length > 5')
pagination(boundary-links="true", total-items="(VM.$VGPUs | resolve).length", ng-model="$parent.currentGPUPage", items-per-page="5", max-size="5", class="pagination-sm", previous-text="<", next-text=">", first-text="<<", last-text=">>")

View File

@@ -1,101 +0,0 @@
import angular from 'angular'
import {
format as formatUrl,
parse as parseUrl,
resolve as resolveUrl
} from 'url'
import {RFB} from 'novnc-node'
import view from './view'
// ===================================================================
function parseRelativeUrl (url) {
/* global window: false */
return parseUrl(resolveUrl(String(window.location), url))
}
const PROTOCOL_ALIASES = {
'http:': 'ws:',
'https:': 'wss:'
}
function fixProtocol (url) {
let protocol = PROTOCOL_ALIASES[url.protocol]
if (protocol) {
url.protocol = protocol
}
}
// ===================================================================
export default angular.module('no-vnc', [])
.controller('NoVncCtrl', function ($attrs, $element, $scope) {
this.height = 480
$attrs.$observe('height', (height) => {
this.height = height
})
this.width = 640
$attrs.$observe('width', (width) => {
this.width = width
})
let rfb
function clean () {
// If there was a previous connection.
if (rfb) {
rfb.disconnect()
rfb = undefined
}
}
this.remoteControl = {
sendCtrlAltDel () {
if (rfb) {
rfb.sendCtrlAltDel()
}
}
}
let canvas = $element.find('canvas')[0]
$attrs.$observe('url', (url) => {
// Remove previous connection.
clean()
// If the URL is empty, stop now.
if (!url) {
return
}
// Parse the URL.
url = parseRelativeUrl(url)
fixProtocol(url)
let isSecure = url.protocol === 'wss:'
rfb = new RFB({
encrypt: isSecure,
target: canvas,
wsProtocols: ['chat']
})
// Connect.
rfb.connect(formatUrl(url))
})
$scope.$on('$destroy', clean)
})
.directive('noVnc', function () {
return {
bindToController: true,
controller: 'NoVncCtrl as noVnc',
restrict: 'E',
scope: {
remoteControl: '='
},
template: view
}
})
.name

View File

@@ -1,9 +0,0 @@
{
"private": true,
"browserify": {
"transform": [
"babelify",
"browserify-plain-jade"
]
}
}

View File

@@ -1,5 +0,0 @@
canvas.center-block(
height = "{{noVnc.height}}"
width = "{{noVnc.width}}"
)
| Sorry, your browser does not support the canvas element.

View File

@@ -1,36 +0,0 @@
import angular from 'angular'
import angularUiRouter from 'angular-ui-router'
import masterSelect from './'
import view from './view'
// -------------------------------------------------------------------
class MasterSelectDemoCtrl {
constructor () {
this.master = null
const items = this.items = new Array(10)
for (let i = 0, n = items.length; i < n; ++i) {
items[i] = {
label: `Item ${i}`,
selected: (Math.random() < 0.5)
}
}
}
}
export default angular.module('xoWebApp.foo', [
angularUiRouter,
masterSelect
])
.config($stateProvider => {
$stateProvider.state('master-select-demo', {
url: '/master-select-demo',
controller: 'MasterSelectDemoCtrl as demo',
template: view
})
})
.controller('MasterSelectDemoCtrl', MasterSelectDemoCtrl)
.name

View File

@@ -1,87 +0,0 @@
import angular from 'angular'
import forEach from 'lodash.foreach'
// -------------------------------------------------------------------
const defaultIsSelected = (object) => object != null && object.selected
const defaultSelect = (object) => {
if (object != null) {
object.selected = true
}
}
const defaultUnselect = (object) => {
if (object != null) {
object.selected = false
}
}
export default angular.module('master-select', [])
.directive('masterSelect', function () {
return {
link ($scope, $elem, $attrs) {
const isSelected = defaultIsSelected
const select = defaultSelect
const unselect = defaultUnselect
let internalChange = false
$scope.$watch('items', items => {
if (internalChange) {
internalChange = false
return
}
const selected = $scope.selectedItems = Object.create(null)
let nAll = 0
let nSelected = 0
forEach(items, (item, key) => {
++nAll
if (isSelected(item, key, items)) {
selected[key] = item
++nSelected
}
})
const indeterminate = nSelected && nSelected !== nAll
const previousNgModel = $scope.ngModel
$scope.ngModel = indeterminate || Boolean(nSelected)
if (previousNgModel !== $scope.ngModel) {
internalChange = true
}
$elem.prop('indeterminate', indeterminate)
}, true)
$scope.$watch('ngModel', selected => {
if (internalChange) {
internalChange = false
return
}
internalChange = true
$elem.prop('indeterminate', false)
const {items} = $scope
const selectedItems = $scope.selectedItems = Object.create(null)
forEach(items, selected ?
(item, key) => {
select(item, key, items)
selectedItems[key] = item
} :
(item, key) => {
unselect(item, key, items)
}
)
})
},
restrict: 'A',
scope: {
items: '=masterSelect',
ngModel: '=',
selectedItems: '=?'
}
}
})
.name

View File

@@ -1,10 +0,0 @@
{
"private": true,
"browserify": {
"transform": [
"babelify",
"browserify-plain-jade"
]
},
"devDependencies": {}
}

View File

@@ -1,31 +0,0 @@
.container-fluid: .row: .grid
.panel.panel-default: .panel-body
p
button(
ng-click = 'demo.master = !demo.master'
) Toggle
p
input(
type = 'checkbox'
master-select = 'demo.items'
selected-items = 'selectedItems'
ng-model = 'demo.master'
)
| Master
ul
li(
ng-repeat = 'item in demo.items'
)
input(
type = 'checkbox'
ng-model = 'item.selected'
)
| {{item.label}}
.panel.panel-default: .panel-body
pre {{demo | json}}
.panel.panel-default: .panel-body
pre {{selectedItems | json}}

413
app/node_modules/xo-api/index.js generated vendored
View File

@@ -1,413 +0,0 @@
import angular from 'angular'
import angularCookies from 'angular-cookies'
import cloneDeep from 'lodash.clonedeep'
import forEach from 'lodash.foreach'
import indexOf from 'lodash.indexof'
import sum from 'lodash.sum'
import XoIndex from 'xo-collection/index'
import xoLib from 'xo-lib'
import XoUniqueIndex from 'xo-collection/unique-index'
import XoView from 'xo-collection/view'
const {defineProperty} = Object
const {isArray, isString} = angular
// ===================================================================
// Low level XO API for Angular.
export default angular.module('xo-api', [
angularCookies
])
.run(function ($rootScope) {
// Ensure correct integration with Angular.
xoLib.setScheduler(function (fn) {
$rootScope.$evalAsync(fn)
})
})
.service('xoApi', function (
$cookieStore,
$rootScope,
$timeout
) {
const xo = new xoLib.Xo()
// A lots of event listeners are added to the collection.
xo.objects.setMaxListeners(0)
// Notifies Angular about changes in the collection.
xo.objects.on('finish', () => {
$rootScope.$applyAsync()
})
try {
const token = $cookieStore.get('token')
// If there is a token, sign in with it.
if (token) {
xo.signIn({ token })
}
} catch (e) {
if (e instanceof SyntaxError) {
$cookieStore.remove('token')
} else {
throw e
}
}
// ---------------------------------------------------------------
const getObject = (function (objects) {
const {
all: byIds,
indexes: {
ref: byRefs
}
} = objects
return function getObject (id, type) {
const object = byIds[id] || byRefs[id]
if (
// The object has been found and …
object && (
// … no type specified.
!type ||
// … is of the expected type.
(type === object.type) ||
// … is of one of the allowed types.
isArray(type) && (indexOf(type, object.type) === -1)
)
) {
return object
}
}
})(xo.objects)
// ---------------------------------------------------------------
// TODO: should probably be merged in the main collection in xo-lib.
let currentAcls = Object.create(null)
;(function updateCurrentAcls () {
xo.call('acl.getCurrent').then(acls => {
currentAcls = Object.create(null)
forEach(acls, acl => {
const object = getObject(acl.object)
if (object) {
currentAcls[object.id] = true
}
})
$timeout(updateCurrentAcls, 1e4)
})
})()
function canAccess (id) {
// Auto unbox.
if (id.id) {
id = id.id
}
const {user} = xo
let object
return (
// Administrators can access everything.
user && (user.permission === 'admin') ||
// Check if the id is in the ACLs table.
(id in currentAcls) ||
// Check if the id is in fact not a true id (maybe a ref or a
// UUID) and if we can resolve it to an id.
(object = getObject(id)) && (object.id in currentAcls)
)
}
// ---------------------------------------------------------------
const getView = (function () {
const views = Object.create(null)
function getView (viewName) {
let view = views[viewName]
if (!view) {
// The view name can be plural (ex VMs) but the type is
// singular.
const type = viewName[viewName.length - 1] === 's' ?
viewName.slice(0, -1) :
viewName
const predicate = (object) => object.type === type
view = views[viewName] = new XoView(xo.objects, predicate)
}
return view
}
// -------------------------------------------------------------
function registerLazyView (name, predicate, collection) {
defineProperty(views, name, {
configurable: true,
enumerable: true,
get () {
if (!collection) {
collection = xo.objects
} else if (isString(collection)) {
collection = getView(collection)
}
const view = new XoView(collection, predicate)
delete views[name]
views[name] = view
return view
}
})
}
registerLazyView(
'runningHosts',
host => host.power_state === 'Running',
'hosts'
)
const RUNNING_VM_STATUSES = {
Running: true,
Paused: true
}
registerLazyView(
'runningVms',
(vm) => RUNNING_VM_STATUSES[vm.power_state],
'VMs'
)
const RUNNING_TASK_STATUSES = {
cancelling: true,
pending: true
}
registerLazyView(
'runningTasks',
(task) => RUNNING_TASK_STATUSES[task.status] && canAccess(task.$host),
'tasks'
)
// -------------------------------------------------------------
return getView
})()
// ---------------------------------------------------------------
const getIndex = (function (indexes) {
function registerLazyIndex (name, computeHash, collection, isUnique) {
Object.defineProperty(indexes, name, {
configurable: true,
get () {
if (!collection) {
collection = xo.objects
} else if (isString(collection)) {
collection = getView(collection)
}
const index = new (isUnique ? XoUniqueIndex : XoIndex)(computeHash)
index._attachCollection(collection)
const items = index.items
delete indexes[name]
indexes[name] = items
return items
}
})
}
registerLazyIndex(
'hostsByPool',
'$poolId',
'hosts'
)
registerLazyIndex(
'networksByPool',
'$poolId',
'networks'
)
registerLazyIndex(
'poolPatchesByPool',
'$poolId',
'pool_patch'
)
registerLazyIndex(
'runningHostsByPool',
'$poolId',
'runningHosts'
)
registerLazyIndex(
'runningTasksByHost',
'$host',
'runningTasks'
)
registerLazyIndex(
'runningVmsByPool',
'$poolId',
'runningVms'
)
registerLazyIndex(
'srsByContainer',
'$container',
'SRs'
)
registerLazyIndex(
'vmsByContainer',
'$container',
'VMs'
)
registerLazyIndex(
'vmsByPool',
'$poolId',
'VMs'
)
registerLazyIndex(
'vmControllersByContainer',
'$container',
'VM-controllers',
true
)
registerLazyIndex(
'vmTemplatesByContainer',
'$container',
'VM-templates'
)
return function getIndex (name) {
const index = indexes[name]
if (!index) {
throw new Error('no such index ' + name)
}
return index
}
})(Object.create(null))
// ---------------------------------------------------------------
const stats = {
$CPUs: 0,
$vCPUs: 0,
$memory: {
usage: 0,
size: 0
}
}
getView('hosts').on('finish', function () {
stats.$CPUs = sum(this.all, host => +host.CPUs.cpu_count)
})
getView('runningVms').on('finish', function () {
stats.$vCPUs = sum(this.all, vm => vm.CPUs.number)
})
// TODO: maybe merge with stats.$CPUs.
getView('runningHosts').on('finish', function () {
// TODO: merge into a single loop.
stats.$memory.usage = sum(this.all, host => host.memory.usage)
stats.$memory.size = sum(this.all, host => host.memory.size)
})
// ---------------------------------------------------------------
return {
// -----------------
// Session
// -----------------
logIn (email, password, persist) {
return xo.signIn({ email, password }).then(() => {
if (persist) {
xo.call('token.create').then(function (token) {
$cookieStore.put('token', token)
})
}
})
},
logOut () {
$cookieStore.remove('token')
return xo.signOut()
},
get status () {
return xo.status
},
get user () {
return xo.user
},
// -----------------
// RPC
// -----------------
call (method, params) {
// The params need to be cloned to prevent them from being
// changed before the method has really been sent.
return xo.call(method, cloneDeep(params))
},
// -----------------
// Objects
// -----------------
// Collection of all objects.
all: xo.objects.all,
// Returns an object (or multiple objects) from its id/ref.
//
// They can be filter by type(s).
get (id, types) {
if (isArray(id)) {
const objects = []
forEach(id, id => {
const object = getObject(id, types)
if (object) {
objects.push(object)
}
})
return objects
}
return getObject(id, types)
},
getIndex,
// Returns a view (read-only XoCollection).
getView,
// Checks whether the current user has access to an object
// (identified via its id or ref).
canAccess,
// -----------------
// Various
// -----------------
// Global stats.
stats
}
})
.name

View File

@@ -1,8 +0,0 @@
{
"private": true,
"browserify": {
"transform": [
"babelify"
]
}
}

View File

@@ -1,124 +0,0 @@
angular = require 'angular'
# TODO: split into multiple modules.
module.exports = angular.module 'xoWebApp.directives', []
# This attribute stops the ascendant propagation of a given event.
#
# The value of this attribute should be the name of the event to
# stop.
.directive 'stopEvent', ->
(_, $element, attrs) ->
$element.on attrs.stopEvent, ($event) ->
$event.stopPropagation()
# This attribute works similarly to `ng-click` but do not handle the
# event if the clicked element:
# - is an `input`;
# - has a `ng-click` attribute;
# - has a `xo-click` attribute;
# - has a `xo-sref` attribute;
# - is a link (`a`) and has a `href` attribute.
.directive 'xoClick', ($parse) ->
($scope, $element, attrs) ->
fn = $parse attrs.xoClick
current = $element[0]
current.addEventListener(
'click'
(event) ->
# Browse all parent elements of the element the event
# happened to and abort if one of them should handle the
# event itself.
el = event.target
while el isnt current
{attributes: attrs, tagName: tag} = el
return if (
tag is 'INPUT' or
attrs['ng-click']? or
attrs['xo-click']? or
attrs['xo-sref']? or
(tag is 'A') and attrs.href?
)
el = el.parentNode
# Stop the propagation.
event.stopPropagation()
# Apply the `xo-click` attribute.
$scope.$applyAsync ->
fn $scope, {$event: event}
true
)
# TODO: create a directive which allows a link on any element.
# TODO: Mutualize code with `xoClick`.
.directive 'xoSref', ($state, $window) ->
($scope, $element, attrs) ->
current = $element[0]
current.addEventListener(
'mouseup'
(event) ->
{which: button} = event
return unless button is 1 or button is 2
# Browse all parent elements of the element the event
# happened to and abort if one of them should handle the
# event itself.
el = event.target
while el isnt current
{attributes: attrs_, tagName: tag} = el
return if (
tag is 'INPUT' or
attrs_['ng-click']? or
attrs_['xo-click']? or
attrs_['xo-sref']? or
(tag is 'A') and attrs_.href?
)
el = el.parentNode
# Stop the propagation.
event.stopPropagation()
# Extracts the state and its parameters for the `xo-sref`
# attribute.
match = attrs.xoSref.match /^([^(]+)\s*(?:\((.*)\))?$/
throw new Error 'invalid SREF' unless match
state = match[1]
params = if match[2] then $scope.$eval match[2] else {}
# Ctrl modifier or middle-button.
if event.ctrlKey or button is 2
url = $state.href state, params
$window.open url
else
$state.go state, params
true
)
.directive 'fixAutofill', ($timeout) ->
restrict: 'A'
require: 'ngModel'
link: ($scope, $elem, attrs, ngModel) ->
previous = $elem.val()
updateValue = ->
current = $elem.val()
if ngModel.$pristine and current isnt previous
previous = current
ngModel.$setViewValue current
# Attempt to update the value.
$timeout updateValue, 5e2
# A refresh can be asked via the fixAutofill event.
$scope.$on 'fixAutofill', updateValue
# A module exports its name.
.name

View File

@@ -1,8 +0,0 @@
{
"private": true,
"browserify": {
"transform": [
"coffeeify"
]
}
}

174
app/node_modules/xo-filters/index.js generated vendored
View File

@@ -1,174 +0,0 @@
import angular from 'angular'
import forEach from 'lodash.foreach'
import isEmpty from 'lodash.isempty'
import map from 'lodash.map'
import slice from 'lodash.slice'
import xoApi from 'xo-api'
// ===================================================================
export default angular.module('xoWebApp.filters', [
xoApi
])
// The bytes filters takes a number and formats it using adapted
// units (KB, MB, etc.).
.filter('bytesToSize', () => {
const powers = ['', 'K', 'M', 'G', 'T', 'P']
return function bytesToSize (bytes, unit = 'B', base = 1024) {
let i = 0
while (bytes >= base) {
bytes /= base
++i
}
if (bytes === -1) {
return '-'
}
// Maximum 1 decimals.
bytes = ((bytes * 10) | 0) / 10
return `${bytes}${powers[i]}${unit}`
}
})
.filter('sizeToBytes', () => {
/* eslint no-multi-spaces: 0 */
const RE = new RegExp('^' +
'(\\d+(?:\\.\\d+)?)' + // digits ('.' digits)?
'\\s*' + // Optional spaces between the digits and the unit.
'([kmgtp])?' + // Optional unit modifier K/M/G/T/P.
'b?' + // Optional unit (“b”), not meaningful.
'$', 'i')
const factors = {
k: 1024,
m: 1048576,
g: 1073741824,
t: 1099511627776,
p: 1125899906842624
}
return function sizeToBytes (size) {
const matches = RE.exec(size)
// If the input is invalid, just returns null.
if (!matches) {
return null
}
let value = +matches[1]
const modifier = matches[2]
if (modifier) {
const factor = factors[modifier.toLowerCase()]
if (factor) {
value *= factor
}
}
return Math.round(value)
}
})
// Simply returns the number of elements in the collection.
.filter('count', () => {
const {hasOwnProperty} = Object.prototype
return function count (collection) {
if (typeof collection !== 'object') {
return 0
}
// Array.
if (angular.isArray(collection)) {
return collection.length
}
// Object.
let n = 0
for (let key in collection) {
if (hasOwnProperty.call(collection, key)) {
++n
}
}
return n
}
})
// Resolves links between objects.
.filter('resolve', (xoApi) => xoApi.get)
.filter('isEmpty', () => isEmpty)
.filter('isNotEmpty', () => (collection) => !isEmpty(collection))
.filter('slice', () => slice)
// Applies a function to a list of items.
//
// If a string is used instead of a function, it will be used as a
// property name to extract from each item.
.filter('map', () => map)
.filter('percentage', () => {
return function percentage (value) {
// If `value` is an array of two values, divide the first by the
// second and multiply by 100.
if (value.length === 2) {
// Special case, if the divider is 0, simply returns "N/A".
if (value[1] === 0) {
return 'N/A'
}
const result = 100 * value[0] / value[1]
if (isNaN(result)) {
return 'N/A'
}
value = result
}
// No decimals at most.
value = Math.round(value * 1e0) / 1e0
return `${value}%`
}
})
.filter('osFamily', () => {
const osToFamily = (function (osByFamily) {
const osToFamily = Object.create(null)
forEach(osByFamily, (list, family) => {
forEach(list, os => {
osToFamily[os] = family
})
})
return osToFamily
})({
linux: [
'centos',
'CoreOS',
'debian',
'fedora',
'gentoo',
'oracle',
'redhat',
'sles',
'suse',
'ubuntu'
],
windows: [
'windows'
]
})
return (osName) => osToFamily[osName] || 'other'
})
// A module exports its name.
.name

View File

@@ -1,8 +0,0 @@
{
"private": true,
"browserify": {
"transform": [
"babelify"
]
}
}

40
app/node_modules/xo-notify/index.js generated vendored
View File

@@ -1,40 +0,0 @@
import angular from 'angular'
import angularAnimate from 'angular-animate'
import angularNotifyToaster from 'angular-notify-toaster'
const {isString} = angular
// ===================================================================
// High level integration of XO API in xo-web.
export default angular.module('xo-notify', [
angularAnimate,
angularNotifyToaster
])
.service('xoNotify', (toaster) => {
function makeNotifier (level) {
return function notifier (options) {
if (isString(options)) {
options = { message: options }
} else if (!options.message) {
throw new Error('missing message')
}
toaster.pop(
level,
options.title || 'Xen-Orchestra',
options.message
)
}
}
return {
warning: makeNotifier('warning'),
error: makeNotifier('error'),
info: makeNotifier('info')
// TODO: It is probably a bad design to have notification for
// successful operations.
// success: makeNotifier 'success'
}
})
.name

View File

@@ -1,8 +0,0 @@
{
"private": true,
"browserify": {
"transform": [
"babelify"
]
}
}

View File

@@ -1,14 +0,0 @@
import angular from 'angular'
import xo from 'xo'
import xoNotify from 'xo-notify'
// ===================================================================
// TODO: remove when no longer used.
export default angular.module('xoWebApp.services', [
xo,
xoNotify
])
// Alias the service for compatibility.
.service('notify', (xoNotify) => xoNotify)
.name

View File

@@ -1,8 +0,0 @@
{
"private": true,
"browserify": {
"transform": [
"babelify"
]
}
}

300
app/node_modules/xo/index.js generated vendored
View File

@@ -1,300 +0,0 @@
import angular from 'angular'
import filter from 'lodash.filter'
import xoApi from 'xo-api'
import xoNotify from 'xo-notify'
const {isString} = angular
const isPlainObject = (function (toS) {
const ref = toS.call({})
return (value) => value != null && toS.call(value) === ref
})(Object.prototype.toString)
// ===================================================================
// High level integration of XO API in xo-web.
export default angular.module('xo', [
xoApi,
xoNotify
])
.service('xo', function (xoApi, xoNotify) {
// FIXME: default mapper should be identity.
const defaultArgsMapper = (...args) => {
const {length} = args
// No arguments.
if (!length) {
return {}
}
if (length !== 1) {
throw new Error('no obvious mapping: more than one argument')
}
const arg = args[0]
// The only argument is an object, it is probably the arguments,
// therefore it should be forwarded.
if (isPlainObject(arg)) {
return arg
}
// The only argument is a string, attempts to match it as `id`.
if (isString(arg)) {
return { id: arg }
}
throw new Error('no obvious mapping: the only argument is neither an object or a string')
}
const action = (name, method, options) => {
if (!method) {
return () => {
xoNotify.info({
title: name,
message: 'This feature has not been implemented yet.'
})
// TODO: A (broken) promise should be returned for
// consistency.
}
}
const {
argsMapper = defaultArgsMapper,
notification
} = options || {}
return (...args) => {
const promise = xoApi.call(method, argsMapper(...args))
promise.catch(error => {
console.error('Error for %s:', method, error)
if (notification !== false) {
const message = (error && error.code === 2) ?
'You don\'t have the permission.' :
'The action failed for unknown reason.'
xoNotify.warning({
title: name,
message
})
}
})
return promise
}
}
/* eslint key-spacing: 0 */
// The interface.
const xo = {
acl: {
add: action('Adding an ACL entry', 'acl.add', {
argsMapper: (subject, object, action) => ({subject, object, action})
}),
get: action('Getting ACLs', 'acl.get'),
remove: action('Remove an ACL entry', 'acl.remove', {
argsMapper: (subject, object, action) => ({subject, object, action})
})
},
pool: {
disconnect: action('Disconnect pool'),
new_sr: action('New SR'), // temp fix before creating SR
patch: action('Upload patch', 'pool.patch', {
argsMapper: (pool) => ({pool})
})
},
host: {
attach: action('Attach host'),
detach: action('Detach host', 'host.detach'),
restart: action('Restart host', 'host.restart'),
restartToolStack: action('Restart tool stack', 'host.restart_agent'),
start: action('Start host', 'host.start'),
enable: action('Enable host', 'host.enable'),
stop: action('Stop host', 'host.stop'),
disable: action('Disable host', 'host.disable'),
new_sr: action('New SR'), // temp fix before creating SR
listMissingPatches: action('Check available patches', 'host.listMissingPatches', {
argsMapper: (host) => ({host})
}),
installPatch: action('Install a patch from a patch id', 'host.installPatch', {
argsMapper: (host, patch) => ({host, patch})
}),
refreshStats: action('Get Stats', 'host.stats', {
notification: false,
argsMapper: (host) => ({host})
})
// TODO: attach/set
},
log: {
delete: action('Delete Log', 'message.delete')
},
message: {
delete: action('Delete message')
},
pbd: {
delete: action('Delete PBD'),
disconnect: action('Disconnect PBD')
},
server: {
add: action('Add server', 'server.add'),
remove: action('Remove server', 'server.remove'),
getAll: action('Getting server', 'server.getAll'),
set: action('Save server', 'server.set'),
connect: action('Connect to a server', 'server.connect', {
notification: false
}),
disconnect: action('Disconnect from a server', 'server.disconnect')
},
task: {
cancel: action('Cancel task', 'task.cancel'),
destroy: action('Destroy task', 'task.destroy')
},
user: {
create: action('Create user', 'user.create'),
delete: action('Delete user', 'user.delete', {
argsMapper: (id) => ({ id: String(id) })
}),
getAll: action('Getting users', 'user.getAll'),
set: action('Save user', 'user.set')
},
group: {
create: action('Create group', 'group.create'),
delete: action('Delete group', 'group.delete', {
argsMapper: (id) => ({ id: String(id) })
}),
getAll: action('Getting groups', 'group.getAll'),
set: action('Save group', 'group.set'),
setUsers: action('Set group users', 'group.setUsers', {
argsMapper: (id, userIds) => ({ id: String(id), userIds})
}),
addUser: action('Add group user', 'group.addUser', {
argsMapper: (id, userId) => ({ id: String(id), userId: String(userId)})
}),
removeUser: action('Remove group users', 'group.removeUser', {
argsMapper: (id, userId) => ({ id: String(id), userId: String(userId)})
})
},
role: {
getAll: action('Getting roles', 'role.getAll')
},
docker: {
start: action('Start a Docker Container', 'docker.start', {
argsMapper: (vm, container) => ({vm, container})
}),
stop: action('Stop a Docker Container', 'docker.stop', {
argsMapper: (vm, container) => ({vm, container})
}),
pause: action('Pause a Docker Container', 'docker.pause', {
argsMapper: (vm, container) => ({vm, container})
}),
unpause: action('Resume a Docker Container', 'docker.unpause', {
argsMapper: (vm, container) => ({vm, container})
}),
restart: action('Restart a Docker Container', 'docker.restart', {
argsMapper: (vm, container) => ({vm, container})
})
},
vm: {
convert: action('Convert VM', 'vm.convert'),
clone: action('Copy VM', 'vm.clone', {
// todo : sr ref to choose target SR
argsMapper: (id, name, full_copy) => ({id, name, full_copy})
}),
createSnapshot: action('Create VM snapshot', 'vm.snapshot', {
argsMapper: (id, name) => ({id, name})
}),
export: action('Export VM', 'vm.export', {
argsMapper: (vm, compress = true) => ({vm, compress})
}),
delete: action('Delete VM', 'vm.delete', {
argsMapper: (id, delete_disks) => ({ id, delete_disks })
}),
ejectCd: action('Eject disc', 'vm.ejectCd'),
insertCd: action('Insert disc', 'vm.insertCd', {
argsMapper: (id, cd_id, force = false) => ({ id, cd_id, force })
}),
import: action('Import VM', 'vm.import', {
argsMapper: (host) => ({ host })
}),
migrate: action('Migrate VM', 'vm.migrate', {
argsMapper: (id, host_id) => ({ id, host_id })
}),
migratePool: action('Migrate VM to another pool', 'vm.migrate_pool'),
restart: action('Restart VM', 'vm.restart', {
argsMapper: (id, force = false) => ({ id, force })
}),
start: action('Start VM', 'vm.start'),
stop: action('Stop VM', 'vm.stop', {
argsMapper: (id, force = false) => ({ id, force })
}),
revert: action('Revert snapshot', 'vm.revert'),
suspend: action('Suspend VM', 'vm.suspend'),
resume: action('Resume VM', 'vm.resume', {
argsMapper: (id, force = true) => ({ id, force })
}),
refreshStats: action('Get Stats', 'vm.stats', {
notification: false
}),
// TODO: create/set/pause
connectPci: action('Connect PCI device', 'vm.attachPci', {
argsMapper: (vm, pciId) => ({vm, pciId})
}),
disconnectPci: action('Disconnect PCI device', 'vm.detachPci', {
argsMapper: (vm) => ({vm})
})
},
vdi: {
delete: action('Delete VDI', 'vdi.delete'),
migrate: action('Migrate VDI', 'vdi.migrate', {
argsMapper: (id, sr_id) => ({ id, sr_id })
})
},
vif: {
delete: action('Delete VIF', 'vif.delete'),
disconnect: action('Disconnect VIF', 'vif.disconnect'),
connect: action('Connect VIF', 'vif.connect')
},
vbd: {
delete: action('Delete VBD', 'vbd.delete'),
disconnect: action('Disconnect VBD', 'vbd.disconnect'),
connect: action('Connect VBD', 'vbd.connect')
}
}
// Adds the dynamic properties.
Object.defineProperties(xo, {
get: {
get () {
throw new Error('use xoApi.get() instead')
}
}
})
// Returns the interface.
return xo
})
.filter('xoHideUnauthorized', (xoApi) => {
const {canAccess} = xoApi
return (objects) => filter(objects, canAccess)
})
.name

8
app/node_modules/xo/package.json generated vendored
View File

@@ -1,8 +0,0 @@
{
"private": true,
"browserify": {
"transform": [
"babelify"
]
}
}

View File

@@ -1,679 +0,0 @@
//////////////////////////////////////////////////////////////////////
// Bootstrap
//////////////////////////////////////////////////////////////////////
@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap";
//////////////////////////////////////////////////////////////////////
// Font-Awesome 4.
//////////////////////////////////////////////////////////////////////
$fa-font-path: "../";
@import "../../node_modules/font-awesome/scss/font-awesome";
// Replace Bootstrap's glyphicons by Font Awesome.
.glyphicon {
@extend .fa;
}
//////////////////////////////////////////////////////////////////////
// Angular Charts.
//////////////////////////////////////////////////////////////////////
@import "../../dist/bower_components/angular-chart.js/dist/angular-chart";
//////////////////////////////////////////////////////////////////////
// Angular xEditable.
//////////////////////////////////////////////////////////////////////
@import "../../dist/bower_components/angular-xeditable/dist/css/xeditable";
//////////////////////////////////////////////////////////////////////
// Angular Notify Toaster.
//////////////////////////////////////////////////////////////////////
@import "../../dist/bower_components/angular-notify-toaster/toaster";
//////////////////////////////////////////////////////////////////////
// UI Select.
//////////////////////////////////////////////////////////////////////
@import "../../dist/bower_components/angular-ui-select/dist/select";
//////////////////////////////////////////////////////////////////////
// Style applied to a message for outdated browsers (IE <= 7).
.browsehappy {
margin: 0.2em 0;
background: #cccccc;
color: black;
padding: 0.2em 0;
}
// Some links are used throught JavaScript and therefore does not have
// a `href` attribute, they should nevertheless have a *pointer*
// cursor.
// Same for all elements with the "ng-click" attribute.
a, [ng-click], [xo-click], [xo-sref] {
cursor: pointer;
}
// TODO: We want all our form inputs to be styled by Bootstrap.
//input, textarea, select
// @extend .form-control
// Click-through notifications.
#toast-container {
pointer-events: none;
}
html, body, .view-main {
height: 100%
}
// Force our content to be under the fixed navbar.
.view-main {
padding-top: 50px;
}
//////////////////////////////////////////////////////////////////////
// TODO: The styles in this file should be
// - commented;
// - converted to SASS;
// - move into this file.
@import "to-clean";
//////////////////////////////////////////////////////////////////////
// Colors
//////////////////////////////////////////////////////////////////////
////
// Power states
////
.xo-color-running {
@extend .text-success;
}
.xo-color-halted {
@extend .text-danger;
}
.xo-color-paused, .xo-color-suspended {
@extend .text-info;
}
.xo-color-unknown {
@extend .text-muted;
}
.xo-color-pending {
@extend .text-warning;
}
//////////////////////////////////////////////////////////////////////
// XO icons
//////////////////////////////////////////////////////////////////////
////
// Alerts
////
.xo-icon-info {
@extend .fa;
@extend .fa-exclamation-circle;
@extend .text-muted;
}
.xo-icon-docker {
@extend .fa;
@extend .fa-ship;
@extend .text-info;
}
.xo-icon-warning {
@extend .fa;
@extend .fa-exclamation-circle;
@extend .text-warning;
}
.xo-icon-error {
@extend .fa;
@extend .fa-exclamation-circle;
@extend .text-danger;
}
.xo-icon-success {
@extend .fa;
@extend .fa-check-circle;
@extend .text-success;
}
////
// Objects
////
.xo-icon-console {
@extend .fa;
@extend .fa-terminal;
}
.xo-icon-pool {
@extend .fa;
@extend .fa-cloud;
}
.xo-icon-host {
@extend .fa;
@extend .fa-server;
}
.xo-icon-vm {
@extend .fa;
@extend .fa-desktop;
}
.xo-icon-memory {
@extend .fa;
@extend .fa-sliders;
}
.xo-icon-cpu {
@extend .fa;
@extend .fa-dashboard;
}
.xo-icon-network {
@extend .fa;
@extend .fa-sitemap;
}
.xo-icon-sr {
@extend .fa;
@extend .fa-hdd-o;
}
.xo-icon-snapshot {
@extend .fa;
@extend .fa-camera;
}
.xo-icon-task {
@extend .fa;
@extend .fa-tasks;
}
.xo-icon-stats {
@extend .fa;
@extend .fa-line-chart;
}
.xo-icon-user {
@extend .fa;
@extend .fa-user;
}
.xo-icon-group {
@extend .fa-users;
}
////
// Power states
////
.xo-icon-running {
@extend .fa;
@extend .fa-circle;
@extend .xo-color-running;
}
.xo-icon-halted {
@extend .fa;
@extend .fa-circle;
@extend .xo-color-halted;
}
.xo-icon-suspended {
@extend .fa;
@extend .fa-circle;
@extend .xo-color-paused;
}
.xo-icon-paused {
@extend .fa;
@extend .fa-circle;
@extend .xo-color-paused;
}
.xo-icon-unknown {
@extend .fa;
@extend .fa-circle;
@extend .xo-color-unknown;
}
// if current operation
.xo-icon-working {
@extend .fa;
@extend .fa-circle;
@extend .text-warning;
}
////
// Others.
////
.xo-icon-cpu-low {
@extend .xo-icon-cpu;
@extend .text-success;
}
.xo-icon-cpu-medium {
@extend .xo-icon-cpu;
@extend .text-warning;
}
.xo-icon-cpu-high {
@extend .xo-icon-cpu;
@extend .text-danger;
}
////
// Guest OS
////
.xo-icon-linux {
@extend .fa;
@extend .fa-linux;
color: #666666;
}
.xo-icon-windows {
@extend .fa;
@extend .fa-windows;
color: #666666;
}
.xo-icon-other {
@extend .fa;
@extend .fa-question-circle;
color: #666666;
}
//////////////////////////////////////////////////////////////////////
// Navbar
//////////////////////////////////////////////////////////////////////
// The login form
.login-form {
padding: 1em;
width: 20em;
// small space between fields
.input-group {
margin: 0.2em;
}
// adapt button for the global theme (dark/blue/grey)
.input-group-addon {
background-color: #3a87ad;
color: #f8f8f8;
border: 0;
}
button {
margin-top: 1em;
}
// adapt form for the global theme
.form-control {
background-color: #666666;
color: #f8f8f8;
border: 0;
}
}
// background dark for the whole form
.login-form-dark {
@extend .login-form;
background-color: #2e3133;
}
//////////////////////////////////////////////////////////////////////
// Main view
//////////////////////////////////////////////////////////////////////
// FIXME: Class names are too generic and styles might be applied to
// other views as well, all styles should be namespaced (e.g.
// `.view-main`).
// Notice messages in place of the VMs list in the main page.
.vms-notice {
@extend .text-center;
@extend .text-muted;
font-size: 1.5em;
flex: 1;
align-self: center;
justify-content: center;
}
.quick-buttons {
display: inline;
float: right;
opacity: 0;
a {
color: #666666;
margin: 0 0.3em;
text-decoration: none;
&:hover {
color: black;
}
}
}
// Quick actions buttons are only visible when over their row.
tr:hover .quick-buttons {
opacity: 1;
}
// remove icon/button in last row on a table
.quick-remove {
display: inline;
float: right;
opacity: 0;
a {
color: #666666;
text-decoration: none;
&:hover {
color: black;
}
}
}
// remove only visible when over its row
tr:hover .quick-remove {
opacity: 1;
}
// edit icon/button in a panel title
.quick-edit {
display: inline;
float: right;
opacity: 1;
color: #666666;
&:hover {
color: black;
}
}
// Substats (less important host stats)
.substats {
opacity: 0;
}
// Substat displayed on hover
div.host-cell:hover .substats {
opacity: 1;
}
// Default SRs (where a new VM will be created).
.default-sr {
@extend .text-primary;
font-weight: bold;
}
// Prevents a host name from overflowing outside its box.
.host-cell, .pool-cell, .vm-cell {
@extend .panel;
& div {
position: relative;
}
}
.host-name, .pool-name, .sr-name {
display: inline-block;
white-space: nowrap;
text-overflow: ellipsis;
max-width: 80%;
overflow: hidden;
}
// Pool block
// A block display a whole pool
.pool-block {
margin-right: 0.8em;
margin-bottom: 0;
}
.pool-cell {
// margin-bottom: 0.5em;
// margin-left: 2em;
// margin-right: 1em;
min-height: 6em;
max-width: 190px;
background-color: white;
}
/* row for all hosts/vms in a pool */
.hosts-vms-cells {
min-height: 6em;
margin-right: -0.8em;
}
/* individual host element */
.host-cell {
max-width: 156px;
background-color: white;
margin-bottom: 0.5em;
}
/* With gutters */
.grid--gutters {
// margin-left: -0.5em;
}
.grid--gutters > .grid-cell {
padding-left: 0.1em;
}
/* vm name in table */
.vm {
display: inline;
font-size: 10pt;
margin: 0;
}
.no-vm {
font-size: 1.5em;
margin-top: 1.8em;
color: #999;
}
.vm-cell table {
margin: 0;
}
.vm-cell td {
border-bottom: 1px solid #edece4 !important;
border-top: 0px !important;
text-overflow: ellipsis;
white-space: nowrap;
}
//////////////////////////////////////////////////////////////////////
// Pool view
//////////////////////////////////////////////////////////////////////
// Allow progress bar in small spaces, like tables
.progress-condensed {
@extend .progress;
margin-bottom: 0;
}
//////////////////////////////////////////////////////////////////////
// Host view
//////////////////////////////////////////////////////////////////////
// Memory progress bar stacked for host
.progress-bar-host {
@extend .progress-bar;
border-right: 1px solid white;
}
// Memory progress bar stacked for VM
.progress-bar-vm {
@extend .progress-bar-success;
border-right: 1px solid white;
}
// Hover color for progress bar
.progress-bar:hover {
background-color: #e25440;
}
.grid {
display: flex;
}
.stat-simple {
margin-top: 1em;
}
//////////////////////////////////////////////////////////////////////
// General object view
//////////////////////////////////////////////////////////////////////
.panel {
flex: 1;
margin: 0.4em;
}
.panel-heading {
text-align: center;
font-variant: small-caps;
font-size: 1.3em;
font-weight: bold;
}
.panel-body-stats {
@extend .panel-body;
padding: 5px;
}
.chart-stat-preview {
max-height: 8em;
text-align: center;
border-left: 1px solid #ddd;
border-right: 1px solid #ddd;
border-bottom: 1px solid #ddd;
}
.chart-stat-full {
max-height: 16em;
text-align: center;
}
.page-title {
text-align: center;
font-size: 2em;
margin: 0;
}
// display a big number for panel stats
.big-stat {
font-size: 5em;
color: #666;
}
// not so big stats
.mid-stat {
font-size: 2.5em;
color: #666;
}
//////////////////////////////////////////////////////////////////////
// Flat view
//////////////////////////////////////////////////////////////////////
.flat-object { @extend .panel; margin: 0.5em;}
.flat-object:hover {background-color: #f8f8f8;}
.flat-cell {border-radius: 0px; margin-left: 1em; margin-right: 1em; margin-top: 0.5em; margin-bottom: 0.5em;}
.flat-cell-name {max-width: 150px; min-width: 150px; font-weight: bold;}
.flat-cell-description {max-width: 250px; min-width: 250px;}
.flat-cell-type {max-width: 40px; font-size: 2em; text-align: center; margin: auto; margin-left: 0.5em;}
.flat-cell-tag {font-size: 11pt; margin: auto; min-height: 2.5em; padding-top: 0.4em; padding-left: 1em; opacity: 0.8;}
//////////////////////////////////////////////////////////////////////
// Login view
//////////////////////////////////////////////////////////////////////
.row-login {
@extend .panel;
background: #fff;
//padding: 20px 50px 20px 50px;
padding: 1em 5em 1em 5em;
max-width: 35em;
margin-left: auto;
margin-right: auto;
}
img.navbar-logo {
margin-top: -0.2em;
display: inline;
margin-right: 0.5em;
}
.navbar-brand {
font-variant: small-caps;
padding-top: 0.8em;
}
//////////////////////////////////////////////////////////////////////
// Settings
//////////////////////////////////////////////////////////////////////
.settings-menu {
background-color: #242628;
border-right: 1px solid #eee;
width: 212px;
}
.settings-menu li a {
font-size: 1em;
padding-left: 2em;
display: block;
color: #f8f8f8;
&:hover, &:focus {
background-color: #2e3133;
}
}
// smaller settings menu on smaller screen
@media (max-width: 970px) {
.settings-menu {
// 2em of padding + 2.29em of fa-fw
width: 3.29em;
}
.settings-menu li a {
padding-left: 1em;
padding-right: 1em;
}
.menu-entry {
display: none;
}
}
.settings-content {
flex: 1;
}
.fa-menu {
margin-right: 1.5em;
}
//////////////////////////////////////////////////////////////////////
// Object view
//////////////////////////////////////////////////////////////////////
// For table with only one line, e.g Docker list table etc
.oneliner {
text-overflow: ellipsis;
white-space: nowrap;
}

View File

@@ -1,227 +0,0 @@
/* Brand color */
.navbar-brand {color: #bf0000;}
input.form-control.inverse {background-color: #666; color: #f8f8f8; border: 0px;}
/* Search bar */
.popover { width: 200px; }
/* search button in main bar */
/* WARNING: hack because of strange Chrome behavior! Remove static height ASAP */
.btn-search {background-color: #3a87ad; color: #f8f8f8; height: 34px;}
.btn-search:hover {background-color: #1d4457; color: #f8f8f8;}
html {
background-color: #edece4;
/* Possibility to get a wallpaper for the background: see later in admin maybe, for the lulz */
/*background: url(bg.jpg) no-repeat center center fixed;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;*/
}
body {
background-color: transparent;
}
.navbar-under { background-color: #f8f8f8;}
td.vcenter {
vertical-align: middle;
}
input[type="checkbox"]{
padding-top: 0px;
line-height: normal;
}
input.inverse {margin: 0;}
/* progress bar */
.progress-small {
height: 0.6em;
width: 4em;
display: inline-block;
float: center;
margin: 3px;
}
.progress-bar-black {
color: black;
}
// FIXME: What is it?
//.i-progress { float: center; margin-right: 0em;}
.grey {color: #666; font-size: 0.9em;}
/* drodown head link for pools/hosts */
.dropdown-pool { border-bottom: 1px solid #edece4; text-align: center;}
.dropdown-pool a {
text-decoration: none;
color: #333;
}
.pool-name {font-size: 1.8em;}
.host-name {font-size: 20px;}
.big-caret {font-size: 1.4em;}
/* for dropdown menu not centered */
.dropdown-menu {background-color: white;}
.left {text-align: left;}
/* VM TABLE */
/* grab zone on VM table, for drag and drop */
td.grab {padding: 0 !important; margin: 0 !important; width: 6px !important; cursor: move;}
tr:hover .grab {background: url("../images/grip.png") no-repeat scroll 1px 50% transparent !important}
table { table-layout: fixed; }
table th, table td { overflow: hidden; }
td.vm-power-state {width: 20px; text-align: center;}
td.select-vm {width: 1.5em; height: 20px;}
td.vm-memory-stat {text-align: right;}
/* the main bar */
.navbar-inverse
{
background-color: #242628;
border-color: #2e3133;
//font-variant:small-caps;
}
.fa {font-variant: normal;}
/* the big subbar */
.sub-bar
{
height:50px;
top:50px;
position: fixed;
background:#242628;
border-bottom:1px solid #2e3133;
width:100%;
margin:0px auto;
z-index: 1020;
}
/* Black theme: inversed colors for drop down menus */
a.dropdown-toggle.inverse:hover {background-color:#2e3133 !important;}
a.dropdown-toggle.inverse:active {background-color:#2e3133 !important;}
a.dropdown-toggle.inverse:focus {background-color:#2e3133 !important;}
ul.inverse {background:#2e3133;}
ul.inverse a {color:#f8f8f8;}
ul.inverse a:hover {background-color:#242628; color: #f8f8f8 ;}
ul.inverse li.divider {background-color:#222;}
/* Inversed (black) buttons */
button.btn.navbar-btn.btn-default.inversed {background-color:#444; border-color: #222; color: #999999;}
a.btn.navbar-btn.btn-default.dropdown-toggle.inversed {background-color:#444; border-color: #222; color: #999999; margin-left: 0.5em;}
/* change caret color for inversed button */
.grey-caret {border-top-color: #999999 !important; border-bottom-color: #999999 !important;}
/* stats bar */
.overview { padding: 1em; color: #a6a6a6 ; max-width: 346px;}
.overview i {font-weight: normal;}
.small {font-size: 10pt; font-style: normal;}
.task-overview {
@extend .overview;
text-align: right;
}
.task-menu {
color: white;
}
/* stats pool and host */
.stats {text-align: center; margin-top: 1em; margin-bottom: 0.4em; padding-bottom: 0.4em; }
.stats a {text-decoration: none; color: #a6a6a6; margin-right: 0.6em;}
.stats a:hover {text-decoration: none; color: #333;}
.sr-name {font-size: 10pt;}
/* "actionbar" which is select and buttons when one or more VM selected */
.before-action-bar { margin-left: 1em;}
.action-bar {display: inline;}
/* SR table (in host and pool) */
.no-border {border-top: 0px !important;}
/* ip display */
.cpu {display: inline;}
.cpu a {text-decoration: none; color: #a6a6a6; margin-left: 0.9em;}
.cpu a:hover {text-decoration: none; color: #333;}
/* tooltip hack to avoid be hidden by other elements */
/*
.tooltip {
position: fixed;
}
*/
/* useful global class */
.center {text-align: center;}
.right {text-align: right;}
.small-caps {font-variant:small-caps;}
.big {font-size: 2em;}
.grid-cell {
flex: 1;
// border-radius: 3px 3px 3px 3px;
}
/* stats name in a grid cell */
.stat-name {text-align: center; font-variant: small-caps; margin-bottom: -0.3em;}
.grid-button {
margin-left: 1em;
margin-right: 1em;
margin-bottom: 0.5em;
padding: 0.5em;
background-color: #efefef;
}
.grid-button:hover {
background-color: #e25440;
}
.page-header {
border-bottom: 1px solid #FFFFFF;
padding-bottom: 9px;
text-align: center;
}
.form-control-login {
border: 1px solid #D6D6D6;
border-radius: 0;
box-shadow: none;
height: 50px;
padding: 6px 15px;
}
legend.login {
border: medium none;
color: #111;
display: block;
font-size: 20px;
line-height: inherit;
margin-bottom: 15px;
padding: 0;
text-align: center;
width: 100%;
}
.btn-login {
padding: 10px;
border-radius: 0;
border: none;
font-size: 21px;
}
.status {
margin-top: 2em;
}

View File

@@ -1,16 +0,0 @@
{
"name": "xo-web",
"version": "0.0.0",
"dependencies": {
"angular-natural-sort": "https://bitbucket.org/OverZealous/angularjs-naturalsort/raw/f6e7ea30bf71324125549bd40a7cf9043abc2449/src/naturalSortVersionDates.js",
"angular-notify-toaster": "~0.4.8",
"angular-xeditable": "~0.1.8",
"ng-file-upload": "~1.6.12",
"angular-ui-select": "~0.9.9",
"Chart.js": "~1.0.2",
"angular-chart.js": "~0.5.3"
},
"resolutions": {
"angular": "~1.x"
}
}

View File

@@ -1,46 +1,15 @@
// Julien Fontanet gulpfile.js
//
// https://gist.github.com/julien-f/4af9f3865513efeff6ab
'use strict'
// ===================================================================
var gulp = require('gulp')
// All plugins are loaded (on demand) by gulp-load-plugins.
var $ = require('gulp-load-plugins')()
var pipe = require('nice-pipe')
// ===================================================================
var DIST_DIR = __dirname +'/dist'
var SRC_DIR = __dirname +'/app'
// Bower directory is read from its configuration.
var BOWER_DIR = (function () {
var cfg
try {
cfg = JSON.parse(require('fs').readFileSync(__dirname +'/.bowerrc'))
} catch (error) {
cfg = {}
}
cfg.cwd || (cfg.cwd = __dirname)
cfg.directory || (cfg.directory = 'bower_components')
return cfg.cwd +'/'+ cfg.directory
})()
var PRODUCTION = process.argv.indexOf('--production') !== -1
var SRC_DIR = __dirname + '/src' // eslint-disable-line no-path-concat
var DIST_DIR = __dirname + '/dist' // eslint-disable-line no-path-concat
// Port to use for the livereload server.
//
// It must be available and if possible unique to not conflict with other projects.
// http://www.random.org/integers/?num=1&min=1024&max=65535&col=1&base=10&format=plain&rnd=new
var LIVERELOAD_PORT = 46417
var LIVERELOAD_PORT = 26242
// Port to use for the embedded web server.
//
@@ -53,274 +22,304 @@ var SERVER_PORT = LIVERELOAD_PORT + 1
// - `null` to make it accessible for the whole network
var SERVER_ADDR = 'localhost'
// -------------------------------------------------------------------
var PRODUCTION = process.env.NODE_ENV === 'production'
var DEVELOPMENT = !PRODUCTION
// Create a noop duplex stream.
var noop = function () {
var PassThrough = require('stream').PassThrough
noop = function () {
return new PassThrough({
objectMode: true
})
}
return noop.apply(this, arguments)
if (!process.env.XOA_PLAN) {
process.env.XOA_PLAN = '5' // Open Source
}
// Browserify plugin for gulp.js which uses watchify in development
// mode.
function browserify (path, opts) {
opts || (opts = {})
// ===================================================================
var bundler = require('browserify')({
var gulp = require('gulp')
// ===================================================================
function lazyFn (factory) {
var fn = function () {
fn = factory()
return fn.apply(this, arguments)
}
return function () {
return fn.apply(this, arguments)
}
}
// -------------------------------------------------------------------
var livereload = lazyFn(function () {
var livereload = require('gulp-refresh')
livereload.listen({
port: LIVERELOAD_PORT
})
return livereload
})
var pipe = lazyFn(function () {
var current
function pipeCore (streams) {
var i, n, stream
for (i = 0, n = streams.length; i < n; ++i) {
stream = streams[i]
if (!stream) {
// Nothing to do
} else if (stream instanceof Array) {
pipeCore(stream)
} else {
current = current
? current.pipe(stream)
: stream
}
}
}
var push = Array.prototype.push
return function (streams) {
try {
if (!(streams instanceof Array)) {
streams = []
push.apply(streams, arguments)
}
pipeCore(streams)
return current
} finally {
current = null
}
}
})
var resolvePath = lazyFn(function () {
return require('path').resolve
})
// -------------------------------------------------------------------
// Similar to `gulp.src()` but the pattern is relative to `SRC_DIR`
// and files are automatically watched when not in production mode.
var src = lazyFn(function () {
function resolve (path) {
return path
? resolvePath(SRC_DIR, path)
: SRC_DIR
}
return PRODUCTION
? function src (pattern, opts) {
var base = resolve(opts && opts.base)
return gulp.src(pattern, {
base: base,
cwd: base,
passthrough: opts && opts.passthrough,
sourcemaps: opts && opts.sourcemaps
})
}
: function src (pattern, opts) {
var base = resolve(opts && opts.base)
return pipe(
gulp.src(pattern, {
base: base,
cwd: base,
passthrough: opts && opts.passthrough,
sourcemaps: opts && opts.sourcemaps
}),
require('gulp-watch')(pattern, {
base: base,
cwd: base
}),
require('gulp-plumber')()
)
}
})
// Similar to `gulp.dest()` but the output directory is relative to
// `DIST_DIR` and default to `./`, and files are automatically live-
// reloaded when not in production mode.
var dest = lazyFn(function () {
function resolve (path) {
return path
? resolvePath(DIST_DIR, path)
: DIST_DIR
}
var opts = {
sourcemaps: {
path: '.'
}
}
return PRODUCTION
? function dest (path) {
return gulp.dest(resolve(path), opts)
}
: function dest (path) {
var stream = gulp.dest(resolve(path), opts)
stream.pipe(livereload())
return stream
}
})
// ===================================================================
function browserify (path, opts) {
if (opts == null) {
opts = {}
}
var bundler = require('browserify')(path, {
basedir: SRC_DIR,
debug: !PRODUCTION,
entries: [path],
debug: DEVELOPMENT, // TODO: enable also in production but need to make it work with gulp-uglify.
extensions: opts.extensions,
fullPaths: false,
paths: SRC_DIR + '/common',
standalone: opts.standalone,
// Required by Watchify.
cache: {},
packageCache: {},
fullPaths: !PRODUCTION
packageCache: {}
})
if (!PRODUCTION) {
var plugins = opts.plugins
for (var i = 0, n = plugins && plugins.length; i < n; ++i) {
var plugin = plugins[i]
bundler.plugin(require(plugin[0]), plugin[1])
}
if (PRODUCTION) {
// FIXME: does not work with react-intl (?!)
// bundler.plugin('bundle-collapser/plugin')
} else {
bundler = require('watchify')(bundler)
bundler.plugin('bundle-collapser/plugin')
}
// Append the extension if necessary.
if (!/\.js$/.test(path)) {
path += '.js'
}
path = resolvePath(SRC_DIR, path)
// Absolute path.
path = require('path').resolve(SRC_DIR, path)
var proxy = noop()
var stream = new (require('readable-stream'))({
objectMode: true
})
var write
function bundle () {
bundler.bundle(function onBundleComplete (err, buf) {
if (err) {
proxy.emit('error', err)
bundler.bundle(function onBundle (error, buffer) {
if (error) {
stream.emit('error', error)
return
}
write(new (require('vinyl'))({
base: SRC_DIR,
path: path,
contents: buf
contents: buffer,
path: path
}))
})
}
if (PRODUCTION) {
write = proxy.end.bind(proxy)
write = function (data) {
stream.push(data)
stream.push(null)
}
} else {
proxy = $.plumber().pipe(proxy)
write = proxy.write.bind(proxy)
stream = require('gulp-plumber')().pipe(stream)
write = function (data) {
stream.push(data)
}
bundler.on('update', bundle)
}
bundle()
return proxy
stream._read = function () {
this._read = function () {}
bundle()
}
return stream
}
// Combine multiple streams together and can be handled as a single
// stream.
var combine = function () {
// `event-stream` is required only when necessary to maximize
// performance.
combine = require('event-stream').pipe
return combine.apply(this, arguments)
}
// Merge multiple readable streams into a single one.
var merge = function () {
// `event-stream` is required only when necessary to maximize
// performance.
merge = require('event-stream').merge
return merge.apply(this, arguments)
}
// Similar to `gulp.src()` but the pattern is relative to `SRC_DIR`
// and files are automatically watched when not in production mode.
var src = (function () {
var resolvePath = require('path').resolve
function resolve (path) {
if (path) {
return resolvePath(SRC_DIR, path)
}
return SRC_DIR
}
if (PRODUCTION) {
return function src (pattern, base) {
base = resolve(base)
return gulp.src(pattern, {
base: base,
cwd: base
})
}
}
// gulp-plumber prevents streams from disconnecting when errors.
// See: https://gist.github.com/floatdrop/8269868#file-thoughts-md
return function src (pattern, base) {
base = resolve(base)
return gulp.src(pattern, {
base: base,
cwd: base
})
.pipe($.watch(pattern, {
base: base,
cwd: base
}))
.pipe($.plumber())
}
})()
// Similar to `gulp.dest()` but the output directory is relative to
// `DIST_DIR` and default to `./`, and files are automatically live-
// reloaded when not in production mode.
var dest = (function () {
var resolvePath = require('path').resolve
function resolve (path) {
if (path) {
return resolvePath(DIST_DIR, path)
}
return DIST_DIR
}
if (PRODUCTION) {
return function dest (path) {
return gulp.dest(resolve(path))
}
}
var livereload = function () {
$.livereload.listen(LIVERELOAD_PORT)
livereload = $.livereload
return livereload()
}
return function dest (path) {
return combine(
gulp.dest(resolve(path)),
livereload()
)
}
})()
// ===================================================================
gulp.task('buildPages', function buildPages () {
return pipe([
src('[i]ndex.jade'),
$.jade(),
!PRODUCTION && $.embedlr({ port: LIVERELOAD_PORT }),
dest(),
])
gulp.task(function buildPages () {
return pipe(
src('index.jade', { sourcemaps: true }),
require('gulp-jade')(),
DEVELOPMENT && require('gulp-embedlr')({
port: LIVERELOAD_PORT
}),
dest()
)
})
gulp.task('buildScripts', [
'installBowerComponents'
], function buildScripts () {
return pipe([
browserify('./app.js', {
extensions: '.coffee .jade'.split(' ')
gulp.task(function buildScripts () {
return pipe(
browserify('./index.js', {
plugins: [
// ['css-modulesify', {
['modular-css/browserify', {
css: DIST_DIR + '/modules.css'
}]
]
}),
PRODUCTION && $.uglify({ mangle: false }),
dest(),
])
PRODUCTION && require('gulp-uglify')(),
dest()
)
})
gulp.task('buildStyles', [
'installBowerComponents'
], function buildStyles () {
return pipe([
src('styles/[m]ain.scss'),
!PRODUCTION && $.sourcemaps.init({
loadMaps: true
}),
$.sass(),
$.autoprefixer([
gulp.task(function buildStyles () {
return pipe(
src('index.scss', { sourcemaps: true }),
require('gulp-sass')(),
require('gulp-autoprefixer')([
'last 1 version',
'> 1%'
]),
PRODUCTION && $.minifyCss(),
!PRODUCTION && $.sourcemaps.write(),
dest(),
])
PRODUCTION && require('gulp-csso')(),
dest()
)
})
gulp.task('copyAssets', [
'installBowerComponents'
], function copyAssets () {
var imgStream
if (PRODUCTION) {
var imgFilter = $.filter('**/*.{gif,jpg,jpeg,png,svg}')
imgStream = combine(
imgFilter,
$.imagemin({
progressive: true
}),
imgFilter.restore()
)
} else {
imgStream = noop()
}
return pipe([
merge(
src([
'[f]avicon.ico',
'images/**/*'
]).pipe(imgStream),
src(
'fontawesome-webfont.*',
__dirname + '/node_modules/font-awesome/fonts/'
)
),
dest(),
])
gulp.task(function copyAssets () {
return pipe(
src(['assets/**/*', 'favicon.*']),
src('fontawesome-webfont.*', {
base: __dirname + '/node_modules/font-awesome/fonts', // eslint-disable-line no-path-concat
passthrough: true
}),
src(['!*.css', 'font-mfizz.*'], {
base: __dirname + '/node_modules/font-mfizz/dist', // eslint-disable-line no-path-concat
passthrough: true
}),
dest()
)
})
gulp.task('installBowerComponents', function installBowerComponents (done) {
require('bower').commands.install()
.on('error', done)
.on('end', function () {
done()
})
})
// -------------------------------------------------------------------
gulp.task('build', [
gulp.task('build', gulp.parallel(
'buildPages',
'buildScripts',
'buildStyles',
'copyAssets'
])
))
gulp.task('clean', function clear (done) {
// -------------------------------------------------------------------
gulp.task(function clean (done) {
require('rimraf')(DIST_DIR, done)
})
gulp.task('distclean', ['clean'], function distclean (done) {
require('rimraf')(BOWER_DIR, done)
})
// -------------------------------------------------------------------
gulp.task('server', function server (done) {
gulp.task(function server (done) {
require('connect')()
.use(require('serve-static')(DIST_DIR))
.listen(SERVER_PORT, SERVER_ADDR, function serverOnListen () {
.listen(SERVER_PORT, SERVER_ADDR, function onListen () {
var address = this.address()
var port = address.port
@@ -331,13 +330,11 @@ gulp.task('server', function server (done) {
address = '[' + address + ']'
}
/* jshint devel: true*/
console.log('Listening on http://' + address + ':' + port)
})
.on('close', function serverOnClose () {
.on('error', done)
.on('close', function onClose () {
done()
})
})
// -----------------------------------------------------------------------------
gulp.task('default', ['build'])

17
node_modules/angular-file-upload.js generated vendored
View File

@@ -1,17 +0,0 @@
'use strict';
//====================================================================
/* global window: false */
window.FileApi = {
jsPath: '/bower_components/ng-file-upload/',
staticPath: '/bower_components/ng-file-upload/',
};
// Must be loaded before Angular.
require('../dist/bower_components/ng-file-upload/angular-file-upload-shim');
require('angular');
require('../dist/bower_components/ng-file-upload/angular-file-upload');
module.exports = 'angularFileUpload';

View File

@@ -1,4 +0,0 @@
'use strict';
require('../dist/bower_components/angular-natural-sort/index');
module.exports = 'naturalSort';

View File

@@ -1,4 +0,0 @@
'use strict';
require('../dist/bower_components/angular-notify-toaster/toaster.js');
module.exports = 'toaster';

View File

@@ -1,7 +0,0 @@
'use strict';
//====================================================================
require('angular-bootstrap');
module.exports = 'ui.bootstrap';

4
node_modules/angular-ui-event.js generated vendored
View File

@@ -1,4 +0,0 @@
'use strict';
require('./angular-ui-utils/modules/event/event');
module.exports = 'ui.event';

View File

@@ -1,4 +0,0 @@
'use strict';
require('./angular-ui-utils/modules/indeterminate/indeterminate');
module.exports = 'ui.indeterminate';

5
node_modules/angular-ui-select.js generated vendored
View File

@@ -1,5 +0,0 @@
'use strict';
require('../dist/bower_components/angular-ui-select/dist/select');
module.exports = 'ui.select';

4
node_modules/angular-xeditable.js generated vendored
View File

@@ -1,4 +0,0 @@
'use strict';
require('../dist/bower_components/angular-xeditable/dist/js/xeditable');
module.exports = 'xeditable';

8
node_modules/angular.js generated vendored
View File

@@ -1,8 +0,0 @@
'use strict';
//====================================================================
// Force Angular to use jQuery.
require('jquery');
module.exports = require('./angular/index.js');

10
node_modules/jquery.js generated vendored
View File

@@ -1,10 +0,0 @@
'use strict';
//====================================================================
var jQuery = require('./jquery/dist/jquery');
/* global window: false */
window.jQuery = window.$ = jQuery;
module.exports = jQuery;

View File

@@ -1,6 +1,7 @@
{
"private": false,
"name": "xo-web",
"version": "4.0.1",
"version": "5.0.5",
"license": "AGPL-3.0",
"description": "Web interface client for Xen-Orchestra",
"keywords": [
@@ -9,67 +10,8 @@
"xen-orchestra",
"web"
],
"devDependencies": {
"@julien-f/json-rpc": "^0.4.3",
"angular": "^1.4.0",
"angular-animate": "^1.4.0",
"angular-bootstrap": "^0.12.0",
"angular-cookies": "^1.4.0",
"angular-ui-router": "^0.2.13",
"angular-ui-utils": "^0.1.1",
"ansi_up": "^1.1.3",
"babelify": "^6.0.2",
"bluebird": "^2.9.14",
"bootstrap-sass": "^3.3.4",
"bower": "^1.3.12",
"browserify": "^10.2.1",
"browserify-plain-jade": "^0.2.2",
"bundle-collapser": "^1.1.4",
"coffeeify": "^1.0.0",
"event-stream": "^3.3.0",
"font-awesome": "^4.3.0",
"gulp": "^3.8.11",
"gulp-autoprefixer": "^2.1.0",
"gulp-embedlr": "^0.5.2",
"gulp-filter": "^2.0.2",
"gulp-imagemin": "^2.2.1",
"gulp-jade": "^1.0.0",
"gulp-livereload": "^3.8.0",
"gulp-load-plugins": "^0.10.0",
"gulp-minify-css": "^1.1.1",
"gulp-plumber": "^1.0.0",
"gulp-sass": "^2.0.1",
"gulp-sourcemaps": "^1.5.2",
"gulp-uglify": "^1.1.0",
"gulp-watch": "^4.2.0",
"in-publish": "^1.1.1",
"jquery": "^2.1.3",
"lodash.assign": "^3.1.0",
"lodash.clonedeep": "^3.0.1",
"lodash.difference": "^3.0.1",
"lodash.filter": "^3.0.0",
"lodash.foreach": "^3.0.3",
"lodash.includes": "^3.1.1",
"lodash.indexof": "^3.0.2",
"lodash.intersection": "^3.1.0",
"lodash.isempty": "^3.0.3",
"lodash.map": "^3.1.2",
"lodash.omit": "^3.1.0",
"lodash.slice": "^3.0.0",
"lodash.sortby": "^3.1.0",
"lodash.sum": "^3.6.1",
"lodash.throttle": "^3.0.1",
"make-error": "^1.0.2",
"nice-pipe": "^0.2.2",
"novnc-node": "^0.5.1",
"rimraf": "^2.3.2",
"socket.io-client": "^1.3.5",
"vinyl": "^0.4.6",
"watchify": "^3.1.1",
"ws": "^0.7.2",
"xo-collection": "^0.3.2",
"xo-lib": "^0.7.2"
},
"homepage": "https://github.com/vatesfr/xo-web",
"bugs": "https://github.com/vatesfr/xo-web/issues",
"repository": {
"type": "git",
"url": "https://github.com/vatesfr/xo-web"
@@ -78,27 +20,155 @@
"name": "Julien Fontanet",
"email": "julien.fontanet@vates.fr"
},
"preferGlobal": false,
"main": "dist/",
"bin": {},
"files": [
"dist/"
],
"engines": {
"node": ">=0.8.0"
"node": ">=4",
"npm": ">=3"
},
"devDependencies": {
"ansi_up": "^1.3.0",
"asap": "^2.0.4",
"ava": "^0.15.0",
"babel-eslint": "^6.0.0",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"babel-plugin-transform-react-constant-elements": "^6.5.0",
"babel-plugin-transform-react-inline-elements": "^6.6.5",
"babel-plugin-transform-runtime": "^6.6.0",
"babel-preset-es2015": "^6.6.0",
"babel-preset-react": "^6.5.0",
"babel-preset-stage-0": "^6.5.0",
"babel-runtime": "^6.6.1",
"babelify": "^7.2.0",
"benchmark": "^2.1.0",
"bootstrap": "github:twbs/bootstrap#v4-dev",
"browserify": "^13.0.0",
"bundle-collapser": "^1.2.1",
"chartist-plugin-legend": "^0.3.1",
"chartist-plugin-tooltip": "0.0.11",
"classnames": "^2.2.3",
"connect": "^3.4.1",
"cookies-js": "^1.2.2",
"d3": "^4.0.0-alpha.50",
"dependency-check": "^2.5.1",
"font-awesome": "^4.5.0",
"font-mfizz": "github:fizzed/font-mfizz",
"ghooks": "^1.1.1",
"globby": "^5.0.0",
"gulp": "github:gulpjs/gulp#4.0",
"gulp-autoprefixer": "^3.1.0",
"gulp-csso": "^2.0.0",
"gulp-embedlr": "^0.5.2",
"gulp-jade": "^1.1.0",
"gulp-plumber": "^1.1.0",
"gulp-refresh": "^1.1.0",
"gulp-sass": "^2.2.0",
"gulp-uglify": "^1.5.3",
"gulp-watch": "^4.3.5",
"human-format": "^0.6.0",
"jsonrpc-websocket-client": "0.0.1-5",
"later": "^1.2.0",
"lodash": "^4.6.1",
"loose-envify": "^1.1.0",
"marked": "^0.3.5",
"modular-css": "^0.22.1",
"moment": "^2.13.0",
"notifyjs": "^2.0.1",
"novnc-node": "^0.5.3",
"promise-toolbox": "^0.4.0",
"random-password": "^0.1.2",
"react": "^15.0.0",
"react-addons-shallow-compare": "^15.1.0",
"react-bootstrap-4": "^0.29.1",
"react-chartist": "^0.10.1",
"react-copy-to-clipboard": "^4.0.2",
"react-debounce-input": "^2.4.0",
"react-dnd": "^2.1.4",
"react-dnd-html5-backend": "^2.1.2",
"react-dom": "^15.0.0",
"react-dropzone": "^3.5.0",
"react-intl": "^2.0.1",
"react-key-handler": "^0.2.0",
"react-notify": "^2.0.1",
"react-redux": "^4.4.0",
"react-router": "^3.0.0-alpha.1",
"react-select": "^1.0.0-beta13",
"react-sparklines": "^1.5.0",
"react-virtualized": "^7.4.0",
"readable-stream": "^2.0.6",
"redux": "^3.3.1",
"redux-devtools": "^3.1.1",
"redux-devtools-dock-monitor": "^1.1.0",
"redux-devtools-log-monitor": "^1.0.5",
"redux-thunk": "^2.0.1",
"reselect": "^2.2.1",
"serve-static": "^1.10.2",
"standard": "^7.0.0",
"superagent": "^2.0.0",
"vinyl": "^1.1.1",
"watchify": "^3.7.0",
"xo-acl-resolver": "^0.2.1",
"xo-lib": "^0.8.0-1",
"xo-remote-parser": "^0.3"
},
"scripts": {
"build": "gulp distclean && gulp build --production",
"dev": "gulp build",
"prepublish": "in-publish && npm run build || in-install"
"benchmarks": "./tools/run-benchmarks.js 'src/**/*.bench.js'",
"build": "npm run build-indexes && NODE_ENV=production gulp build",
"build-indexes": "./tools/generate-index src/common/intl/locales",
"dev": "npm run build-indexes && gulp build server",
"dev-test": "ava --watch",
"lint": "standard",
"posttest": "npm run lint",
"prepublish": "npm run build",
"test": "ava"
},
"files": [
"dist"
],
"browserify": {
"transform": [
"babelify",
"browserify-plain-jade",
"coffeeify"
"loose-envify"
]
},
"ava": {
"babel": "inherit",
"files": [
"src/**/*.spec.js"
],
"require": [
"babel-register"
]
},
"babel": {
"env": {
"production": {
"plugins": [
"transform-react-constant-elements",
"transform-react-inline-elements"
]
}
},
"plugins": [
"transform-decorators-legacy",
"transform-runtime"
],
"presets": [
"es2015",
"react",
"stage-0"
]
},
"config": {
"ghooks": {
"commit-msg": "npm test"
}
},
"standard": {
"ignore": [
"dist"
]
],
"parser": "babel-eslint"
}
}

1
src/assets/loading.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" encoding="utf-8"?><svg width='62px' height='62px' xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" class="uil-ring-alt"><rect x="0" y="0" width="100" height="100" fill="none" class="bk"></rect><circle cx="50" cy="50" r="40" stroke="#cfcfcf" fill="none" stroke-width="10" stroke-linecap="round"></circle><circle cx="50" cy="50" r="40" stroke="#366e98" fill="none" stroke-width="6" stroke-linecap="round"><animate attributeName="stroke-dashoffset" dur="1s" repeatCount="indefinite" from="0" to="502"></animate><animate attributeName="stroke-dasharray" dur="1s" repeatCount="indefinite" values="150.6 100.4;1 250;150.6 100.4"></animate></circle></svg>

After

Width:  |  Height:  |  Size: 707 B

View File

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

123
src/chartist.scss Normal file
View File

@@ -0,0 +1,123 @@
// CHARTIST ===================================================================
$ct-series-colors: (
$brand-success,
$brand-primary,
#60bd68,
#f17cb0,
#b2912f,
#b276b2,
#decf3f,
#f15854,
#4d4d4d,
#dda458,
#eacf7d,
#86797d,
#b2c326,
#6188e2,
#a748ca
) !default;
@import "../node_modules/chartist/dist/scss/settings/_chartist-settings";
@import "../node_modules/chartist/dist/scss/chartist";
// Line in charts with only 2px in width
.ct-line {
stroke-width: 2px;
}
.ct-bar {
stroke-width: 10%;
}
.ct-point {
stroke-width: 30px;
stroke-opacity: 0!important;
}
.ct-point:hover {
stroke-opacity: 0.2!important;
stroke-width: 20px;
}
.ct-tooltip {
position: absolute;
display: inline-block;
min-width: 5em;
padding: 8px 10px;
background: #383838;
color: #fff;
text-align: center;
pointer-events: none;
z-index: 10;
font-weight: 700;
// Arrow!
&:before {
position: absolute;
bottom: -14px;
top: 100%;
left: 50%;
border: solid transparent;
content: '';
height: 0;
width: 0;
pointer-events: none;
border-color: rgba(251, 249, 228, 0);
border-top-color: #383838;
border-width: 7px;
margin-left: -8px;
}
&.hide {
display: block;
opacity: 0;
visibility: hidden;
}
}
// CHARTIST LEGEND =============================================================
.ct-legend {
position: absolute;
bottom: 0;
margin-bottom: -1em;
li {
position: relative;
padding-left: 1.4em;
list-style-type: none;
display: inline;
margin-right: 0.5em;
font-size: 0.8em;
}
li:before {
width: 1em;
height: 1em;
position: absolute;
left: 0;
content: '';
border: 3px solid transparent;
border-radius: 2px;
margin-top: 0.5em;
}
li.inactive:before {
background: transparent;
}
&.ct-legend-inside {
position: absolute;
top: 0;
right: 0;
}
@for $i from 0 to length($ct-series-colors) {
.ct-series-#{$i}:before {
background-color: nth($ct-series-colors, $i + 1);
border-color: nth($ct-series-colors, $i + 1);
}
}
}

36
src/common/action-bar.js Normal file
View File

@@ -0,0 +1,36 @@
// import _ from 'intl' TODO: fix tooltip
import ActionButton from 'action-button'
import map from 'lodash/map'
import React from 'react'
// import Tooltip from 'tooltip' TODO: fix tooltip
import {
ButtonGroup
} from 'react-bootstrap-4/lib'
const ActionBar = ({ actions, param }) => (
<ButtonGroup>
{map(actions, ({ handler, handlerParam = param, label, icon }, index) => (
/* <Tooltip key={index} content={_(label)}> TODO: fix tooltip */
<ActionButton
key={index}
btnStyle='secondary'
handler={handler}
handlerParam={handlerParam}
icon={icon}
size='large'
/>
/* </Tooltip> */
))}
</ButtonGroup>
)
ActionBar.propTypes = {
actions: React.PropTypes.arrayOf(
React.PropTypes.shape({
label: React.PropTypes.string.isRequired,
icon: React.PropTypes.string.isRequired,
handler: React.PropTypes.func
})
).isRequired,
display: React.PropTypes.oneOf(['icon', 'text', 'both'])
}
export { ActionBar as default }

119
src/common/action-button.js Normal file
View File

@@ -0,0 +1,119 @@
import Icon from 'icon'
import isFunction from 'lodash/isFunction'
import React from 'react'
import { Button } from 'react-bootstrap-4/lib'
import Component from './base-component'
import logError from './log-error'
import propTypes from './prop-types'
@propTypes({
btnStyle: propTypes.string,
disabled: propTypes.bool,
form: propTypes.string,
handler: propTypes.func.isRequired,
handlerParam: propTypes.any,
icon: propTypes.string.isRequired,
redirectOnSuccess: propTypes.oneOfType([
propTypes.func,
propTypes.string
]),
size: propTypes.oneOf([
'large',
'small'
])
})
export default class ActionButton extends Component {
static contextTypes = {
router: React.PropTypes.object
}
async _execute () {
if (this.state.working) {
return
}
const {
handler,
handlerParam
} = this.props
try {
this.setState({
error: null,
working: true
})
const result = await handler(handlerParam)
let { redirectOnSuccess } = this.props
if (redirectOnSuccess) {
if (isFunction(redirectOnSuccess)) {
redirectOnSuccess = redirectOnSuccess(result)
}
return this.context.router.push(redirectOnSuccess)
}
this.setState({
working: false
})
} catch (error) {
this.setState({
error,
working: false
})
logError(error)
}
}
_execute = ::this._execute
_eventListener = event => {
event.preventDefault()
this._execute()
}
componentDidMount () {
const { form } = this.props
if (form) {
document.getElementById(form).addEventListener('submit', this._eventListener)
}
}
componentWillUnmount () {
const { form } = this.props
if (form) {
document.getElementById(form).removeEventListener('submit', this._eventListener)
}
}
render () {
const {
props: {
btnStyle,
children,
className,
disabled,
form,
icon,
size: bsSize,
style
},
state: { error, working }
} = this
return <Button
bsStyle={error ? 'warning' : btnStyle}
form={form}
onClick={!form && this._execute}
disabled={working || disabled}
type={form ? 'submit' : 'button'}
{...{ bsSize, className, style }}
>
<Icon icon={working ? 'loading' : icon} fixedWidth />
{children && ' '}
{children}
</Button>
}
}

View File

@@ -0,0 +1,7 @@
.button {
opacity: 0.5;
}
tr:hover .button, tr:focus .button {
opacity: 1;
}

View File

@@ -0,0 +1,14 @@
import React from 'react'
import ActionButton from '../action-button'
import styles from './index.css'
const ActionRowButton = props => (
<ActionButton
{...props}
className={styles.button}
size='small'
/>
)
export { ActionRowButton as default }

Some files were not shown because too many files have changed in this diff Show More