diff --git a/assets/src/bundles/add_forge/index.js b/assets/src/bundles/add_forge/index.js
--- a/assets/src/bundles/add_forge/index.js
+++ b/assets/src/bundles/add_forge/index.js
@@ -9,3 +9,4 @@
export * from './create-request';
export * from './moderation-dashboard';
+export * from './request-dashboard';
diff --git a/assets/src/bundles/add_forge/request-dashboard.js b/assets/src/bundles/add_forge/request-dashboard.js
new file mode 100644
--- /dev/null
+++ b/assets/src/bundles/add_forge/request-dashboard.js
@@ -0,0 +1,124 @@
+/**
+ * Copyright (C) 2022 The Software Heritage developers
+ * See the AUTHORS file at the top-level directory of this distribution
+ * License: GNU Affero General Public License version 3, or any later version
+ * See top-level LICENSE file for more information
+ */
+
+import {handleFetchError, csrfPost} from 'utils/functions';
+
+export function onRequestDashboardLoad(requestId) {
+ $(document).ready(() => {
+ populateRequestDetails(requestId);
+
+ $('#contactForgeAdmin').click((event) => {
+ contactForgeAdmin(event);
+ });
+
+ $('#updateRequestForm').submit(async function(event) {
+ event.preventDefault();
+ try {
+ const response = await csrfPost($(this).attr('action'),
+ {'Content-Type': 'application/x-www-form-urlencoded'},
+ $(this).serialize());
+ handleFetchError(response);
+ $('#userMessage').text('The request status has been updated ');
+ $('#userMessage').removeClass('badge-danger');
+ $('#userMessage').addClass('badge-success');
+ populateRequestDetails(requestId);
+ } catch (response) {
+ // const responseText = await response.json();
+ $('#userMessage').text('Sorry; Updating the request failed');
+ $('#userMessage').removeClass('badge-success');
+ $('#userMessage').addClass('badge-danger');
+ }
+ });
+ });
+}
+
+async function populateRequestDetails(requestId) {
+ try {
+ const response = await fetch(Urls.api_1_add_forge_request_get(requestId));
+ handleFetchError(response);
+ const data = await response.json();
+ $('#requestStatus').text(data.request.status);
+ $('#requestType').text(data.request.forge_type);
+ $('#requestURL').text(data.request.forge_url);
+ $('#requestEmail').text(data.request.forge_contact_email);
+ // FIXME, set the correct email address in send button
+ // $('#requestEmail').(data.request.forge_contact_email);
+ populateRequestHistory(data.history);
+ populateDecisionSelectOption(data.request.status);
+ } catch (response) {
+ $('#fetchError').removeClass('d-none');
+ $('#requestDetails').addClass('d-none');
+ }
+}
+
+function populateRequestHistory(history) {
+ history.forEach((each) => {
+ $('#swh-request-history').append(
+ `
+ On ${each.date} by ${each.actor} (${each.actor_role})
+ New status: ${each.new_status}`
+ );
+ });
+}
+
+export function populateDecisionSelectOption(currentStatus) {
+ const nextStatusesFor = {
+ 'PENDING': ['WAITING_FOR_FEEDBACK', 'REJECTED', 'SUSPENDED'],
+ 'WAITING_FOR_FEEDBACK': ['FEEDBACK_TO_HANDLE'],
+ 'FEEDBACK_TO_HANDLE': [
+ 'WAITING_FOR_FEEDBACK',
+ 'ACCEPTED',
+ 'REJECTED',
+ 'SUSPENDED'
+ ],
+ 'ACCEPTED': ['SCHEDULED'],
+ 'SCHEDULED': [
+ 'FIRST_LISTING_DONE',
+ 'FIRST_ORIGIN_LOADED'
+ ],
+ 'FIRST_LISTING_DONE': ['FIRST_ORIGIN_LOADED'],
+ 'FIRST_ORIGIN_LOADED': [],
+ 'REJECTED': [],
+ 'SUSPENDED': ['PENDING'],
+ 'DENIED': []
+ };
+
+ const statusLabel = {
+ 'PENDING': 'pending',
+ 'WAITING_FOR_FEEDBACK': 'waiting for feedback',
+ 'FEEDBACK_TO_HANDLE': 'feedback to handle',
+ 'ACCEPTED': 'accepted',
+ 'SCHEDULED': 'scheduled',
+ 'FIRST_LISTING_DONE': 'first listing done',
+ 'FIRST_ORIGIN_LOADED': 'first origin loaded',
+ 'REJECTED': 'rejected',
+ 'SUSPENDED': 'suspended',
+ 'DENIED': 'denied'
+ };
+
+ // Determine the possible next status out of the current one
+ const nextStatuses = nextStatusesFor[currentStatus];
+
+ function addStatusOption(status, index) {
+ // Push the next possible status option
+ const label = statusLabel[status];
+ $('#decisionOptions').append(
+ ``
+ );
+ }
+ // Remove all the options and add ones
+ $('#decisionOptions').children().remove();
+ nextStatuses.forEach(addStatusOption);
+}
+
+function contactForgeAdmin(event) {
+ // Open the mailclient with pre-filled text
+ const mailTo = $('#contactForgeAdmin').attr('emailTo');
+ const subject = $('#contactForgeAdmin').attr('emailSubject');
+ const emailText = $('#swh-input-forge-comment').val();
+ window.location = `mailto: ${mailTo}?subject=${subject}&body=${emailText}`;
+}
diff --git a/cypress/fixtures/add-forge-now-request.json b/cypress/fixtures/add-forge-now-request.json
new file mode 100644
--- /dev/null
+++ b/cypress/fixtures/add-forge-now-request.json
@@ -0,0 +1,23 @@
+{
+ "request":{
+ "id":1,
+ "status":"PENDING",
+ "submission_date":"2022-03-17T13:35:24.324848Z",
+ "submitter_name":"admin",
+ "submitter_email":"admin@swh-web.org",
+ "forge_type":"bitbucket",
+ "forge_url":"test.com",
+ "forge_contact_email":"test@example.com",
+ "forge_contact_name":"test user",
+ "forge_contact_comment":"test comment"
+ },"history":[
+ {
+ "id":1,
+ "text":"",
+ "actor":"admin",
+ "actor_role":"SUBMITTER",
+ "date":"2022-03-17T13:35:24.326190Z",
+ "new_status":"PENDING"
+ }
+ ]
+}
diff --git a/cypress/integration/add-forge-now-request-dashboard.spec.js b/cypress/integration/add-forge-now-request-dashboard.spec.js
new file mode 100644
--- /dev/null
+++ b/cypress/integration/add-forge-now-request-dashboard.spec.js
@@ -0,0 +1,86 @@
+/**
+ * Copyright (C) 2022 The Software Heritage developers
+ * See the AUTHORS file at the top-level directory of this distribution
+ * License: GNU Affero General Public License version 3, or any later version
+ * See top-level LICENSE file for more information
+ */
+
+const requestId = 1;
+
+describe('Test add forge now request dashboard load', function() {
+
+ beforeEach(function() {
+ const url = this.Urls.add_forge_now_request_dashboard(requestId);
+ cy.adminLogin();
+ cy.intercept(`${this.Urls.api_1_add_forge_request_get(requestId)}**`,
+ {fixture: 'add-forge-now-request'}).as('forgeAddRequest');
+ cy.visit(url);
+ });
+
+ // it('should not let non moderator access page', function() {
+ // cy.userLogin();
+ // cy.visit(this.Urls.add_forge_now_request_dashboard(requestId));
+ // });
+
+ it('should load add forge request details', function() {
+ cy.wait('@forgeAddRequest');
+ cy.get('#requestStatus')
+ .should('contain', 'PENDING');
+
+ cy.get('#requestType')
+ .should('contain', 'bitbucket');
+
+ cy.get('#requestURL')
+ .should('contain', 'test.com');
+
+ cy.get('#requestEmail')
+ .should('contain', 'test@example.com');
+ });
+
+ it('should not show any error message', function() {
+ cy.get('#fetchError')
+ .should('have.class', 'd-none');
+ cy.get('#requestDetails')
+ .should('not.have.class', 'd-none');
+ });
+
+ it('should show error message for an api error', function() {
+ const invalidRequestId = 2;
+ const url = this.Urls.add_forge_now_request_dashboard(invalidRequestId);
+ cy.visit(url);
+ cy.get('#fetchError')
+ .should('not.have.class', 'd-none');
+ cy.get('#requestDetails')
+ .should('have.class', 'd-none');
+ });
+
+ it('should load add forge request history', function() {
+ cy.get('#swh-request-history')
+ .children()
+ .should('have.length', 1);
+
+ cy.get('#swh-request-history')
+ .children()
+ .should('contain', 'New status: PENDING');
+ });
+
+ // it('should load right email template ', function() {
+ // });
+
+ // it('should open mailclient with right text', function() {
+ // // make sure the email address is right
+ // });
+
+ it('should load possible next status', function() {
+ // 3 possible status for a request in pending state
+ cy.get('#decisionOptions')
+ .children()
+ .should('have.length', 3);
+ });
+
+ it('should update the forge request', function() {
+ });
+
+ it('should update change the request details', function() {
+ });
+});
diff --git a/swh/web/admin/add_forge_now.py b/swh/web/admin/add_forge_now.py
--- a/swh/web/admin/add_forge_now.py
+++ b/swh/web/admin/add_forge_now.py
@@ -28,3 +28,17 @@
"add_forge_now/requests-moderation.html",
{"heading": "Add forge now requests moderation"},
)
+
+
+@admin_route(
+ r"add-forge/request/(?P.+)/",
+ view_name="add-forge-now-request-dashboard",
+)
+@user_passes_test(_can_access_moderation, login_url=settings.LOGIN_URL)
+def add_forge_now_request_dashboard(request, request_id):
+ """Moderation dashboard to allow listing current requests.
+
+ """
+ return render(
+ request, "add_forge_now/request-dashboard.html", {"request_id": request_id},
+ )
diff --git a/swh/web/templates/add_forge_now/request-dashboard.html b/swh/web/templates/add_forge_now/request-dashboard.html
new file mode 100644
--- /dev/null
+++ b/swh/web/templates/add_forge_now/request-dashboard.html
@@ -0,0 +1,137 @@
+{% extends "../layout.html" %}
+
+{% comment %}
+Copyright (C) 2022 The Software Heritage developers
+See the AUTHORS file at the top-level directory of this distribution
+License: GNU Affero General Public License version 3, or any later version
+See top-level LICENSE file for more information
+{% endcomment %}
+
+{% load render_bundle from webpack_loader %}
+{% load static %}
+
+{% block header %}
+{% render_bundle 'add_forge' %}
+{% endblock %}
+
+{% block title %}Add forge request – Software Heritage archive{% endblock %}
+
+{% block navbar-content %}
+Add forge now request dashboard
+
+{% endblock %}
+
+{% block content %}
+
+
+
+
Error fetching information about the request
+
+
+
+
+
+ Request Info
+
+
+ -
+
+
Status
+
+
+
+ -
+
+
Type
+
+
+
+ -
+
+
Forge URL
+
+
+
+ -
+
+
Forge contact email
+
+
+
+
+
+
+
+
+
+ Request History
+
+
+
+
+
+
+
+ Message Forge administrator (Editable)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{% endblock %}