@spinnaker/core 2025.0.6 → 2025.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/ApiService.d.ts +2 -2
- package/dist/api/mock/mockHttpUtils.d.ts +2 -2
- package/dist/application/listExtractor/AppListExtractor.d.ts +2 -2
- package/dist/bootstrap/paramChangedHelper.d.ts +1 -1
- package/dist/cloudProvider/providerSelection/ProviderSelectionService.d.ts +1 -1
- package/dist/cluster/filter/ClusterFilterService.d.ts +1 -1
- package/dist/cluster/task.matcher.d.ts +1 -1
- package/dist/domain/IManagedEntity.d.ts +8 -8
- package/dist/domain/IServerGroup.d.ts +1 -0
- package/dist/domain/IStageTypeConfig.d.ts +1 -1
- package/dist/entityTag/notifications/NotificationsPopover.d.ts +1 -1
- package/dist/image/image.reader.d.ts +2 -2
- package/dist/index.js +1726 -1521
- package/dist/index.js.map +1 -1
- package/dist/managed/config/Configuration.d.ts +1 -1
- package/dist/managed/config/GitIntegration.d.ts +1 -1
- package/dist/managed/constraints/registry.d.ts +2 -2
- package/dist/managed/graphql/graphql-sdk.d.ts +137 -137
- package/dist/managed/managed.states.d.ts +1 -1
- package/dist/managed/overview/artifact/ArtifactActionModal.d.ts +1 -1
- package/dist/managed/overview/artifact/VersionOperation.d.ts +3 -3
- package/dist/managed/overview/artifact/utils.d.ts +2 -2
- package/dist/managed/overview/types.d.ts +9 -9
- package/dist/managed/resourceHistory/ManagedResourceHistoryModal.d.ts +1 -1
- package/dist/managed/resources/ResourceDefinitionModal.d.ts +1 -1
- package/dist/managed/resources/resourceRegistry.d.ts +1 -1
- package/dist/managed/versionMetadata/MetadataComponents.d.ts +1 -1
- package/dist/managed/versionsHistory/types.d.ts +6 -6
- package/dist/manifest/ManifestYaml.d.ts +1 -1
- package/dist/modal/wizard/WizardPage.d.ts +1 -1
- package/dist/navigation/urlParser.d.ts +1 -1
- package/dist/pagerDuty/Pager.d.ts +1 -1
- package/dist/pipeline/config/actions/pipelineJson/EditPipelineJsonModal.d.ts +1 -1
- package/dist/pipeline/config/stages/FormikStageConfig.d.ts +2 -2
- package/dist/pipeline/config/stages/bakeManifest/helm/BakeHelmConfigForm.d.ts +1 -0
- package/dist/pipeline/config/stages/common/ExecutionDetailsSection.d.ts +1 -1
- package/dist/pipeline/config/stages/entityTags/TagEditor.d.ts +1 -1
- package/dist/pipeline/config/templates/PipelineTemplateReader.d.ts +1 -1
- package/dist/pipeline/config/triggers/artifacts/helm-image/HelmImageArtifactEditor.d.ts +3 -0
- package/dist/pipeline/config/validation/anyFieldRequired.validator.d.ts +1 -1
- package/dist/pipeline/config/validation/requiredField.validator.d.ts +1 -1
- package/dist/plugins/plugin.registry.d.ts +1 -1
- package/dist/presentation/Placement.d.ts +1 -1
- package/dist/presentation/Popover.d.ts +1 -1
- package/dist/presentation/details/Details.d.ts +7 -0
- package/dist/presentation/forms/fields/FormField.d.ts +1 -1
- package/dist/presentation/forms/fields/FormikExpressionField.d.ts +1 -1
- package/dist/presentation/forms/fields/FormikExpressionRegexField.d.ts +1 -1
- package/dist/presentation/forms/fields/FormikFormField.d.ts +1 -1
- package/dist/presentation/forms/inputs/interface.d.ts +2 -2
- package/dist/presentation/forms/validation/categories.d.ts +3 -3
- package/dist/presentation/forms/validation/validation.d.ts +3 -3
- package/dist/presentation/hooks/useLatestPromise.hook.d.ts +1 -1
- package/dist/presentation/modal/showModal.d.ts +1 -1
- package/dist/presentation/tables/Table.d.ts +1 -1
- package/dist/presentation/tables/TableCell.d.ts +1 -1
- package/dist/presentation/tables/TableRow.d.ts +1 -1
- package/dist/presentation/tables/standardGridTableLayout.d.ts +1 -1
- package/dist/projects/Projects.d.ts +2 -0
- package/dist/projects/index.d.ts +1 -0
- package/dist/projects/projects.module.d.ts +3 -2
- package/dist/reactShims/AngularJSAdapter.d.ts +3 -3
- package/dist/search/infrastructure/SearchResultPods.d.ts +1 -1
- package/dist/search/infrastructure/infrastructureSearch.service.d.ts +1 -1
- package/dist/serverGroup/details/ServerGroupDetailsWrapper.d.ts +1 -1
- package/dist/serverGroupManager/index.d.ts +1 -0
- package/dist/serverGroupManager/serverGroupManager.states.d.ts +1 -1
- package/dist/utils/Logger.d.ts +1 -1
- package/dist/utils/feature/Feature.d.ts +58 -0
- package/dist/utils/feature/FeatureContext.d.ts +24 -0
- package/dist/utils/feature/index.d.ts +3 -0
- package/dist/utils/feature/useFeature.hook.d.ts +15 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/json/traverseObject.d.ts +1 -1
- package/dist/utils/parseNum.d.ts +1 -0
- package/dist/utils/testUtils/index.d.ts +7 -0
- package/dist/utils/workerPool.d.ts +1 -1
- package/package.json +3 -3
- package/src/artifact/ArtifactIconService.ts +1 -0
- package/src/artifact/ArtifactTypes.ts +1 -0
- package/src/artifact/ExpectedArtifactSelectorViewController.ts +1 -1
- package/src/config/VersionChecker.tsx +1 -1
- package/src/domain/IServerGroup.ts +1 -0
- package/src/help/help.contents.ts +1 -1
- package/src/navigation/UrlBuilder.ts +15 -0
- package/src/notification/NotificationsList.tsx +12 -8
- package/src/pipeline/config/stages/bakeManifest/helm/BakeHelmConfigForm.tsx +8 -2
- package/src/pipeline/config/triggers/artifacts/helm-image/HelmImageArtifactEditor.tsx +169 -0
- package/src/pipeline/config/triggers/artifacts/index.ts +3 -0
- package/src/pipeline/config/validation/PipelineConfigValidator.ts +2 -2
- package/src/pipeline/executions/executionGroup/ExecutionGroups.tsx +37 -2
- package/src/pipeline/filter/executionFilter.service.ts +50 -5
- package/src/presentation/details/Details.tsx +18 -1
- package/src/presentation/forms/FormikForm.tsx +1 -1
- package/src/projects/ProjectHeader.tsx +12 -9
- package/src/projects/Projects.spec.tsx +141 -0
- package/src/projects/Projects.tsx +148 -0
- package/src/projects/index.ts +1 -0
- package/src/projects/{projects.module.js → projects.module.ts} +0 -2
- package/src/projects/projects.states.ts +4 -6
- package/src/serverGroup/details/ServerGroupDetails.tsx +1 -1
- package/src/serverGroupManager/ServerGroupManager.tsx +2 -0
- package/src/serverGroupManager/ServerGroupManagerTag.tsx +1 -1
- package/src/serverGroupManager/index.ts +1 -0
- package/src/serverGroupManager/serverGroupManager.states.ts +3 -3
- package/src/utils/feature/Feature.tsx +98 -0
- package/src/utils/feature/FeatureContext.tsx +49 -0
- package/src/utils/feature/index.ts +3 -0
- package/src/utils/feature/useFeature.hook.tsx +25 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/parseNum.ts +2 -0
- package/src/utils/testUtils/index.tsx +30 -0
- package/dist/projects/projects.controller.d.ts +0 -2
- package/src/projects/projects.controller.js +0 -112
- package/src/projects/projects.controller.spec.js +0 -86
- package/src/projects/projects.html +0 -87
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { pushStateLocationPlugin, UIRouter } from '@uirouter/react';
|
|
2
|
+
import { mount } from 'enzyme';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { act } from 'react-dom/test-utils';
|
|
5
|
+
|
|
6
|
+
// ----------------------------------------------------------------------------------
|
|
7
|
+
// Test Utilities
|
|
8
|
+
// ----------------------------------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Resolve pending tasks scheduled by the component.
|
|
12
|
+
*/
|
|
13
|
+
const flush = () => new Promise((r) => setTimeout(r, 0));
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Create a minimal UIRouter environment so components can render RouteLinks, etc.
|
|
17
|
+
*/
|
|
18
|
+
export const wrapWithRouter = (node: React.ReactElement) => (
|
|
19
|
+
<UIRouter plugins={[pushStateLocationPlugin]}>{node}</UIRouter>
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
/** Helper to DRY mounting + async flush + update. */
|
|
23
|
+
export async function mountAndFlush(element: React.ReactElement) {
|
|
24
|
+
const wrapper = mount(wrapWithRouter(element));
|
|
25
|
+
await act(async () => {
|
|
26
|
+
await flush();
|
|
27
|
+
});
|
|
28
|
+
wrapper.update();
|
|
29
|
+
return wrapper;
|
|
30
|
+
}
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import UIROUTER_ANGULARJS from '@uirouter/angularjs';
|
|
2
|
-
import { module } from 'angular';
|
|
3
|
-
import { react2angular } from 'react2angular';
|
|
4
|
-
|
|
5
|
-
import { ViewStateCache } from '../cache';
|
|
6
|
-
import { ConfigureProjectModal } from './configure';
|
|
7
|
-
import { InsightMenu as ProjectInsightMenu } from '../insight/InsightMenu';
|
|
8
|
-
import { INSIGHT_MENU_DIRECTIVE } from '../insight/insightmenu.directive';
|
|
9
|
-
import { withErrorBoundary } from '../presentation/SpinErrorBoundary';
|
|
10
|
-
import { ANY_FIELD_FILTER } from '../presentation/anyFieldFilter/anyField.filter';
|
|
11
|
-
import { CORE_PRESENTATION_SORTTOGGLE_SORTTOGGLE_DIRECTIVE } from '../presentation/sortToggle/sorttoggle.directive';
|
|
12
|
-
import { ProjectReader } from './service/ProjectReader';
|
|
13
|
-
|
|
14
|
-
('use strict');
|
|
15
|
-
|
|
16
|
-
export const CORE_PROJECTS_PROJECTS_CONTROLLER = 'spinnaker.projects.controller';
|
|
17
|
-
export const name = CORE_PROJECTS_PROJECTS_CONTROLLER; // for backwards compatibility
|
|
18
|
-
module(CORE_PROJECTS_PROJECTS_CONTROLLER, [
|
|
19
|
-
UIROUTER_ANGULARJS,
|
|
20
|
-
ANY_FIELD_FILTER,
|
|
21
|
-
CORE_PRESENTATION_SORTTOGGLE_SORTTOGGLE_DIRECTIVE,
|
|
22
|
-
INSIGHT_MENU_DIRECTIVE,
|
|
23
|
-
])
|
|
24
|
-
.component(
|
|
25
|
-
'projectInsightMenu',
|
|
26
|
-
react2angular(withErrorBoundary(ProjectInsightMenu, 'projectInsightMenu'), [
|
|
27
|
-
'createApp',
|
|
28
|
-
'createProject',
|
|
29
|
-
'refreshCaches',
|
|
30
|
-
]),
|
|
31
|
-
)
|
|
32
|
-
.controller('ProjectsCtrl', [
|
|
33
|
-
'$scope',
|
|
34
|
-
'$uibModal',
|
|
35
|
-
'$log',
|
|
36
|
-
'$filter',
|
|
37
|
-
function ($scope, $uibModal, $log, $filter) {
|
|
38
|
-
const projectsViewStateCache =
|
|
39
|
-
ViewStateCache.get('projects') || ViewStateCache.createCache('projects', { version: 1 });
|
|
40
|
-
|
|
41
|
-
function cacheViewState() {
|
|
42
|
-
projectsViewStateCache.put('#global', $scope.viewState);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function initializeViewState() {
|
|
46
|
-
$scope.viewState = projectsViewStateCache.get('#global') || {
|
|
47
|
-
sortModel: { key: 'name' },
|
|
48
|
-
projectFilter: '',
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
$scope.projectsLoaded = false;
|
|
53
|
-
|
|
54
|
-
$scope.projectFilter = '';
|
|
55
|
-
|
|
56
|
-
$scope.menuActions = [
|
|
57
|
-
{
|
|
58
|
-
displayName: 'Create Project',
|
|
59
|
-
action: function () {
|
|
60
|
-
ConfigureProjectModal.show().catch(() => {});
|
|
61
|
-
},
|
|
62
|
-
},
|
|
63
|
-
];
|
|
64
|
-
|
|
65
|
-
this.filterProjects = function filterProjects() {
|
|
66
|
-
const filtered = $filter('anyFieldFilter')($scope.projects, {
|
|
67
|
-
name: $scope.viewState.projectFilter,
|
|
68
|
-
email: $scope.viewState.projectFilter,
|
|
69
|
-
});
|
|
70
|
-
const sorted = $filter('orderBy')(filtered, $scope.viewState.sortModel.key);
|
|
71
|
-
$scope.filteredProjects = sorted;
|
|
72
|
-
this.resetPaginator();
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
this.resultPage = function resultPage() {
|
|
76
|
-
const pagination = $scope.pagination;
|
|
77
|
-
const allFiltered = $scope.filteredProjects;
|
|
78
|
-
const start = (pagination.currentPage - 1) * pagination.itemsPerPage;
|
|
79
|
-
const end = pagination.currentPage * pagination.itemsPerPage;
|
|
80
|
-
if (!allFiltered || !allFiltered.length) {
|
|
81
|
-
return [];
|
|
82
|
-
}
|
|
83
|
-
if (allFiltered.length < pagination.itemsPerPage) {
|
|
84
|
-
return allFiltered;
|
|
85
|
-
}
|
|
86
|
-
if (allFiltered.length < end) {
|
|
87
|
-
return allFiltered.slice(start);
|
|
88
|
-
}
|
|
89
|
-
return allFiltered.slice(start, end);
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
this.resetPaginator = function resetPaginator() {
|
|
93
|
-
$scope.pagination = {
|
|
94
|
-
currentPage: 1,
|
|
95
|
-
itemsPerPage: 12,
|
|
96
|
-
maxSize: 12,
|
|
97
|
-
};
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
const ctrl = this;
|
|
101
|
-
|
|
102
|
-
ProjectReader.listProjects().then(function (projects) {
|
|
103
|
-
$scope.projects = projects;
|
|
104
|
-
ctrl.filterProjects();
|
|
105
|
-
$scope.projectsLoaded = true;
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
$scope.$watch('viewState', cacheViewState, true);
|
|
109
|
-
|
|
110
|
-
initializeViewState();
|
|
111
|
-
},
|
|
112
|
-
]);
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
import { ProjectReader } from './service/ProjectReader';
|
|
4
|
-
|
|
5
|
-
describe('Controller: Projects', function () {
|
|
6
|
-
beforeEach(window.module(require('./projects.controller').name, require('angular-ui-bootstrap')));
|
|
7
|
-
|
|
8
|
-
describe('filtering', function () {
|
|
9
|
-
var deck = { name: 'deck', email: 'a@netflix.com', createTs: new Date(2) },
|
|
10
|
-
oort = { name: 'oort', email: 'b@netflix.com', createTs: new Date(3) },
|
|
11
|
-
mort = { name: 'mort', email: 'c@netflix.com', createTs: new Date(1) },
|
|
12
|
-
projectList = [deck, oort, mort];
|
|
13
|
-
|
|
14
|
-
// Initialize the controller and a mock scope
|
|
15
|
-
beforeEach(
|
|
16
|
-
window.inject(function ($controller, $rootScope, $window, $q, $uibModal, $log, $filter, $state, $timeout) {
|
|
17
|
-
this.$scope = $rootScope.$new();
|
|
18
|
-
this.$q = $q;
|
|
19
|
-
|
|
20
|
-
spyOn(ProjectReader, 'listProjects').and.callFake(function () {
|
|
21
|
-
return $q.when(projectList);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
this.ctrl = $controller('ProjectsCtrl', {
|
|
25
|
-
$scope: this.$scope,
|
|
26
|
-
$uibModal: $uibModal,
|
|
27
|
-
$log: $log,
|
|
28
|
-
$filter: $filter,
|
|
29
|
-
$state: $state,
|
|
30
|
-
$timeout: $timeout,
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
this.$scope.viewState.projectFilter = '';
|
|
34
|
-
this.$scope.viewState.sortModel.key = 'name';
|
|
35
|
-
}),
|
|
36
|
-
);
|
|
37
|
-
|
|
38
|
-
it('sets projectsLoaded flag when projects retrieved and added to scope', function () {
|
|
39
|
-
var $scope = this.$scope;
|
|
40
|
-
|
|
41
|
-
expect($scope.projectsLoaded).toBe(false);
|
|
42
|
-
expect($scope.projects).toBeUndefined();
|
|
43
|
-
|
|
44
|
-
$scope.$digest();
|
|
45
|
-
|
|
46
|
-
expect($scope.projectsLoaded).toBe(true);
|
|
47
|
-
expect($scope.projects).toBe(projectList);
|
|
48
|
-
expect($scope.filteredProjects).toEqual([deck, mort, oort]);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('filters projects by name or email', function () {
|
|
52
|
-
var $scope = this.$scope,
|
|
53
|
-
ctrl = this.ctrl;
|
|
54
|
-
|
|
55
|
-
$scope.viewState.projectFilter = 'a@netflix.com';
|
|
56
|
-
$scope.$digest();
|
|
57
|
-
expect($scope.projects).toBe(projectList);
|
|
58
|
-
expect($scope.filteredProjects).toEqual([deck]);
|
|
59
|
-
|
|
60
|
-
$scope.viewState.projectFilter = 'ort';
|
|
61
|
-
ctrl.filterProjects();
|
|
62
|
-
expect($scope.filteredProjects).toEqual([mort, oort]);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('sorts and filters projects', function () {
|
|
66
|
-
var $scope = this.$scope,
|
|
67
|
-
ctrl = this.ctrl;
|
|
68
|
-
|
|
69
|
-
$scope.viewState.sortModel.key = '-name';
|
|
70
|
-
$scope.$digest();
|
|
71
|
-
expect($scope.filteredProjects).toEqual([oort, mort, deck]);
|
|
72
|
-
|
|
73
|
-
$scope.viewState.sortModel.key = '-createTs';
|
|
74
|
-
ctrl.filterProjects();
|
|
75
|
-
expect($scope.filteredProjects).toEqual([oort, deck, mort]);
|
|
76
|
-
|
|
77
|
-
$scope.viewState.sortModel.key = 'createTs';
|
|
78
|
-
ctrl.filterProjects();
|
|
79
|
-
expect($scope.filteredProjects).toEqual([mort, deck, oort]);
|
|
80
|
-
|
|
81
|
-
$scope.viewState.projectFilter = 'ort';
|
|
82
|
-
ctrl.filterProjects();
|
|
83
|
-
expect($scope.filteredProjects).toEqual([mort, oort]);
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
});
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
<div class="infrastructure">
|
|
2
|
-
<div class="infrastructure-section search-header">
|
|
3
|
-
<div class="container">
|
|
4
|
-
<h2 class="header-section">
|
|
5
|
-
<span class="search-label">Projects</span>
|
|
6
|
-
<input
|
|
7
|
-
type="search"
|
|
8
|
-
placeholder="Search projects"
|
|
9
|
-
class="form-control input-md"
|
|
10
|
-
focus
|
|
11
|
-
ng-model="viewState.projectFilter"
|
|
12
|
-
ng-change="ctrl.filterProjects()"
|
|
13
|
-
/>
|
|
14
|
-
</h2>
|
|
15
|
-
<div class="header-actions">
|
|
16
|
-
<project-insight-menu create-app="false" create-project="true" refresh-caches="false" />
|
|
17
|
-
</div>
|
|
18
|
-
</div>
|
|
19
|
-
</div>
|
|
20
|
-
<div class="container">
|
|
21
|
-
<div ng-if="!projectsLoaded" class="horizontal center middle" style="margin-bottom: 250px; height: 100px">
|
|
22
|
-
<loading-spinner size="'small'"></loading-spinner>
|
|
23
|
-
</div>
|
|
24
|
-
<table ng-if="projectsLoaded" class="table table-hover">
|
|
25
|
-
<thead>
|
|
26
|
-
<tr>
|
|
27
|
-
<th
|
|
28
|
-
width="20%"
|
|
29
|
-
sort-toggle
|
|
30
|
-
key="name"
|
|
31
|
-
label="Name"
|
|
32
|
-
sort-model="viewState.sortModel"
|
|
33
|
-
on-change="ctrl.filterProjects()"
|
|
34
|
-
></th>
|
|
35
|
-
<th
|
|
36
|
-
width="20%"
|
|
37
|
-
sort-toggle
|
|
38
|
-
key="createTs"
|
|
39
|
-
label="Created"
|
|
40
|
-
sort-model="viewState.sortModel"
|
|
41
|
-
on-change="ctrl.filterProjects()"
|
|
42
|
-
></th>
|
|
43
|
-
<th
|
|
44
|
-
width="20%"
|
|
45
|
-
sort-toggle
|
|
46
|
-
key="updateTs"
|
|
47
|
-
label="Updated"
|
|
48
|
-
sort-model="viewState.sortModel"
|
|
49
|
-
on-change="ctrl.filterProjects()"
|
|
50
|
-
></th>
|
|
51
|
-
<th
|
|
52
|
-
width="25%"
|
|
53
|
-
sort-toggle
|
|
54
|
-
key="email"
|
|
55
|
-
label="Owner"
|
|
56
|
-
sort-model="viewState.sortModel"
|
|
57
|
-
on-change="ctrl.filterProjects()"
|
|
58
|
-
></th>
|
|
59
|
-
</tr>
|
|
60
|
-
</thead>
|
|
61
|
-
<tbody>
|
|
62
|
-
<tr
|
|
63
|
-
class="clickable"
|
|
64
|
-
ng-repeat="project in ctrl.resultPage()"
|
|
65
|
-
ui-sref="home.project.dashboard({project: project.name.toLowerCase()})"
|
|
66
|
-
>
|
|
67
|
-
<td>
|
|
68
|
-
<a href ui-sref="home.project.dashboard({project: project.name.toLowerCase()})">
|
|
69
|
-
{{ project.name.toLowerCase() }}
|
|
70
|
-
</a>
|
|
71
|
-
</td>
|
|
72
|
-
<td>{{ project.createTs | timestamp }}</td>
|
|
73
|
-
<td>{{ project.updateTs | timestamp }}</td>
|
|
74
|
-
<td>{{ project.email }}</td>
|
|
75
|
-
</tr>
|
|
76
|
-
</tbody>
|
|
77
|
-
</table>
|
|
78
|
-
<ul
|
|
79
|
-
uib-pagination
|
|
80
|
-
ng-if="projectsLoaded"
|
|
81
|
-
items-per-page="pagination.itemsPerPage"
|
|
82
|
-
total-items="filteredProjects.length"
|
|
83
|
-
max-size="pagination.maxSize"
|
|
84
|
-
ng-model="pagination.currentPage"
|
|
85
|
-
></ul>
|
|
86
|
-
</div>
|
|
87
|
-
</div>
|