From c5800a8c988bc083205aef7c6e29c33dc6a6eb55 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Tue, 30 Oct 2018 14:09:08 -0400 Subject: [PATCH 01/13] Vue-ify requests listing page --- atst/filters.py | 5 +++ atst/models/request.py | 4 +++ atst/models/request_status_event.py | 9 +++++ atst/routes/requests/index.py | 9 +++++ js/components/forms/requests_list.js | 50 ++++++++++++++++++++++++++++ js/index.js | 2 ++ templates/requests/index.html | 48 +++++++++++++------------- 7 files changed, 103 insertions(+), 24 deletions(-) create mode 100644 js/components/forms/requests_list.js diff --git a/atst/filters.py b/atst/filters.py index 217b9e2f..aade52c8 100644 --- a/atst/filters.py +++ b/atst/filters.py @@ -77,6 +77,10 @@ def dateFromString(value, formatter="%m/%Y"): return datetime.datetime.strptime(value, formatter) +def boolean(value): + return "true" if value else "false" + + def register_filters(app): app.jinja_env.filters["iconSvg"] = iconSvg app.jinja_env.filters["dollars"] = dollars @@ -88,3 +92,4 @@ def register_filters(app): app.jinja_env.filters["renderList"] = renderList app.jinja_env.filters["formattedDate"] = formattedDate app.jinja_env.filters["dateFromString"] = dateFromString + app.jinja_env.filters["boolean"] = boolean diff --git a/atst/models/request.py b/atst/models/request.py index 4d518274..4d03c4ec 100644 --- a/atst/models/request.py +++ b/atst/models/request.py @@ -237,6 +237,10 @@ class Request(Base, mixins.TimestampsMixin, mixins.AuditableMixin): else None ) + @property + def simple_status(self): + return self.latest_status.simple_name + def __repr__(self): return "".format( self.status_displayname, diff --git a/atst/models/request_status_event.py b/atst/models/request_status_event.py index 90ec2532..1eb14723 100644 --- a/atst/models/request_status_event.py +++ b/atst/models/request_status_event.py @@ -56,6 +56,15 @@ class RequestStatusEvent(Base, mixins.TimestampsMixin, mixins.AuditableMixin): else: return self.displayname + @property + def simple_name(self): + if self.new_status in [RequestStatus.CHANGES_REQUESTED, RequestStatus.CHANGES_REQUESTED_TO_FINVER]: + return "denied" + elif self.new_status == [RequestStatus.PENDING_FINANCIAL_VERIFICATION, RequestStatus.APPROVED]: + return "accepted" + else: + return "pending" + def __repr__(self): return "".format( self.log_name, self.request_id, self.id diff --git a/atst/routes/requests/index.py b/atst/routes/requests/index.py index 99e3ad5c..6817e65c 100644 --- a/atst/routes/requests/index.py +++ b/atst/routes/requests/index.py @@ -55,6 +55,12 @@ class RequestsIndex(object): "extended_view": False, } + def _workspace_link_for_request(self, request): + if request.is_approved: + return url_for("workspaces.workspace_projects", workspace_id=request.workspace_id) + else: + return None + def _map_request(self, request, viewing_role): time_created = pendulum.instance(request.time_created) is_new = time_created.add(days=1) > pendulum.now() @@ -67,7 +73,9 @@ class RequestsIndex(object): "workspace_id": request.workspace.id if request.workspace else None, "name": request.displayname, "is_new": is_new, + "is_approved": request.is_approved, "status": request.status_displayname, + "simple_status": request.simple_status, "app_count": app_count, "last_submission_timestamp": request.last_submission_timestamp, "last_edited_timestamp": request.latest_revision.time_updated, @@ -76,6 +84,7 @@ class RequestsIndex(object): "edit_link": url_for("requests.edit", request_id=request.id), "action_required": request.action_required_by == viewing_role, "dod_component": request.latest_revision.dod_component, + "workspace_link": self._workspace_link_for_request(request) } diff --git a/js/components/forms/requests_list.js b/js/components/forms/requests_list.js new file mode 100644 index 00000000..050588cd --- /dev/null +++ b/js/components/forms/requests_list.js @@ -0,0 +1,50 @@ +import Modal from '../../mixins/modal' + +export default { + name: 'requests-list', + + mixins: [Modal], + + components: { + Modal, + }, + + props: { + initialData: { + type: Array, + default: [], + }, + isExtended: { + type: Boolean, + default: false, + }, + }, + + data: function () { + const requests = this.initialData + return { + requests, + searchValue: '', + statusValue: '', + } + }, + + mounted: function () { + }, + + computed: { + filteredRequests: function () { + return this.applySearch(this.searchValue) + } + }, + + methods: { + applySearch: function(query) { + return this.requests.filter( + (request) => query !== '' ? + request.name.toLowerCase().includes(query.toLowerCase()) : + true + ) + } + }, + } diff --git a/js/index.js b/js/index.js index ac1f7c79..e6c4ae68 100644 --- a/js/index.js +++ b/js/index.js @@ -22,6 +22,7 @@ import SpendTable from './components/tables/spend_table' import CcpoApproval from './components/forms/ccpo_approval' import MembersList from './components/forms/members_list' import LocalDatetime from './components/local_datetime' +import RequestsList from './components/forms/requests_list' Vue.use(VTooltip) @@ -46,6 +47,7 @@ const app = new Vue({ LocalDatetime, EditEnvironmentRole, EditProjectRoles, + RequestsList, }, mounted: function() { diff --git a/templates/requests/index.html b/templates/requests/index.html index 3f5c121b..0cf9cf35 100644 --- a/templates/requests/index.html +++ b/templates/requests/index.html @@ -5,6 +5,8 @@ {% from "components/empty_state.html" import EmptyState %} {% block content %} + +
{% call Modal(name='pendingFinancialVerification', dismissable=True) %}

Request submitted!

@@ -55,7 +57,6 @@ ) }} {% else %} - {% if extended_view %}
@@ -79,7 +80,7 @@
- {% endif %} +
+ + {% endblock %} From 588584ccee062c3f80e656b02441f1dfb2aebb9f Mon Sep 17 00:00:00 2001 From: richard-dds Date: Tue, 30 Oct 2018 14:57:57 -0400 Subject: [PATCH 02/13] Use local-datetime components --- js/components/forms/requests_list.js | 2 ++ templates/requests/index.html | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/js/components/forms/requests_list.js b/js/components/forms/requests_list.js index 050588cd..5cb40e06 100644 --- a/js/components/forms/requests_list.js +++ b/js/components/forms/requests_list.js @@ -1,4 +1,5 @@ import Modal from '../../mixins/modal' +import LocalDatetime from '../../components/local_datetime' export default { name: 'requests-list', @@ -7,6 +8,7 @@ export default { components: { Modal, + LocalDatetime }, props: { diff --git a/templates/requests/index.html b/templates/requests/index.html index 0cf9cf35..e0bb9072 100644 --- a/templates/requests/index.html +++ b/templates/requests/index.html @@ -121,9 +121,9 @@ !{ r.name } Action Required - !{ r.last_submission_timestamp} + {% if extended_view %} - !{ r.last_edited_timestamp } + !{ r.full_name } {% endif %} !{ r.annual_usage } From 18c3354519b23a0c9e171f2e63851a2afd64b9ef Mon Sep 17 00:00:00 2001 From: richard-dds Date: Tue, 30 Oct 2018 15:08:16 -0400 Subject: [PATCH 03/13] Format dollar amount --- js/components/forms/requests_list.js | 4 +++- templates/requests/index.html | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/js/components/forms/requests_list.js b/js/components/forms/requests_list.js index 5cb40e06..abc40852 100644 --- a/js/components/forms/requests_list.js +++ b/js/components/forms/requests_list.js @@ -1,5 +1,6 @@ import Modal from '../../mixins/modal' import LocalDatetime from '../../components/local_datetime' +import { formatDollars } from '../../lib/dollars' export default { name: 'requests-list', @@ -47,6 +48,7 @@ export default { request.name.toLowerCase().includes(query.toLowerCase()) : true ) - } + }, + dollars: (value) => formatDollars(value, false), }, } diff --git a/templates/requests/index.html b/templates/requests/index.html index e0bb9072..8c8aa472 100644 --- a/templates/requests/index.html +++ b/templates/requests/index.html @@ -126,7 +126,7 @@ !{ r.full_name } {% endif %} - !{ r.annual_usage } + !{ dollars(r.annual_usage) } !{ r.status } From af014cae039753c7bb61c422cac2afebcd8b36fc Mon Sep 17 00:00:00 2001 From: richard-dds Date: Tue, 30 Oct 2018 15:14:12 -0400 Subject: [PATCH 04/13] Filter by status --- js/components/forms/requests_list.js | 13 ++++++++++--- templates/requests/index.html | 5 +++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/js/components/forms/requests_list.js b/js/components/forms/requests_list.js index abc40852..51f1afa7 100644 --- a/js/components/forms/requests_list.js +++ b/js/components/forms/requests_list.js @@ -37,18 +37,25 @@ export default { computed: { filteredRequests: function () { - return this.applySearch(this.searchValue) + return this.applyFilters(this.applySearch(this.requests, this.searchValue), this.statusValue) } }, methods: { - applySearch: function(query) { - return this.requests.filter( + applySearch: (requests, query) => { + return requests.filter( (request) => query !== '' ? request.name.toLowerCase().includes(query.toLowerCase()) : true ) }, + applyFilters: (requests, status) => { + return requests.filter( + (request) => status !== '' ? + request.simple_status.toLowerCase() === status : + true + ) + }, dollars: (value) => formatDollars(value, false), }, } diff --git a/templates/requests/index.html b/templates/requests/index.html index 8c8aa472..73fe6810 100644 --- a/templates/requests/index.html +++ b/templates/requests/index.html @@ -79,8 +79,8 @@ {% if extended_view %} From 5477076fe153beaf4dd2a22e375b60cb3c766341 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Wed, 31 Oct 2018 11:25:43 -0400 Subject: [PATCH 08/13] Formatting --- atst/routes/requests/index.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/atst/routes/requests/index.py b/atst/routes/requests/index.py index 209c3773..4c5f281d 100644 --- a/atst/routes/requests/index.py +++ b/atst/routes/requests/index.py @@ -20,10 +20,7 @@ class RequestsIndex(object): else: context = self._non_ccpo_view(self.user) - return { - **context, - "possible_statuses": Requests.possible_statuses(), - } + return {**context, "possible_statuses": Requests.possible_statuses()} def _ccpo_view(self, user): requests = Requests.get_many() From d540b2ae747cbd47e0eb5543fe28712027319472 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Wed, 31 Oct 2018 14:52:48 -0400 Subject: [PATCH 09/13] Sort requests --- js/components/forms/requests_list.js | 54 ++++++++++++++++++++++++++-- package.json | 1 + templates/requests/index.html | 23 ++++++------ yarn.lock | 5 +++ 4 files changed, 68 insertions(+), 15 deletions(-) diff --git a/js/components/forms/requests_list.js b/js/components/forms/requests_list.js index 006ebe92..eae5ba4f 100644 --- a/js/components/forms/requests_list.js +++ b/js/components/forms/requests_list.js @@ -1,6 +1,8 @@ import Modal from '../../mixins/modal' import LocalDatetime from '../../components/local_datetime' import { formatDollars } from '../../lib/dollars' +import { parse } from 'date-fns' +import { compose, partial, indexBy, prop, sortBy, reverse, pipe } from 'ramda' export default { name: 'requests-list', @@ -28,9 +30,30 @@ export default { }, data: function () { + const defaultSort = (sort, requests) => sortBy(prop(sort.columnName), requests) + const dateSort = (sort, requests) => { + const parseDate = compose(partial(parse), prop(sort.columnName)) + return sortBy(parseDate, requests) + } + + const columnList = [ + { displayName: 'JEDI Cloud Request Name', attr: 'name', sortFunc: defaultSort }, + { displayName: 'Date Request Submitted', attr: 'last_submission_timestamp', sortFunc: dateSort }, + { displayName: 'Date Request Last Edited', attr: 'last_edited_timestamp', extendedOnly: true, sortFunc: dateSort }, + { displayName: 'Requester', attr: 'full_name', extendedOnly: true, sortFunc: defaultSort, }, + { displayName: 'Projected Annual Usage ($)', attr: 'annual_usage', sortFunc: defaultSort }, + { displayName: 'Request Status', attr: 'status', sortFunc: defaultSort }, + { displayName: 'DOD Component', attr: 'dod_component', extendedOnly: true, sortFunc: defaultSort }, + ] + return { searchValue: '', statusValue: '', + sort: { + columnName: '', + isAscending: true + }, + columns: indexBy(prop('attr'), columnList), } }, @@ -39,25 +62,50 @@ export default { computed: { filteredRequests: function () { - return this.applyFilters(this.applySearch(this.requests, this.searchValue), this.statusValue) + return pipe( + partial(this.applySearch, [this.searchValue]), + partial(this.applyFilters, [this.statusValue]), + partial(this.applySort, [this.sort]), + )(this.requests) } }, methods: { - applySearch: (requests, query) => { + getColumns: function() { + return Object.values(this.columns) + .filter((column) => !column.extendedOnly || this.isExtended) + }, + applySearch: (query, requests) => { return requests.filter( (request) => query !== '' ? request.name.toLowerCase().includes(query.toLowerCase()) : true ) }, - applyFilters: (requests, status) => { + applyFilters: (status, requests) => { return requests.filter( (request) => status !== '' ? request.status === status : true ) }, + applySort: function(sort, requests) { + if (sort.columnName === '') { + return requests + } else { + const { sortFunc } = this.columns[sort.columnName] + const sorted = sortFunc(sort, requests) + return sort.isAscending ? + sorted : + reverse(sorted) + } + }, dollars: (value) => formatDollars(value, false), + updateSortValue: function(columnName) { + if (columnName === this.sort.columnName) { + this.sort.isAscending = !this.sort.isAscending + } + this.sort.columnName = columnName; + }, }, } diff --git a/package.json b/package.json index 2a939edf..9dd73d40 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "date-fns": "^1.29.0", "npm": "^6.0.1", "parcel": "^1.9.7", + "ramda": "^0.25.0", "svg-innerhtml": "^1.1.0", "text-mask-addons": "^3.8.0", "uswds": "^1.6.3", diff --git a/templates/requests/index.html b/templates/requests/index.html index 6f21f9f9..de9b0d1a 100644 --- a/templates/requests/index.html +++ b/templates/requests/index.html @@ -3,6 +3,7 @@ {% from "components/alert.html" import Alert %} {% from "components/modal.html" import Modal %} {% from "components/empty_state.html" import EmptyState %} +{% from "components/icon.html" import Icon %} {% block content %} @@ -101,17 +102,15 @@ - - - {% if extended_view %} - - - {% endif %} - - - {% if extended_view %} - - {% endif %} + @@ -121,7 +120,7 @@ Action Required - {% if extended_view %} + {% if extended_view %} {% endif %} diff --git a/yarn.lock b/yarn.lock index 965179de..f7a9368e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6101,6 +6101,11 @@ qw@~1.0.1: resolved "https://registry.yarnpkg.com/qw/-/qw-1.0.1.tgz#efbfdc740f9ad054304426acb183412cc8b996d4" integrity sha1-77/cdA+a0FQwRCassYNBLMi5ltQ= +ramda@^0.25.0: + version "0.25.0" + resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.25.0.tgz#8fdf68231cffa90bc2f9460390a0cb74a29b29a9" + integrity sha512-GXpfrYVPwx3K7RQ6aYT8KPS8XViSXUVJT1ONhoKPE9VAleW42YE+U+8VEyGWt41EnEQW7gwecYJriTI0pKoecQ== + randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: version "2.0.6" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80" From 63d5f3d25ce0b86659b020d13fb0db3b79210d52 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Wed, 31 Oct 2018 15:09:31 -0400 Subject: [PATCH 10/13] Formatting --- js/components/forms/requests_list.js | 45 +++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/js/components/forms/requests_list.js b/js/components/forms/requests_list.js index eae5ba4f..a4ab592b 100644 --- a/js/components/forms/requests_list.js +++ b/js/components/forms/requests_list.js @@ -37,13 +37,44 @@ export default { } const columnList = [ - { displayName: 'JEDI Cloud Request Name', attr: 'name', sortFunc: defaultSort }, - { displayName: 'Date Request Submitted', attr: 'last_submission_timestamp', sortFunc: dateSort }, - { displayName: 'Date Request Last Edited', attr: 'last_edited_timestamp', extendedOnly: true, sortFunc: dateSort }, - { displayName: 'Requester', attr: 'full_name', extendedOnly: true, sortFunc: defaultSort, }, - { displayName: 'Projected Annual Usage ($)', attr: 'annual_usage', sortFunc: defaultSort }, - { displayName: 'Request Status', attr: 'status', sortFunc: defaultSort }, - { displayName: 'DOD Component', attr: 'dod_component', extendedOnly: true, sortFunc: defaultSort }, + { + displayName: 'JEDI Cloud Request Name', + attr: 'name', + sortFunc: defaultSort, + }, + { + displayName: 'Date Request Submitted', + attr: 'last_submission_timestamp', + sortFunc: dateSort, + }, + { + displayName: 'Date Request Last Edited', + attr: 'last_edited_timestamp', + extendedOnly: true, + sortFunc: dateSort, + }, + { + displayName: 'Requester', + attr: 'full_name', + extendedOnly: true, + sortFunc: defaultSort, + }, + { + displayName: 'Projected Annual Usage ($)', + attr: 'annual_usage', + sortFunc: defaultSort, + }, + { + displayName: 'Request Status', + attr: 'status', + sortFunc: defaultSort, + }, + { + displayName: 'DOD Component', + attr: 'dod_component', + extendedOnly: true, + sortFunc: defaultSort, + }, ] return { From bb903ece9f0013025809c44ceed2347fac4daa32 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Wed, 31 Oct 2018 15:52:52 -0400 Subject: [PATCH 11/13] No sorting for non-ccpo users --- js/components/forms/requests_list.js | 4 ++++ templates/requests/index.html | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/js/components/forms/requests_list.js b/js/components/forms/requests_list.js index a4ab592b..52d46f26 100644 --- a/js/components/forms/requests_list.js +++ b/js/components/forms/requests_list.js @@ -133,9 +133,13 @@ export default { }, dollars: (value) => formatDollars(value, false), updateSortValue: function(columnName) { + if (!this.isExtended) { return } + + // toggle ascending / descending if column is clicked twice if (columnName === this.sort.columnName) { this.sort.isAscending = !this.sort.isAscending } + this.sort.columnName = columnName; }, }, diff --git a/templates/requests/index.html b/templates/requests/index.html index de9b0d1a..3fcb5489 100644 --- a/templates/requests/index.html +++ b/templates/requests/index.html @@ -102,8 +102,8 @@
JEDI Cloud Request NameDate Request SubmittedDate Request Last EditedRequesterProjected Annual Usage ($)Request StatusDOD Component + !{ column.displayName } + + {{ Icon("caret_down") }} + + + {{ Icon("caret_up") }} + +
!{ r.full_name }
-
- !{ column.displayName } + + !{ column.displayName } {{ Icon("caret_down") }} From 05b09e7961b886b303610e1571ced58f32c4455e Mon Sep 17 00:00:00 2001 From: richard-dds Date: Thu, 1 Nov 2018 10:36:16 -0400 Subject: [PATCH 12/13] Template fixes --- js/components/forms/requests_list.js | 9 +-------- templates/requests/index.html | 9 +++++---- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/js/components/forms/requests_list.js b/js/components/forms/requests_list.js index 52d46f26..c3b07518 100644 --- a/js/components/forms/requests_list.js +++ b/js/components/forms/requests_list.js @@ -1,4 +1,3 @@ -import Modal from '../../mixins/modal' import LocalDatetime from '../../components/local_datetime' import { formatDollars } from '../../lib/dollars' import { parse } from 'date-fns' @@ -7,11 +6,8 @@ import { compose, partial, indexBy, prop, sortBy, reverse, pipe } from 'ramda' export default { name: 'requests-list', - mixins: [Modal], - components: { - Modal, - LocalDatetime + LocalDatetime, }, props: { @@ -88,9 +84,6 @@ export default { } }, - mounted: function () { - }, - computed: { filteredRequests: function () { return pipe( diff --git a/templates/requests/index.html b/templates/requests/index.html index 3fcb5489..d9bd4a58 100644 --- a/templates/requests/index.html +++ b/templates/requests/index.html @@ -6,8 +6,6 @@ {% from "components/icon.html" import Icon %} {% block content %} - -
{% call Modal(name='pendingFinancialVerification', dismissable=True) %}

Request submitted!

@@ -39,6 +37,9 @@
{% endcall %} + +
+ {% if num_action_required %} {% set title -%} Action required on {{ num_action_required }} requests. @@ -82,7 +83,7 @@
-
@@ -104,7 +105,7 @@
!{ column.displayName } - + {{ Icon("caret_down") }} From 1baac6ede9fadd05c5809bbbf919d673799a8df6 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Thu, 1 Nov 2018 14:29:42 -0400 Subject: [PATCH 13/13] Disable form submission --- templates/requests/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/requests/index.html b/templates/requests/index.html index d9bd4a58..acba403f 100644 --- a/templates/requests/index.html +++ b/templates/requests/index.html @@ -79,7 +79,7 @@
{% if extended_view %} -