Commit 701c967c authored by Kelvin Jiang's avatar Kelvin Jiang Committed by Commit Bot

[Extensions] Add loading state to activity log page

Add a loading state to activity log so we clear the activity log when
we switch to a new extension. This ensures that the user does not see
any previous data when new activity log data is being loaded. It also
gives users a bit more feedback on progress loading the activity log.

Bug: 832354
Change-Id: I30d5756fc375979d0a6f183af1e2e1bf25fe1073
Reviewed-on: https://chromium-review.googlesource.com/c/1345409
Commit-Queue: Kelvin Jiang <kelvinjiang@chromium.org>
Reviewed-by: default avatarDevlin <rdevlin.cronin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#610165}
parent 3a4b1617
......@@ -226,6 +226,9 @@
<message name="IDS_MD_EXTENSIONS_LOAD_ERROR_RETRY" desc="The text on the button to retry loading an unpacked extension after a failed load.">
Retry
</message>
<message name="IDS_MD_EXTENSIONS_LOADING_ACTIVITIES" desc="The message shown to the user when the activity log for an extension is currently being fetched from the API.">
Fetching activities...
</message>
<message name="IDS_MD_EXTENSIONS_NO_ACTIVITIES" desc="The message shown to the user when an extension has no recent activities.">
No recent activities
</message>
......
......@@ -12,7 +12,7 @@
<dom-module id="extensions-activity-log">
<template>
<style include="iron-flex cr-shared-style shared-style">
.empty-activity-message {
.activity-message {
color: #6e6e6e;
font-size: 123%; /* Should be 16px when 100% is 13px. */
font-weight: 500;
......@@ -29,12 +29,18 @@
</paper-icon-button-light>
<span>$i18n{activityLogPageHeading}</span>
</div>
<div id="no-activities" class="empty-activity-message"
<div id="loading-activities" class="activity-message"
hidden$="[[!shouldShowLoadingMessage_(
pageState_)]]">
<span>$i18n{loadingActivities}</span>
</div>
<div id="no-activities" class="activity-message"
hidden$="[[!shouldShowEmptyActivityLogMessage_(
activityData_)]]">
pageState_, activityData_)]]">
<span>$i18n{noActivities}</span>
</div>
<div hidden$="[[!activityData_]]">
<div id="activity-list"
hidden$="[[!shouldShowActivities_(pageState_, activityData_)]]">
<template is="dom-repeat" items="[[activityData_.activities]]">
<activity-log-item id="[[item.activityId]]" data="[[item]]">
</activity-log-item>
......
......@@ -2,6 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
cr.exportPath('extensions');
/**
* The different states the activity log page can be in. Initial state is
* LOADING because we call the activity log API whenever a user navigates to the
* page. LOADED is the state where the API call has returned a successful
* result.
* @enum {string}
*/
const ActivityLogPageState = {
LOADING: 'loading',
LOADED: 'loaded'
};
cr.define('extensions', function() {
'use strict';
......@@ -34,6 +48,15 @@ cr.define('extensions', function() {
*/
activityData_: Object,
/**
* @private
* @type {ActivityLogPageState}
*/
pageState_: {
type: String,
value: ActivityLogPageState.LOADING,
},
/**
* A promise resolver for any external files waiting for the
* GetExtensionActivity API call to finish.
......@@ -53,10 +76,10 @@ cr.define('extensions', function() {
this.getActivityLog_();
// Add a listener here so we fetch the activity log whenever a user
// navigates to the activity log from another page.
// This is needed since this component already exists in the background
// if a user navigates away from this page so attached may not be called
// when a user navigates back.
// navigates to the activity log from another page. This is needed since
// this component already exists in the background if a user navigates
// away from this page so attached may not be called when a user navigates
// back.
this.navigationListener_ = extensions.navigation.addListener(newPage => {
if (newPage.page === Page.ACTIVITY_LOG)
this.getActivityLog_();
......@@ -74,7 +97,25 @@ cr.define('extensions', function() {
* @return {boolean}
*/
shouldShowEmptyActivityLogMessage_: function() {
return !this.activityData_ || this.activityData_.activities.length === 0;
return this.pageState_ === ActivityLogPageState.LOADED &&
(!this.activityData_ || this.activityData_.activities.length === 0);
},
/**
* @private
* @return {boolean}
*/
shouldShowLoadingMessage_: function() {
return this.pageState_ === ActivityLogPageState.LOADING;
},
/**
* @private
* @return {boolean}
*/
shouldShowActivities_: function() {
return this.pageState_ === ActivityLogPageState.LOADED &&
!!this.activityData_ && this.activityData_.activities.length > 0;
},
/** @private */
......@@ -85,7 +126,9 @@ cr.define('extensions', function() {
/** @private */
getActivityLog_: function() {
this.pageState_ = ActivityLogPageState.LOADING;
this.delegate.getExtensionActivityLog(this.extensionId).then(result => {
this.pageState_ = ActivityLogPageState.LOADED;
this.activityData_ = result;
this.onDataFetched.resolve();
});
......
......@@ -227,6 +227,7 @@ content::WebUIDataSource* CreateMdExtensionsSource(bool in_dev_mode) {
{"loadErrorFileLabel", IDS_MD_EXTENSIONS_LOAD_ERROR_FILE_LABEL},
{"loadErrorErrorLabel", IDS_MD_EXTENSIONS_LOAD_ERROR_ERROR_LABEL},
{"loadErrorRetry", IDS_MD_EXTENSIONS_LOAD_ERROR_RETRY},
{"loadingActivities", IDS_MD_EXTENSIONS_LOADING_ACTIVITIES},
{"noActivities", IDS_MD_EXTENSIONS_NO_ACTIVITIES},
{"noErrorsToShow", IDS_EXTENSIONS_ERROR_NO_ERRORS_CODE_MESSAGE},
{"runtimeHostsDialogInputError",
......
......@@ -69,6 +69,9 @@ suite('ExtensionsActivityLogTest', function() {
test('activities are present for extension', function() {
Polymer.dom.flush();
testVisible('#no-activities', false);
testVisible('#loading-activities', false);
testVisible('#activity-list', true);
expectEquals(
activityLog.shadowRoot.querySelectorAll('activity-log-item').length, 2);
});
......@@ -82,10 +85,23 @@ suite('ExtensionsActivityLogTest', function() {
Polymer.dom.flush();
testVisible('#no-activities', true);
testVisible('#loading-activities', false);
testVisible('#activity-list', false);
expectEquals(
activityLog.shadowRoot.querySelectorAll('activity-log-item').length, 0);
});
test('message shown when activities are being fetched', function() {
// Pretend the activity log is still loading.
activityLog.pageState_ = ActivityLogPageState.LOADING;
Polymer.dom.flush();
testVisible('#no-activities', false);
testVisible('#loading-activities', true);
testVisible('#activity-list', false);
});
test('clicking on back button navigates to the details page', function() {
Polymer.dom.flush();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment