[PATCH] Issue #296 [enhance]kimchi UI should not waiting while generating reports

1) Removed the dialogue window when generating a debug report. 2) Designed an animation bar indicate user there is a report generating during the generating progress. 3) Disable the buttons' functions in debug report area when generating a new report in case there might be any conflict. Meanwhile user can operate on other parts of Kimchi. 4) Enable all buttonss' functions in debug report area after generating progress. --- ui/css/theme-default/host.css | 22 +++++++++++++++++++++ ui/js/src/kimchi.report_add_main.js | 38 ++++++++++++++++++++++++++++++++----- 2 files changed, 55 insertions(+), 5 deletions(-) diff --git a/ui/css/theme-default/host.css b/ui/css/theme-default/host.css index 6a1a308..c684c0a 100644 --- a/ui/css/theme-default/host.css +++ b/ui/css/theme-default/host.css @@ -219,6 +219,28 @@ width: 200px; } +#id-generate-bar { + text-align: center; + vertical-align: middle; +} + +#id-generate-panel { + vertical-align: middle; + margin: 0 auto; + text-align: center; + height: 20px; + width: 250px; + color: #fff; + border: 1px solid #ccc; + background-color: #5af; +} + +#id-generating { + font-color: #fff; + background: #5af url(../../images/theme-default/loading.gif) 7px + center no-repeat; + padding-left: 26px; +} /* End of Debug Report */ /* Software Updates */ diff --git a/ui/js/src/kimchi.report_add_main.js b/ui/js/src/kimchi.report_add_main.js index 8759c2b..1e5df89 100644 --- a/ui/js/src/kimchi.report_add_main.js +++ b/ui/js/src/kimchi.report_add_main.js @@ -1,4 +1,5 @@ kimchi.report_add_main = function() { + var reportGridID = 'available-reports-grid'; var addReportForm = $('#form-report-add'); var submitButton = $('#button-report-add'); var nameTextbox = $('input[name="name"]', addReportForm); @@ -13,12 +14,39 @@ kimchi.report_add_main = function() { return false; } var formData = addReportForm.serializeObject(); - submitButton - .text(i18n['KCHDR6007M']) - .prop('disabled', true); - nameTextbox.prop('disabled', true); + kimchi.window.close(); + var reportGrid = null; + $('#' + reportGridID + '-generate-button').prop('disabled',true); + $('#' + reportGridID + '-remove-button').prop('disabled',true); + $('#' + reportGridID + '-download-button').prop('disabled',true); + $('#' + reportGridID + '-rename-button').prop('disabled',true); + $('#available-reports-grid').find('.grid-body').find('table').find('tr').click(function() { + $('#' + reportGridID + '-remove-button').prop('disabled',true); + $('#' + reportGridID + '-download-button').prop('disabled',true); + $('#' + reportGridID + '-rename-button').prop('disabled',true); + }); + var len = $('#available-reports-grid').find('.grid-frozen-body-view').find('tr').length + 1; + $('#available-reports-grid').find('.grid-frozen-body-view').find('table').append('<tr id="temp-row-col1"><td>' + len + '</td></tr>'); + $('#available-reports-grid').find('.grid-body-view').find('table').append('<tr id="temp-row-col2"><td id="id-generate-bar"; colspan="2"></td></tr>'); + var textboxValue = $('#report-name-textbox').val(); + if (textboxValue != "") { + if (textboxValue.length <= 15) { + $('#id-generate-bar').append('<div id="id-generate-panel"></div>'); + $('#id-generate-panel').append('<label id="id-generating"><span>' + '"' + textboxValue +'" ' + i18n['KCHDR6007M'] + '</span></label>'); + } + else { + $('#id-generate-bar').append('<div id="id-generate-panel"></div>'); + $('#id-generate-panel').append('<label id="id-generating"><span>' + '"' + textboxValue.substring(0,13) +'..." ' + i18n['KCHDR6007M'] + '</span></label>'); + } + } + else { + $('#id-generate-bar').append('<div id="id-generate-panel"></div>'); + $('#id-generate-panel').append('<label id="id-generating"><span>' + i18n['KCHDR6007M'] + '</span></label>'); + } kimchi.createReport(formData, function(result) { - kimchi.window.close(); + $('#temp-row-col1').remove(); + $('#temp-row-col2').remove(); + $('#' + reportGridID + '-generate-button').prop('disabled',false); kimchi.topic('kimchi/debugReportAdded').publish({ result: result }); -- 1.9.1

1) Removed the dialogue window when generating a debug report. 2) Designed an animation bar indicate user there is a report generating during the generating progress. 3) Disable the buttons' functions in debug report area when generating a new report in case there might be any conflict. Meanwhile user can operate on other parts of Kimchi. 4) Enable all buttonss' functions in debug report area after generating progress. --- ui/css/theme-default/host.css | 22 +++++++++++++++++++++ ui/js/src/kimchi.report_add_main.js | 38 ++++++++++++++++++++++++++++++++----- 2 files changed, 55 insertions(+), 5 deletions(-)
diff --git a/ui/css/theme-default/host.css b/ui/css/theme-default/host.css index 6a1a308..c684c0a 100644 --- a/ui/css/theme-default/host.css +++ b/ui/css/theme-default/host.css @@ -219,6 +219,28 @@ width: 200px; }
+#id-generate-bar { + text-align: center; + vertical-align: middle; +} + +#id-generate-panel { + vertical-align: middle; + margin: 0 auto; + text-align: center; + height: 20px; + width: 250px; + color: #fff; + border: 1px solid #ccc; + background-color: #5af; +} + +#id-generating { + font-color: #fff; + background: #5af url(../../images/theme-default/loading.gif) 7px + center no-repeat; + padding-left: 26px; +} /* End of Debug Report */
/* Software Updates */ diff --git a/ui/js/src/kimchi.report_add_main.js b/ui/js/src/kimchi.report_add_main.js index 8759c2b..1e5df89 100644 --- a/ui/js/src/kimchi.report_add_main.js +++ b/ui/js/src/kimchi.report_add_main.js @@ -1,4 +1,5 @@ kimchi.report_add_main = function() { + var reportGridID = 'available-reports-grid'; var addReportForm = $('#form-report-add'); var submitButton = $('#button-report-add'); var nameTextbox = $('input[name="name"]', addReportForm); @@ -13,12 +14,39 @@ kimchi.report_add_main = function() { return false; } var formData = addReportForm.serializeObject(); - submitButton - .text(i18n['KCHDR6007M']) - .prop('disabled', true); - nameTextbox.prop('disabled', true); + kimchi.window.close(); + var reportGrid = null; + $('#' + reportGridID + '-generate-button').prop('disabled',true); + $('#' + reportGridID + '-remove-button').prop('disabled',true); + $('#' + reportGridID + '-download-button').prop('disabled',true); + $('#' + reportGridID + '-rename-button').prop('disabled',true); + $('#available-reports-grid').find('.grid-body').find('table').find('tr').click(function() { at the beginning, there is a "reportGridID" defined, so here just use
When there are many reports that make the grid has a scrollbar, the temp row is always append to the end which make it invisible. for current design, when generate a report, need to get the grid to scroll down to the bottom to get it seen. if all actions are disabled, then just make a bar float on top of the gird in the middle. if you plan to enable some action when generating the report in the future, then just keep current design. On 5/28/2014 9:45 AM, Wen Wang wrote: that varialble.
+ $('#' + reportGridID + '-remove-button').prop('disabled',true); + $('#' + reportGridID + '-download-button').prop('disabled',true); + $('#' + reportGridID + '-rename-button').prop('disabled',true); + }); + var len = $('#available-reports-grid').find('.grid-frozen-body-view').find('tr').length + 1; + $('#available-reports-grid').find('.grid-frozen-body-view').find('table').append('<tr id="temp-row-col1"><td>' + len + '</td></tr>'); + $('#available-reports-grid').find('.grid-body-view').find('table').append('<tr id="temp-row-col2"><td id="id-generate-bar"; colspan="2"></td></tr>'); + var textboxValue = $('#report-name-textbox').val(); + if (textboxValue != "") { + if (textboxValue.length <= 15) { + $('#id-generate-bar').append('<div id="id-generate-panel"></div>'); + $('#id-generate-panel').append('<label id="id-generating"><span>' + '"' + textboxValue +'" ' + i18n['KCHDR6007M'] + '</span></label>'); + } + else { + $('#id-generate-bar').append('<div id="id-generate-panel"></div>'); + $('#id-generate-panel').append('<label id="id-generating"><span>' + '"' + textboxValue.substring(0,13) +'..." ' + i18n['KCHDR6007M'] + '</span></label>'); + } + } + else { + $('#id-generate-bar').append('<div id="id-generate-panel"></div>'); + $('#id-generate-panel').append('<label id="id-generating"><span>' + i18n['KCHDR6007M'] + '</span></label>'); + } Looks like here it is trying to make sure there is sufficient horizontal space for the report name to make it scalable for different size of real screen estate, try text-overflow: ellipsis; where browser will handle overflow issue. Then there is no need to check below, always '"' + textboxValue +'" ' + i18n['KCHDR6007M']
if (textboxValue != "")
kimchi.createReport(formData, function(result) { - kimchi.window.close(); + $('#temp-row-col1').remove(); + $('#temp-row-col2').remove();
the whole row need to be removed?
+ $('#' + reportGridID + '-generate-button').prop('disabled',false); kimchi.topic('kimchi/debugReportAdded').publish({ result: result }); why there is no error handling?

On 05/30/2014 03:44 PM, Yu Xin Huo wrote: > When there are many reports that make the grid has a scrollbar, the > temp row is always append to the end which make it invisible. > > for current design, when generate a report, need to get the grid to > scroll down to the bottom to get it seen. > > if all actions are disabled, then just make a bar float on top of the > gird in the middle. > if you plan to enable some action when generating the report in the > future, then just keep current design. > I think it's better to enable the buttons in the future. But for current design, disable the buttons seems to be a nicer solution. I will think of other ways that can enable the buttons as well as show the procedure bar properly. > On 5/28/2014 9:45 AM, Wen Wang wrote: >> 1) Removed the dialogue window when generating a debug report. >> 2) Designed an animation bar indicate user there is a report generating >> during the generating progress. >> 3) Disable the buttons' functions in debug report area when generating a new >> report in case there might be any conflict. Meanwhile user can operate >> on other parts of Kimchi. >> 4) Enable all buttonss' functions in debug report area after generating >> progress. >> --- >> ui/css/theme-default/host.css | 22 +++++++++++++++++++++ >> ui/js/src/kimchi.report_add_main.js | 38 ++++++++++++++++++++++++++++++++----- >> 2 files changed, 55 insertions(+), 5 deletions(-) >> >> diff --git a/ui/css/theme-default/host.css b/ui/css/theme-default/host.css >> index 6a1a308..c684c0a 100644 >> --- a/ui/css/theme-default/host.css >> +++ b/ui/css/theme-default/host.css >> @@ -219,6 +219,28 @@ >> width: 200px; >> } >> >> +#id-generate-bar { >> + text-align: center; >> + vertical-align: middle; >> +} >> + >> +#id-generate-panel { >> + vertical-align: middle; >> + margin: 0 auto; >> + text-align: center; >> + height: 20px; >> + width: 250px; >> + color: #fff; >> + border: 1px solid #ccc; >> + background-color: #5af; >> +} >> + >> +#id-generating { >> + font-color: #fff; >> + background: #5af url(../../images/theme-default/loading.gif) 7px >> + center no-repeat; >> + padding-left: 26px; >> +} >> /* End of Debug Report */ >> >> /* Software Updates */ >> diff --git a/ui/js/src/kimchi.report_add_main.js b/ui/js/src/kimchi.report_add_main.js >> index 8759c2b..1e5df89 100644 >> --- a/ui/js/src/kimchi.report_add_main.js >> +++ b/ui/js/src/kimchi.report_add_main.js >> @@ -1,4 +1,5 @@ >> kimchi.report_add_main = function() { >> + var reportGridID = 'available-reports-grid'; >> var addReportForm = $('#form-report-add'); >> var submitButton = $('#button-report-add'); >> var nameTextbox = $('input[name="name"]', addReportForm); >> @@ -13,12 +14,39 @@ kimchi.report_add_main = function() { >> return false; >> } >> var formData = addReportForm.serializeObject(); >> - submitButton >> - .text(i18n['KCHDR6007M']) >> - .prop('disabled', true); >> - nameTextbox.prop('disabled', true); >> + kimchi.window.close(); >> + var reportGrid = null; >> + $('#' + reportGridID + '-generate-button').prop('disabled',true); >> + $('#' + reportGridID + '-remove-button').prop('disabled',true); >> + $('#' + reportGridID + '-download-button').prop('disabled',true); >> + $('#' + reportGridID + '-rename-button').prop('disabled',true); >> + $('#available-reports-grid').find('.grid-body').find('table').find('tr').click(function() { > at the beginning, there is a "reportGridID" defined, so here just use > that varialble. ACK, I will have it fixed. >> + $('#' + reportGridID + '-remove-button').prop('disabled',true); >> + $('#' + reportGridID + '-download-button').prop('disabled',true); >> + $('#' + reportGridID + '-rename-button').prop('disabled',true); >> + }); >> + var len = $('#available-reports-grid').find('.grid-frozen-body-view').find('tr').length + 1; >> + $('#available-reports-grid').find('.grid-frozen-body-view').find('table').append('<tr id="temp-row-col1"><td>' + len + '</td></tr>'); >> + $('#available-reports-grid').find('.grid-body-view').find('table').append('<tr id="temp-row-col2"><td id="id-generate-bar"; colspan="2"></td></tr>'); >> + var textboxValue = $('#report-name-textbox').val(); >> + if (textboxValue != "") { >> + if (textboxValue.length <= 15) { >> + $('#id-generate-bar').append('<div id="id-generate-panel"></div>'); >> + $('#id-generate-panel').append('<label id="id-generating"><span>' + '"' + textboxValue +'" ' + i18n['KCHDR6007M'] + '</span></label>'); >> + } >> + else { >> + $('#id-generate-bar').append('<div id="id-generate-panel"></div>'); >> + $('#id-generate-panel').append('<label id="id-generating"><span>' + '"' + textboxValue.substring(0,13) +'..." ' + i18n['KCHDR6007M'] + '</span></label>'); >> + } >> + } >> + else { >> + $('#id-generate-bar').append('<div id="id-generate-panel"></div>'); >> + $('#id-generate-panel').append('<label id="id-generating"><span>' + i18n['KCHDR6007M'] + '</span></label>'); >> + } > Looks like here it is trying to make sure there is sufficient > horizontal space for the rRe: [Kimchi-devel] [PATCH] Issue #296 > [enhance]kimchi UI should not waiting while generating reportseport name > to make it scalable for different size of real screen estate, try > text-overflow: ellipsis; where browser will handle overflow issue. > Then there is no need to check below, always '"' + textboxValue +'" ' > + i18n['KCHDR6007M'] ACK, thanks for the tips. > if (textboxValue != "") >> kimchi.createReport(formData, function(result) { >> - kimchi.window.close(); >> + $('#temp-row-col1').remove(); >> + $('#temp-row-col2').remove(); > the whole row need to be removed? These two columns are generated for the showing bar. It will be covered by the new generated report. either way user will not be able to see them. I don't know which way is better for designing it. I can keep it if it's a better way of the whole task. >> + $('#' + reportGridID + '-generate-button').prop('disabled',false); >> kimchi.topic('kimchi/debugReportAdded').publish({ >> result: result >> }); > why there is no error handling? Sorry that I didn't change the code of showing the result. I will have it fixed. > > > > _______________________________________________ > Kimchi-devel mailing list > Kimchi-devel@ovirt.org > http://lists.ovirt.org/mailman/listinfo/kimchi-devel

What if I want to rename/remove/download another debug report when there is a new debug report being generated? All buttons are disabled when generating a debug report so it's impossible to access any debug reports. On 05/28/2014 09:45 AM, Wen Wang wrote:
1) Removed the dialogue window when generating a debug report. 2) Designed an animation bar indicate user there is a report generating during the generating progress. 3) Disable the buttons' functions in debug report area when generating a new report in case there might be any conflict. Meanwhile user can operate on other parts of Kimchi. 4) Enable all buttonss' functions in debug report area after generating progress. --- ui/css/theme-default/host.css | 22 +++++++++++++++++++++ ui/js/src/kimchi.report_add_main.js | 38 ++++++++++++++++++++++++++++++++----- 2 files changed, 55 insertions(+), 5 deletions(-)
diff --git a/ui/css/theme-default/host.css b/ui/css/theme-default/host.css index 6a1a308..c684c0a 100644 --- a/ui/css/theme-default/host.css +++ b/ui/css/theme-default/host.css @@ -219,6 +219,28 @@ width: 200px; }
+#id-generate-bar { + text-align: center; + vertical-align: middle; +} + +#id-generate-panel { + vertical-align: middle; + margin: 0 auto; + text-align: center; + height: 20px; + width: 250px; + color: #fff; + border: 1px solid #ccc; + background-color: #5af; +} + +#id-generating { + font-color: #fff; + background: #5af url(../../images/theme-default/loading.gif) 7px + center no-repeat; + padding-left: 26px; +} /* End of Debug Report */
/* Software Updates */ diff --git a/ui/js/src/kimchi.report_add_main.js b/ui/js/src/kimchi.report_add_main.js index 8759c2b..1e5df89 100644 --- a/ui/js/src/kimchi.report_add_main.js +++ b/ui/js/src/kimchi.report_add_main.js @@ -1,4 +1,5 @@ kimchi.report_add_main = function() { + var reportGridID = 'available-reports-grid'; var addReportForm = $('#form-report-add'); var submitButton = $('#button-report-add'); var nameTextbox = $('input[name="name"]', addReportForm); @@ -13,12 +14,39 @@ kimchi.report_add_main = function() { return false; } var formData = addReportForm.serializeObject(); - submitButton - .text(i18n['KCHDR6007M']) - .prop('disabled', true); - nameTextbox.prop('disabled', true); + kimchi.window.close(); + var reportGrid = null; + $('#' + reportGridID + '-generate-button').prop('disabled',true); + $('#' + reportGridID + '-remove-button').prop('disabled',true); + $('#' + reportGridID + '-download-button').prop('disabled',true); + $('#' + reportGridID + '-rename-button').prop('disabled',true); + $('#available-reports-grid').find('.grid-body').find('table').find('tr').click(function() { + $('#' + reportGridID + '-remove-button').prop('disabled',true); + $('#' + reportGridID + '-download-button').prop('disabled',true); + $('#' + reportGridID + '-rename-button').prop('disabled',true); + }); + var len = $('#available-reports-grid').find('.grid-frozen-body-view').find('tr').length + 1; + $('#available-reports-grid').find('.grid-frozen-body-view').find('table').append('<tr id="temp-row-col1"><td>' + len + '</td></tr>'); + $('#available-reports-grid').find('.grid-body-view').find('table').append('<tr id="temp-row-col2"><td id="id-generate-bar"; colspan="2"></td></tr>'); + var textboxValue = $('#report-name-textbox').val(); + if (textboxValue != "") { + if (textboxValue.length <= 15) { + $('#id-generate-bar').append('<div id="id-generate-panel"></div>'); + $('#id-generate-panel').append('<label id="id-generating"><span>' + '"' + textboxValue +'" ' + i18n['KCHDR6007M'] + '</span></label>'); + } + else { + $('#id-generate-bar').append('<div id="id-generate-panel"></div>'); + $('#id-generate-panel').append('<label id="id-generating"><span>' + '"' + textboxValue.substring(0,13) +'..." ' + i18n['KCHDR6007M'] + '</span></label>'); + } + } + else { + $('#id-generate-bar').append('<div id="id-generate-panel"></div>'); + $('#id-generate-panel').append('<label id="id-generating"><span>' + i18n['KCHDR6007M'] + '</span></label>'); + } kimchi.createReport(formData, function(result) { - kimchi.window.close(); + $('#temp-row-col1').remove(); + $('#temp-row-col2').remove(); + $('#' + reportGridID + '-generate-button').prop('disabled',false); kimchi.topic('kimchi/debugReportAdded').publish({ result: result });

Good point. For current process, I enabled all other parts of Kimchi except the Debug report area. I have some thoughts of enable the buttons when generating the debug report which don't seem to work with current design. I believe it's better to enable the buttons during the generating procedure. I will have that done in the future. Thanks Hongliang! On 05/30/2014 05:03 PM, Hongliang Wang wrote:
What if I want to rename/remove/download another debug report when there is a new debug report being generated? All buttons are disabled when generating a debug report so it's impossible to access any debug reports.
On 05/28/2014 09:45 AM, Wen Wang wrote:
1) Removed the dialogue window when generating a debug report. 2) Designed an animation bar indicate user there is a report generating during the generating progress. 3) Disable the buttons' functions in debug report area when generating a new report in case there might be any conflict. Meanwhile user can operate on other parts of Kimchi. 4) Enable all buttonss' functions in debug report area after generating progress. --- ui/css/theme-default/host.css | 22 +++++++++++++++++++++ ui/js/src/kimchi.report_add_main.js | 38 ++++++++++++++++++++++++++++++++----- 2 files changed, 55 insertions(+), 5 deletions(-)
diff --git a/ui/css/theme-default/host.css b/ui/css/theme-default/host.css index 6a1a308..c684c0a 100644 --- a/ui/css/theme-default/host.css +++ b/ui/css/theme-default/host.css @@ -219,6 +219,28 @@ width: 200px; }
+#id-generate-bar { + text-align: center; + vertical-align: middle; +} + +#id-generate-panel { + vertical-align: middle; + margin: 0 auto; + text-align: center; + height: 20px; + width: 250px; + color: #fff; + border: 1px solid #ccc; + background-color: #5af; +} + +#id-generating { + font-color: #fff; + background: #5af url(../../images/theme-default/loading.gif) 7px + center no-repeat; + padding-left: 26px; +} /* End of Debug Report */
/* Software Updates */ diff --git a/ui/js/src/kimchi.report_add_main.js b/ui/js/src/kimchi.report_add_main.js index 8759c2b..1e5df89 100644 --- a/ui/js/src/kimchi.report_add_main.js +++ b/ui/js/src/kimchi.report_add_main.js @@ -1,4 +1,5 @@ kimchi.report_add_main = function() { + var reportGridID = 'available-reports-grid'; var addReportForm = $('#form-report-add'); var submitButton = $('#button-report-add'); var nameTextbox = $('input[name="name"]', addReportForm); @@ -13,12 +14,39 @@ kimchi.report_add_main = function() { return false; } var formData = addReportForm.serializeObject(); - submitButton - .text(i18n['KCHDR6007M']) - .prop('disabled', true); - nameTextbox.prop('disabled', true); + kimchi.window.close(); + var reportGrid = null; + $('#' + reportGridID + '-generate-button').prop('disabled',true); + $('#' + reportGridID + '-remove-button').prop('disabled',true); + $('#' + reportGridID + '-download-button').prop('disabled',true); + $('#' + reportGridID + '-rename-button').prop('disabled',true); + $('#available-reports-grid').find('.grid-body').find('table').find('tr').click(function() { + $('#' + reportGridID + '-remove-button').prop('disabled',true); + $('#' + reportGridID + '-download-button').prop('disabled',true); + $('#' + reportGridID + '-rename-button').prop('disabled',true); + }); + var len = $('#available-reports-grid').find('.grid-frozen-body-view').find('tr').length + 1; + $('#available-reports-grid').find('.grid-frozen-body-view').find('table').append('<tr id="temp-row-col1"><td>' + len + '</td></tr>'); + $('#available-reports-grid').find('.grid-body-view').find('table').append('<tr id="temp-row-col2"><td id="id-generate-bar"; colspan="2"></td></tr>'); + var textboxValue = $('#report-name-textbox').val(); + if (textboxValue != "") { + if (textboxValue.length <= 15) { + $('#id-generate-bar').append('<div id="id-generate-panel"></div>'); + $('#id-generate-panel').append('<label id="id-generating"><span>' + '"' + textboxValue +'" ' + i18n['KCHDR6007M'] + '</span></label>'); + } + else { + $('#id-generate-bar').append('<div id="id-generate-panel"></div>'); + $('#id-generate-panel').append('<label id="id-generating"><span>' + '"' + textboxValue.substring(0,13) +'..." ' + i18n['KCHDR6007M'] + '</span></label>'); + } + } + else { + $('#id-generate-bar').append('<div id="id-generate-panel"></div>'); + $('#id-generate-panel').append('<label id="id-generating"><span>' + i18n['KCHDR6007M'] + '</span></label>'); + } kimchi.createReport(formData, function(result) { - kimchi.window.close(); + $('#temp-row-col1').remove(); + $('#temp-row-col2').remove(); + $('#' + reportGridID + '-generate-button').prop('disabled',false); kimchi.topic('kimchi/debugReportAdded').publish({ result: result });
participants (4)
-
Hongliang Wang
-
Wang Wen
-
Wen Wang
-
Yu Xin Huo