Skip to content
This repository was archived by the owner on Sep 6, 2021. It is now read-only.

Commit 2954858

Browse files
saurabh95swmitra
authored andcommitted
Added Extension Sorting capability according to downloads and last published date (#13080)
* Added Extension Sorting capability according to downloads and last published date * Passed sort criteria to sortRegistry function in registy_utils * Added some tests * Added check for existence of downloadCount in extension-manager * Added test for checking downloadCount in ExtensionManager view * Added svg image for download icon in Extension Manager
1 parent 8d4c836 commit 2954858

14 files changed

+160
-44
lines changed

src/extensibility/ExtensionManager.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ define(function (require, exports, module) {
108108
_idsToDisable = {};
109109

110110
PreferencesManager.stateManager.definePreference(FOLDER_AUTOINSTALL, "object", undefined);
111+
PreferencesManager.definePreference("extensions.sort", "string", "publishedDate", {
112+
description: Strings.SORT_EXTENSION_METHOD
113+
});
111114

112115
/**
113116
* @private

src/extensibility/ExtensionManagerDialog.js

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ define(function (require, exports, module) {
4141
KeyEvent = require("utils/KeyEvent"),
4242
ExtensionManager = require("extensibility/ExtensionManager"),
4343
ExtensionManagerView = require("extensibility/ExtensionManagerView").ExtensionManagerView,
44-
ExtensionManagerViewModel = require("extensibility/ExtensionManagerViewModel");
44+
ExtensionManagerViewModel = require("extensibility/ExtensionManagerViewModel"),
45+
PreferencesManager = require("preferences/PreferencesManager");
4546

4647
var dialogTemplate = require("text!htmlContent/extension-manager-dialog.html");
4748

@@ -372,6 +373,11 @@ define(function (require, exports, module) {
372373
if (models[_activeTabIndex]) {
373374
$modalDlg.scrollTop(models[_activeTabIndex].scrollPos || 0);
374375
clearSearch();
376+
if (_activeTabIndex === 2) {
377+
$(".ext-sort-group").hide();
378+
} else {
379+
$(".ext-sort-group").show();
380+
}
375381
}
376382
}
377383

@@ -460,6 +466,18 @@ define(function (require, exports, module) {
460466
$modalDlg.scrollTop(0);
461467
});
462468
}).on("click", ".search-clear", clearSearch);
469+
470+
// Sort the extension list based on the current selected sorting criteria
471+
$dlg.on("change", ".sort-extensions", function (e) {
472+
var sortBy = $(this).val();
473+
PreferencesManager.set("extensions.sort", sortBy);
474+
models.forEach(function (model, index) {
475+
if (index <= 1) {
476+
model._setSortedExtensionList(ExtensionManager.extensions, index === 1);
477+
views[index].filter($(".search").val());
478+
}
479+
});
480+
});
463481

464482
// Disable the search field when there are no items in the model
465483
models.forEach(function (model, index) {
@@ -480,6 +498,11 @@ define(function (require, exports, module) {
480498
} else { // Otherwise show the first tab
481499
$dlg.find(".nav-tabs a:first").tab("show");
482500
}
501+
if ($activeTab.hasClass("installed")) {
502+
$(".ext-sort-group").hide();
503+
} else {
504+
$(".ext-sort-group").show();
505+
}
483506
});
484507

485508
// Handle the 'Install from URL' button.

src/extensibility/ExtensionManagerView.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ define(function (require, exports, module) {
3636
LanguageManager = require("language/LanguageManager"),
3737
Mustache = require("thirdparty/mustache/mustache"),
3838
PathUtils = require("thirdparty/path-utils/path-utils"),
39-
itemTemplate = require("text!htmlContent/extension-manager-view-item.html");
39+
itemTemplate = require("text!htmlContent/extension-manager-view-item.html"),
40+
PreferencesManager = require("preferences/PreferencesManager");
4041

4142

4243
/**
@@ -71,6 +72,7 @@ define(function (require, exports, module) {
7172
this._$infoMessage = $("<div class='info-message'/>")
7273
.appendTo(this.$el).html(this.model.infoMessage);
7374
this._$table = $("<table class='table'/>").appendTo(this.$el);
75+
$(".sort-extensions").val(PreferencesManager.get("extensions.sort"));
7476

7577
this.model.initialize().done(function () {
7678
self._setupEventHandlers();
@@ -248,6 +250,7 @@ define(function (require, exports, module) {
248250
var installWarningBase = context.requiresNewer ? Strings.EXTENSION_LATEST_INCOMPATIBLE_NEWER : Strings.EXTENSION_LATEST_INCOMPATIBLE_OLDER;
249251
context.installWarning = StringUtils.format(installWarningBase, entry.registryInfo.versions[entry.registryInfo.versions.length - 1].version, latestVerCompatInfo.compatibleVersion);
250252
}
253+
context.downloadCount = entry.registryInfo.totalDownloads;
251254
} else {
252255
// We should only get here when viewing the Installed tab and some extensions don't exist in the registry
253256
// (or registry is offline). These flags *should* always be ignored in that scenario, but just in case...

src/extensibility/ExtensionManagerViewModel.js

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,11 @@ define(function (require, exports, module) {
2828

2929
var _ = require("thirdparty/lodash");
3030

31-
var ExtensionManager = require("extensibility/ExtensionManager"),
32-
registry_utils = require("extensibility/registry_utils"),
33-
EventDispatcher = require("utils/EventDispatcher"),
34-
Strings = require("strings");
31+
var ExtensionManager = require("extensibility/ExtensionManager"),
32+
registry_utils = require("extensibility/registry_utils"),
33+
EventDispatcher = require("utils/EventDispatcher"),
34+
Strings = require("strings"),
35+
PreferencesManager = require("preferences/PreferencesManager");
3536

3637
/**
3738
* @private
@@ -292,6 +293,20 @@ define(function (require, exports, module) {
292293
});
293294
};
294295

296+
ExtensionManagerViewModel.prototype._setSortedExtensionList = function (extensions, isTheme) {
297+
this.filterSet = this.sortedFullSet = registry_utils.sortRegistry(extensions, "registryInfo", PreferencesManager.get("extensions.sort"))
298+
.filter(function (entry) {
299+
if (!isTheme) {
300+
return entry.registryInfo && !entry.registryInfo.metadata.theme;
301+
} else {
302+
return entry.registryInfo && entry.registryInfo.metadata.theme;
303+
}
304+
})
305+
.map(function (entry) {
306+
return entry.registryInfo.metadata.name;
307+
});
308+
};
309+
295310
/**
296311
* The model for the ExtensionManagerView that is responsible for handling registry-based extensions.
297312
* This extends ExtensionManagerViewModel.
@@ -329,13 +344,7 @@ define(function (require, exports, module) {
329344
self.extensions = ExtensionManager.extensions;
330345

331346
// Sort the registry by last published date and store the sorted list of IDs.
332-
self.sortedFullSet = registry_utils.sortRegistry(self.extensions, "registryInfo")
333-
.filter(function (entry) {
334-
return entry.registryInfo !== undefined && entry.registryInfo.metadata.theme === undefined;
335-
})
336-
.map(function (entry) {
337-
return entry.registryInfo.metadata.name;
338-
});
347+
self._setSortedExtensionList(ExtensionManager.extensions, false);
339348
self._setInitialFilter();
340349
})
341350
.fail(function () {
@@ -536,13 +545,7 @@ define(function (require, exports, module) {
536545
self.extensions = ExtensionManager.extensions;
537546

538547
// Sort the registry by last published date and store the sorted list of IDs.
539-
self.sortedFullSet = registry_utils.sortRegistry(self.extensions, "registryInfo")
540-
.filter(function (entry) {
541-
return entry.registryInfo !== undefined && entry.registryInfo.metadata.theme;
542-
})
543-
.map(function (entry) {
544-
return entry.registryInfo.metadata.name;
545-
});
548+
self._setSortedExtensionList(ExtensionManager.extensions, true);
546549
self._setInitialFilter();
547550
})
548551
.fail(function () {
@@ -570,4 +573,4 @@ define(function (require, exports, module) {
570573
exports.RegistryViewModel = RegistryViewModel;
571574
exports.ThemesViewModel = ThemesViewModel;
572575
exports.InstalledViewModel = InstalledViewModel;
573-
});
576+
});

src/extensibility/registry_utils.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ define(function (require, exports, module) {
120120
* we should look at the top level of the object.
121121
* @return {Array} Sorted array of registry entries.
122122
*/
123-
exports.sortRegistry = function (registry, subkey) {
123+
exports.sortRegistry = function (registry, subkey, sortBy) {
124124
function getPublishTime(entry) {
125125
if (entry.versions) {
126126
return new Date(entry.versions[entry.versions.length - 1].published).getTime();
@@ -136,8 +136,16 @@ define(function (require, exports, module) {
136136
sortedEntries.push(registry[key]);
137137
});
138138
sortedEntries.sort(function (entry1, entry2) {
139-
return getPublishTime((subkey && entry2[subkey]) || entry2) -
140-
getPublishTime((subkey && entry1[subkey]) || entry1);
139+
if (sortBy !== "publishedDate") {
140+
if (entry1.registryInfo && entry2.registryInfo) {
141+
return entry2.registryInfo.totalDownloads - entry1.registryInfo.totalDownloads;
142+
} else {
143+
return Number.NEGATIVE_INFINITY;
144+
}
145+
} else {
146+
return getPublishTime((subkey && entry2[subkey]) || entry2) -
147+
getPublishTime((subkey && entry1[subkey]) || entry1);
148+
}
141149
});
142150

143151
return sortedEntries;

src/htmlContent/extension-manager-dialog.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
<li><a href="#installed" class="installed" data-toggle="tab"><span class="notification"></span><img src="styles/images/extension-manager-installed.svg"/><br/>{{Strings.EXTENSIONS_INSTALLED_TITLE}}</a></li>
1010
</ul>
1111
<div>
12+
<span class="sort-extensions-title ext-sort-group">{{Strings.EXTENSIONS_SORT_BY}}</span>
13+
<select class="sort-extensions ext-sort-group">
14+
<option value="publishedDate">{{Strings.EXTENSIONS_LAST_UPDATED}}</option>
15+
<option value="downloadCount">{{Strings.EXTENSIONS_DOWNLOADS}}</option>
16+
</select>
1217
<button class="search-clear">&times;</button>
1318
<input class="search" type="text" placeholder="{{EXTENSION_SEARCH_PLACEHOLDER}}">
1419
</div>

src/htmlContent/extension-manager-view-item.html

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
{{#hasVersionInfo}}
99
<span class="muted ext-date"> &mdash; {{lastVersionDate}}</span>
1010
{{/hasVersionInfo}}
11+
{{#downloadCount}}
12+
<p title="{{downloadCount}} {{Strings.EXTENSIONS_DOWNLOADS}}"><img src="styles/images/download-icon.svg"/> {{downloadCount}}</p>
13+
{{/downloadCount}}
1114
</td>
1215
<td class="ext-desc">
1316
{{#showInstallButton}}
@@ -99,4 +102,4 @@
99102
{{/isInstalled}}
100103
</div>
101104
</td>
102-
</tr>
105+
</tr>

src/nls/root/strings.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,7 @@ define({
503503
"INSTALL_CANCELED" : "Installation canceled.",
504504
"VIEW_COMPLETE_DESCRIPTION" : "View complete description",
505505
"VIEW_TRUNCATED_DESCRIPTION" : "View truncated description",
506+
"SORT_EXTENSION_METHOD" : "Sort Extensions using downloadCount or publishedDate",
506507
// These must match the error codes in ExtensionsDomain.Errors.* :
507508
"INVALID_ZIP_FILE" : "The downloaded content is not a valid zip file.",
508509
"MISSING_PACKAGE_JSON" : "The package has no package.json file.",
@@ -580,6 +581,9 @@ define({
580581
"EXTENSIONS_AVAILABLE_TITLE" : "Available",
581582
"EXTENSIONS_THEMES_TITLE" : "Themes",
582583
"EXTENSIONS_UPDATES_TITLE" : "Updates",
584+
"EXTENSIONS_SORT_BY" : "Sort By",
585+
"EXTENSIONS_LAST_UPDATED" : "Last Updated",
586+
"EXTENSIONS_DOWNLOADS" : "Downloads",
583587

584588
"INLINE_EDITOR_NO_MATCHES" : "No matches available.",
585589
"INLINE_EDITOR_HIDDEN_MATCHES" : "All matches are collapsed. Expand the files listed at right to view matches.",

src/styles/brackets_patterns_override.less

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1183,6 +1183,17 @@ a[href^="http"] {
11831183
opacity: 0.3;
11841184
}
11851185
}
1186+
.sort-extensions-title {
1187+
float: left;
1188+
margin-right: 5px;
1189+
margin-top: 5px;
1190+
}
1191+
.sort-extensions {
1192+
float: left;
1193+
margin-right: 10px;
1194+
width: auto;
1195+
padding-right: 18px;
1196+
}
11861197
}
11871198
.modal-body {
11881199
height: 400px;

src/styles/images/download-icon.svg

Lines changed: 19 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)