update application and repository views to set <meta> description to improve search results

This commit is contained in:
Alec Merdler 2017-07-13 10:12:46 -04:00
parent 21ecc2eadd
commit a9c2ea608d
7 changed files with 65 additions and 52 deletions

View file

@ -10,7 +10,7 @@
}); });
}]); }]);
function AppViewCtrl($scope, $routeParams, $location, $timeout, ApiService, UserService, AngularPollChannel, ImageLoaderService, CookieService) { function AppViewCtrl($scope, $routeParams, $rootScope, ApiService, UtilService) {
$scope.namespace = $routeParams.namespace; $scope.namespace = $routeParams.namespace;
$scope.name = $routeParams.name; $scope.name = $routeParams.name;
@ -29,8 +29,13 @@
}; };
$scope.repositoryResource = ApiService.getRepoAsResource(params).get(function(repo) { $scope.repositoryResource = ApiService.getRepoAsResource(params).get(function(repo) {
if (repo != undefined) {
$scope.repository = repo; $scope.repository = repo;
$scope.viewScope.repository = repo; $scope.viewScope.repository = repo;
// Update the page description for SEO
$rootScope.description = UtilService.getFirstMarkdownLineAsString(repo.description);
}
}); });
}; };

View file

@ -10,7 +10,8 @@
}); });
}]); }]);
function RepoViewCtrl($scope, $routeParams, $location, $timeout, ApiService, UserService, AngularPollChannel, ImageLoaderService, CookieService) { function RepoViewCtrl($scope, $routeParams, $rootScope, $timeout, ApiService,
UserService, AngularPollChannel, ImageLoaderService, UtilService) {
$scope.namespace = $routeParams.namespace; $scope.namespace = $routeParams.namespace;
$scope.name = $routeParams.name; $scope.name = $routeParams.name;
@ -59,15 +60,14 @@
}; };
$scope.repositoryResource = ApiService.getRepoAsResource(params).get(function(repo) { $scope.repositoryResource = ApiService.getRepoAsResource(params).get(function(repo) {
if (repo != undefined) {
$scope.repository = repo; $scope.repository = repo;
$scope.viewScope.repository = repo; $scope.viewScope.repository = repo;
$scope.publicRepoExperiment = CookieService.get('quay.public-repo-exp') == 'true';
// Flag for new repo page experiment // Update the page description for SEO
$scope.newRepoExperiment = $scope.repository.is_public && $scope.user.username != $scope.repository.namespace && $scope.publicRepoExperiment; $rootScope.description = UtilService.getFirstMarkdownLineAsString(repo.description);
// Load the remainder of the data async, so we don't block the initial view from // Load the remainder of the data async, so we don't block the initial view from showing
// showing.
$timeout(function() { $timeout(function() {
$scope.setTags($routeParams.tag); $scope.setTags($routeParams.tag);
@ -75,6 +75,7 @@
buildPollChannel = AngularPollChannel.create($scope, loadRepositoryBuilds, 30000 /* 30s */); buildPollChannel = AngularPollChannel.create($scope, loadRepositoryBuilds, 30000 /* 30s */);
buildPollChannel.start(); buildPollChannel.start();
}, 10); }, 10);
}
}); });
}; };

View file

@ -16,21 +16,21 @@ provideRun.$inject = [
'MetaService', 'MetaService',
]; ];
export function provideRun($rootScope: QuayRunScope, export function provideRun($rootScope: QuayRunScope,
Restangular: any, restangular: any,
PlanService: any, planService: any,
$http: ng.IHttpService, $http: ng.IHttpService,
CookieService: any, cookieService: any,
Features: any, features: any,
$anchorScroll: ng.IAnchorScrollService, $anchorScroll: ng.IAnchorScrollService,
MetaService: any): void { metaService: any): void {
const defaultTitle: string = INJECTED_CONFIG['REGISTRY_TITLE'] || 'Quay Container Registry'; const defaultTitle: string = INJECTED_CONFIG['REGISTRY_TITLE'] || 'Quay Container Registry';
// Handle session security. // Handle session security.
Restangular.setDefaultRequestParams(['post', 'put', 'remove', 'delete'], restangular.setDefaultRequestParams(['post', 'put', 'remove', 'delete'],
{'_csrf_token': (<any>window).__token || ''}); {'_csrf_token': (<any>window).__token || ''});
// Handle session expiration. // Handle session expiration.
Restangular.setErrorInterceptor(function(response) { restangular.setErrorInterceptor(function(response) {
if (response !== undefined && response.status == 503) { if (response !== undefined && response.status == 503) {
(<any>$('#cannotContactService')).modal({}); (<any>$('#cannotContactService')).modal({});
return false; return false;
@ -59,20 +59,20 @@ export function provideRun($rootScope: QuayRunScope,
}); });
// Check if we need to redirect based on a previously chosen plan. // Check if we need to redirect based on a previously chosen plan.
const result: boolean = PlanService.handleNotedPlan(); const result: boolean = planService.handleNotedPlan();
// Check to see if we need to show a redirection page. // Check to see if we need to show a redirection page.
const redirectUrl: string = CookieService.get('quay.redirectAfterLoad'); const redirectUrl: string = cookieService.get('quay.redirectAfterLoad');
CookieService.clear('quay.redirectAfterLoad'); cookieService.clear('quay.redirectAfterLoad');
if (!result && redirectUrl && redirectUrl.indexOf((<any>window).location.href) == 0) { if (!result && redirectUrl && redirectUrl.indexOf((<any>window).location.href) == 0) {
(<any>window).location = redirectUrl; (<any>window).location = redirectUrl;
return; return;
} }
$rootScope.$watch('description', function(description: string) { $rootScope.$watch('description', (description: string) => {
if (!description) { if (!description) {
description = `Hosted private docker repositories. Includes full user management and history. description = `Hosted private Docker repositories. Includes full user management and history.
Free for public repositories.`; Free for public repositories.`;
} }
@ -82,18 +82,7 @@ export function provideRun($rootScope: QuayRunScope,
$('#descriptionTag').attr('content', description); $('#descriptionTag').attr('content', description);
}); });
// Listen for scope changes and update the title and description accordingly. $rootScope.$on('$routeChangeSuccess', (event, current, previous) => {
$rootScope.$watch(function() {
const title: string = MetaService.getTitle($rootScope.currentPage) || defaultTitle;
$rootScope.title = title;
const description: string = MetaService.getDescription($rootScope.currentPage) || '';
if ($rootScope.description != description) {
$rootScope.description = description;
}
});
$rootScope.$on('$routeChangeSuccess', function(event, current, previous) {
$rootScope.current = current.$$route; $rootScope.current = current.$$route;
$rootScope.currentPage = current; $rootScope.currentPage = current;
$rootScope.pageClass = ''; $rootScope.pageClass = '';
@ -102,7 +91,7 @@ export function provideRun($rootScope: QuayRunScope,
var pageClass: string | Function = current.$$route.pageClass || ''; var pageClass: string | Function = current.$$route.pageClass || '';
if (typeof pageClass != 'string') { if (typeof pageClass != 'string') {
pageClass = pageClass(Features); pageClass = pageClass(features);
} }
$rootScope.pageClass = pageClass; $rootScope.pageClass = pageClass;
@ -112,6 +101,16 @@ export function provideRun($rootScope: QuayRunScope,
$anchorScroll(); $anchorScroll();
}); });
// Listen for route changes and update the title and description accordingly.
$rootScope.$on('$routeChangeSuccess', async(event, current, previous) => {
$rootScope.title = metaService.getTitle(current) || defaultTitle;
const description = await metaService.getDescription(current);
if ($rootScope.description != description) {
$rootScope.description = description;
}
});
var initallyChecked: boolean = false; var initallyChecked: boolean = false;
(<any>window).__isLoading = function() { (<any>window).__isLoading = function() {
if (!initallyChecked) { if (!initallyChecked) {

View file

@ -1,8 +1,7 @@
/** /**
* Service which helps set the contents of the <meta> tags (and the <title> of a page). * Service which helps set the contents of the <meta> tags (and the <title> of a page).
*/ */
angular.module('quay').factory('MetaService', ['$interpolate', 'Config', '$rootScope', '$interval', angular.module('quay').factory('MetaService', ['$interpolate', '$timeout', function($interpolate, $timeout) {
function($interpolate, Config, $rootScope, $interval) {
var metaService = {}; var metaService = {};
var interpolate = function(page, expr) { var interpolate = function(page, expr) {
@ -28,12 +27,16 @@ angular.module('quay').factory('MetaService', ['$interpolate', 'Config', '$rootS
}; };
metaService.getDescription = function(page) { metaService.getDescription = function(page) {
return new Promise(function(resolve, reject) {
if (!page || !page.$$route) { if (!page || !page.$$route) {
return null; resolve(null);
} else {
// Timeout needed because page.scope is undefined
$timeout(function() {
resolve(interpolate(page, page.$$route.description));
}, 10);
} }
});
var route = page.$$route;
return interpolate(route && route.description);
}; };
return metaService; return metaService;

View file

@ -75,6 +75,11 @@ angular.module('quay').factory('UtilService', ['$sanitize', 'markdownConverterFa
return ''; return '';
}; };
utilService.getFirstMarkdownLineAsString = function(commentString) {
return utilService.getFirstMarkdownLineAsText(commentString, false).replace('</p>', '')
.replace('<p>', '');
};
utilService.escapeHtmlString = function(text) { utilService.escapeHtmlString = function(text) {
var textStr = (text || '').toString(); var textStr = (text || '').toString();
var adjusted = textStr.replace(/&/g, "&amp;") var adjusted = textStr.replace(/&/g, "&amp;")

View file

@ -7,7 +7,7 @@
{% block added_meta %} {% block added_meta %}
<base href="/"> <base href="/">
<meta id="descriptionTag" name="description" content="Quay is the best place to build, store, and distribute your containers. Public repositories are always free."></meta> <meta id="descriptionTag" name="description" content="Quay is the best place to build, store, and distribute your containers. Public repositories are always free." />
<meta name="google-site-verification" content="GalDznToijTsHYmLjJvE4QaB9uk_IP16aaGDz5D75T4" /> <meta name="google-site-verification" content="GalDznToijTsHYmLjJvE4QaB9uk_IP16aaGDz5D75T4" />
<meta name="google-site-verification" content="oio7ioMILUo9QDflvyFz8pWig1ac2eLq5IGyQuzFMh8" /> <meta name="google-site-verification" content="oio7ioMILUo9QDflvyFz8pWig1ac2eLq5IGyQuzFMh8" />

View file

@ -21,7 +21,7 @@ var config = {
module: { module: {
rules: [ rules: [
{ {
test: /\.ts?$/, test: /\.ts$/,
use: ["ts-loader"], use: ["ts-loader"],
exclude: /node_modules/ exclude: /node_modules/
}, },