diff --git a/internal/models/deskRound.go b/internal/models/deskRound.go
index 231b3b06adf0746f064c4154db4379af52c607a3..b939019069b7dcda66dd47e662fc5c9f04e9356d 100644
--- a/internal/models/deskRound.go
+++ b/internal/models/deskRound.go
@@ -57,6 +57,11 @@ func (d *DataHandler) putDeskRound(w http.ResponseWriter, r *http.Request, id in
 		return
 	}
 
+	if !o.Completed {
+		http.Error(w, "Le bureau doit être complété avant de le valider", http.StatusInternalServerError)
+		return
+	}
+
 	var deskRound DeskRound
 	err := json.NewDecoder(r.Body).Decode(&deskRound)
 	if err != nil {
diff --git a/internal/rootmux/admin_test.go b/internal/rootmux/admin_test.go
index 4e4cf2cec715e6d34a9ee60098b8608d1e66851e..b80792167f94c7f0e8ec61a9e3abc04e5752f7e4 100644
--- a/internal/rootmux/admin_test.go
+++ b/internal/rootmux/admin_test.go
@@ -84,11 +84,12 @@ func AdminTests(t *testing.T) {
 		do("GET", "/api/DeskRound/1", xsrfHeader, ``, 200, `{"ID":1,"RoundID":1,"DeskID":1,"Capturers":[],"Completed":false,"DateCompletion":"0001-01-01T00:00:00Z","Validated":false,"Votes":[]}`)
 		// Get DeskRounds
 		do("GET", "/api/DeskRound/", xsrfHeader, ``, 200, `[{"ID":1,"RoundID":1,"DeskID":1,"Capturers":[],"Completed":false,"DateCompletion":"0001-01-01T00:00:00Z","Validated":false,"Votes":[]}]`)
-		// Update a DeskRound
-		do("PUT", "/api/DeskRound/1", xsrfHeader, `{"ID":1,"Validated":true}`, 200, `{"ID":1,"RoundID":1,"DeskID":1,"Capturers":[],"Completed":false,"DateCompletion":"0001-01-01T00:00:00Z","Validated":true,"Votes":[]}`)
 		// Delete a DeskRound should fail with 400
 		do("DELETE", "/api/DeskRound/1", xsrfHeader, ``, 400, `method not allowed`)
 
+		// Update a DeskRound should be done after desk completion by capturing votes
+		// do("PUT", "/api/DeskRound/1", xsrfHeader, `{"ID":1,"Validated":true}`, 200, `{"ID":1,"RoundID":1,"DeskID":1,"Capturers":[],"Completed":false,"DateCompletion":"0001-01-01T00:00:00Z","Validated":true,"Votes":[]}`)
+
 		// Delete a Round
 		do("DELETE", "/api/Round/1", xsrfHeader, ``, 200, ``)
 		// Delete a desk
diff --git a/internal/rootmux/rootmux_test.go b/internal/rootmux/rootmux_test.go
index 1a5d922fe6f510bfb5b57e2c9612736f7b892c0f..4295acfdc663451b32807634239330eabdcd70ab 100644
--- a/internal/rootmux/rootmux_test.go
+++ b/internal/rootmux/rootmux_test.go
@@ -98,6 +98,9 @@ func appTests(t *testing.T) {
 		do("GET", "/api/Round/1", xsrfHeader, ``, 200, `{"ID":1,"ElectionID":1,"Parameter":{"ID":0,"CountBlankAndNull":false,"ShowOnlyCompleted":false,"ShowMap":false},"Date":"2020-06-28","Round":1,"DeskRounds":[{"ID":1,"RoundID":1,"DeskID":1,"Capturers":null,"Completed":false,"DateCompletion":"0001-01-01T00:00:00Z","Validated":false,"Votes":null}],"CandidateLists":[]}`)
 		do("GET", "/api/Desk/1", xsrfHeader, ``, 200, `{"ID":1,"SectionID":1,"Name":"Desk 1","WitnessDesk":true,"Subscribed":9587,"DeskRounds":[{"ID":1,"RoundID":1,"DeskID":1,"Capturers":null,"Completed":false,"DateCompletion":"0001-01-01T00:00:00Z","Validated":false,"Votes":null}]}`)
 
+		// Verify that a DeskRound can't be validated witout being completed
+		do("PUT", "/api/DeskRound/1", xsrfHeader, `{"ID":1,"Validated":true}`, 500, `Le bureau doit être complété avant de le valider`)
+
 		// Verify that on Desk deletion deskRounds are deleted
 		do("GET", "/api/Desk/1", xsrfHeader, ``, 200, `{"ID":1,"SectionID":1,"Name":"Desk 1","WitnessDesk":true,"Subscribed":9587,"DeskRounds":[{"ID":1,"RoundID":1,"DeskID":1,"Capturers":null,"Completed":false,"DateCompletion":"0001-01-01T00:00:00Z","Validated":false,"Votes":null}]}`)
 		do("DELETE", "/api/Desk/1", xsrfHeader, ``, 200, ``)
diff --git a/web/components/management/management.js b/web/components/management/management.js
index 6a6fadeaf0d4405beadfe2af03c066e373ea5254..d14167fd18fa06a685fb6e397bb67d5ecd61a319 100644
--- a/web/components/management/management.js
+++ b/web/components/management/management.js
@@ -39,7 +39,7 @@ class Management {
           </li>
         </ul>
       </div>
-      <section class="section" id="management-section" style="margin-bottom: 230px;"></section>
+      <section id="management-section" style="margin-bottom: 230px;"></section>
     `;
     current_user = await Auth.GetUser();
     this.handleDom();
diff --git a/web/components/management/round-desks.js b/web/components/management/round-desks.js
index ea924e85a718cef4af6b6b98df802158b7c1f225..28ce765bd5beaaabb9011eb5c691816a6909682b 100644
--- a/web/components/management/round-desks.js
+++ b/web/components/management/round-desks.js
@@ -1,5 +1,7 @@
 // Imports
 import * as Auth from "/services/auth/auth.js";
+import * as Getters from "/services/common/getters.js";
+import * as Messages from "/services/messages/messages.js";
 
 // DOM elements
 
@@ -14,7 +16,6 @@ export async function mount(where, parent) {
 
 class RoundDesk {
   constructor(parent) {
-    this.method = null;
     this.parent = parent;
   }
 
@@ -26,12 +27,185 @@ class RoundDesk {
           Bureaux de votes
         </p>
       </header>
-      <div class="card-content">
-        <div id="round-desks-list" class="content">
-          Liste des bureaux de votes
+      <div class="columns card-content">
+        <div class="column">
+          <div id="desk-rounds"></div>
+        </div>
+        <div class="column">
+          <div id="desk-round-details"></div>
+        </div>
+        <div class="column">
+          <div id="active-capturer" class="card"></div>
+        </div>
+        <div class="column">
+          <div id="available-capturer" class="card"></div>
         </div>
       </div>
     `;
     current_user = await Auth.GetUser();
   }
+
+  deskRoundTemplate(deskRound) {
+    return /* HTML */ `<div class="card card-list">
+      <div id="deskrounds-deskround-${deskRound.ID}" class="card-content">
+        <div class="content">
+          <nav class="level">
+            <div
+              id="deskrounds-deskround-desc-${deskRound.ID}"
+              class="level-left"
+            ></div>
+            <div class="level-right"></div>
+          </nav>
+        </div>
+      </div>
+    </div>`;
+  }
+
+  deskRoundDetailsTemplate() {
+    return /* HTML */ `<div>
+      <section class="modal-card-body">
+        <div class="field">
+          <div class="control">
+            <label class="checkbox" disabled>
+              <input
+                class="input"
+                type="checkbox"
+                id="deskround-completed"
+                ${this.deskRound.Completed ? 'checked="true"' : ""}
+                disabled
+              />
+              Complété
+              ${this.deskRound.Completed
+                ? "(" +
+                  new Date(this.deskRound.DateCompletion).toLocaleDateString() +
+                  ")"
+                : ""}
+            </label>
+          </div>
+        </div>
+        <div class="field">
+          <div class="control">
+            <label class="checkbox" ${!this.deskRound.Completed ? 'disabled="true"' : ""}>
+              <input
+                class="input"
+                type="checkbox"
+                id="deskround-validated"
+                ${this.deskRound.Validated ? 'checked="true"' : ""}
+                ${!this.deskRound.Completed ? 'disabled="true"' : ""}
+              />
+              Validé
+            </label>
+          </div>
+        </div>
+      </section>
+      <footer class="modal-card-foot">
+        <button id="deskround-save" class="button is-success">
+          Sauvegarder
+        </button>
+        <button id="deskround-cancel" class="button">
+          Annuler
+        </button>
+      </footer>
+    </div>`;
+  }
+
+  async displayDesks() {
+    let deskRounds = await this.updateDeskRounds();
+    const markup = deskRounds
+      .map((deskRound) => this.deskRoundTemplate(deskRound))
+      .join("");
+    document.getElementById("desk-rounds").innerHTML = markup;
+
+    let deskRoundHandler = this;
+    deskRounds.map(async (deskRound) => {
+      let desk = await Getters.getDesk(current_user, deskRound.DeskID);
+      document.getElementById(
+        `deskrounds-deskround-desc-${deskRound.ID}`
+      ).innerHTML = desk.Name;
+      document
+        .getElementById(`deskrounds-deskround-${deskRound.ID}`)
+        .addEventListener("click", function () {
+          deskRoundHandler.activateDeskRound(deskRound);
+          deskRoundHandler.deskRound = deskRound;
+          deskRoundHandler.displayDeskRoundsDetails();
+          // TODO open capturers affected
+        });
+    });
+  }
+
+  async displayDeskRoundsDetails() {
+    document.getElementById(
+      "desk-round-details"
+    ).innerHTML = this.deskRoundDetailsTemplate();
+    let deskRoundHandler = this;
+    document
+      .getElementById(`deskround-save`)
+      .addEventListener("click", async function () {
+        await deskRoundHandler.saveDeskRound();
+      });
+  }
+
+  async activateDeskRound(deskRoundToActivate) {
+    let deskRounds = await this.updateDeskRounds();
+    deskRounds.forEach((deskRound) => {
+      document
+        .getElementById(`deskrounds-deskround-${deskRound.ID}`)
+        .classList.remove("active-card");
+    });
+    document
+      .getElementById(`deskrounds-deskround-${deskRoundToActivate.ID}`)
+      .classList.add("active-card");
+  }
+
+  async updateDeskRounds() {
+    let deskRoundHandler = this;
+    try {
+      const response = await fetch("/api/DeskRound/", {
+        method: "GET",
+        headers: new Headers({
+          "XSRF-Token": current_user.xsrftoken,
+        }),
+      });
+      if (response.status !== 200) {
+        throw new Error(
+          `DeskRounds could not be fetched (status ${response.status})`
+        );
+      }
+      let deskRounds = await response.json();
+      return deskRounds.filter(function (deskRound) {
+        return deskRound.RoundID == deskRoundHandler.round.ID;
+      });
+    } catch (e) {
+      Messages.Show("is-warning", e.message);
+      console.error(e);
+    }
+  }
+
+  async saveDeskRound() {
+    let round;
+    try {
+      const response = await fetch("/api/DeskRound/" + this.deskRound.ID, {
+        method: "PUT",
+        headers: new Headers({
+          "XSRF-Token": current_user.xsrftoken,
+        }),
+        body: JSON.stringify({
+          ID: this.deskRound.ID,
+          Validated: document.getElementById("deskround-validated").checked,
+        }),
+      });
+      if (response.status !== 200) {
+        throw new Error(
+          `DeskRound could not be updated (status ${response.status})`
+        );
+      }
+      await response.json();
+    } catch (e) {
+      Messages.Show("is-warning", e.message);
+      console.error(e);
+      return;
+    }
+    Messages.Show("is-success", "Bureau de vote mis à jour");
+    this.displayDesks();
+  }
 }
diff --git a/web/components/management/round.js b/web/components/management/round.js
index 864b26b1dee9623b8d662127b2a97a4f813e0720..a977ceaa39cdc2e3e620bc1dc3b11f6aff80b61f 100644
--- a/web/components/management/round.js
+++ b/web/components/management/round.js
@@ -39,8 +39,8 @@ class Round {
       <div class="modal" id="round-modal"></div>
     `;
     current_user = await Auth.GetUser();
-    this.roundsHandler = RoundsCard.mount("rounds-list", this)
-    this.roundsHandler = RoundDesks.mount("round-desks", this)
-    this.roundsHandler = CandidateList.mount("candidate-lists", this)
+    this.roundsHandler = await RoundsCard.mount("rounds-list", this)
+    this.deskRoundsHandler = await RoundDesks.mount("round-desks", this)
+    this.candidateListHandler = await CandidateList.mount("candidate-lists", this)
   }
 }
diff --git a/web/components/management/rounds-card.js b/web/components/management/rounds-card.js
index 81dad9801cbd1baabd79fda895b4bbcd51fbecb4..561b6b09c074174bb958c4ce36267ba68514fb8e 100644
--- a/web/components/management/rounds-card.js
+++ b/web/components/management/rounds-card.js
@@ -168,8 +168,11 @@ class Round {
         });
       document
         .getElementById(`rounds-round-${round.ID}`)
-        .addEventListener("click", function () {
-          // TODO open desk rounds
+        .addEventListener("click", async function () {
+          roundHandler.activateRound(round);
+          roundHandler.parent.deskRoundsHandler.round = round;
+          await roundHandler.parent.deskRoundsHandler.displayDesks();
+          document.getElementById("candidate-list-new").setAttribute("disabled", "true");
           // TODO open candidate list
         });
     });
@@ -211,16 +214,16 @@ class Round {
   }
 
   async activateRound(roundToActivate) {
-    // TODO unselect desks and candidateLists
     let rounds = await this.updateRounds();
     rounds.forEach((round) => {
       document
-        .getElementById(`rounds-round-${round.ID}`)
-        .classList.remove("active-card");
+      .getElementById(`rounds-round-${round.ID}`)
+      .classList.remove("active-card");
     });
     document
-      .getElementById(`rounds-round-${roundToActivate.ID}`)
-      .classList.add("active-card");
+    .getElementById(`rounds-round-${roundToActivate.ID}`)
+    .classList.add("active-card");
+    // TODO unselect candidateLists
   }
 
   newRound() {
@@ -235,7 +238,9 @@ class Round {
     this.method = "PUT";
     document.getElementById("round-modal-id").value = round.ID;
     document.getElementById("round-modal-election-id").value = round.ElectionID;
-    document.getElementById("round-modal-date").value = new Date(round.Date).toISOString().split('T')[0];
+    document.getElementById("round-modal-date").value = new Date(round.Date)
+      .toISOString()
+      .split("T")[0];
     document.getElementById("round-modal-round").value = round.Round;
     Common.toggleModal("round-modal", "round-modal-card");
   }
@@ -265,7 +270,7 @@ class Round {
       );
       if (response.status !== 200) {
         throw new Error(
-          `Area could not be updated or created (status ${response.status})`
+          `Round could not be updated or created (status ${response.status})`
         );
       }
       round = await response.json();
diff --git a/web/services/common/getters.js b/web/services/common/getters.js
index 4691a741319da3a92865a4987eba3a0d5f2ebcdb..25b4e4ea8e808105c71b714afb8d71d812c8f22b 100644
--- a/web/services/common/getters.js
+++ b/web/services/common/getters.js
@@ -36,4 +36,24 @@ export async function getElection(current_user, id) {
     Messages.Show("is-warning", e.message);
     console.error(e);
   }
+}
+
+export async function getDesk(current_user, id) {
+  try {
+    const response = await fetch("/api/Desk/" + id, {
+      method: "GET",
+      headers: new Headers({
+        "XSRF-Token": current_user.xsrftoken,
+      }),
+    });
+    if (response.status !== 200) {
+      throw new Error(
+        `Desk could not be fetched (status ${response.status})`
+      );
+    }
+    return await response.json();
+  } catch (e) {
+    Messages.Show("is-warning", e.message);
+    console.error(e);
+  }
 }
\ No newline at end of file
diff --git a/web/style.css b/web/style.css
index 1c4154cd551cf442dc6356d64203047cd30ff9e9..8039cb53528ec56e52a9bfae911e6ea69dc50a9a 100644
--- a/web/style.css
+++ b/web/style.css
@@ -88,19 +88,20 @@ img {
   cursor: auto;
 }
 
-.select, select{
-  width :100%;
+.select,
+select {
+  width: 100%;
 }
 
-.card-list{
+.card-list {
   border: solid lightgray;
   border-width: 0.5px;
   border-radius: 2px;
-  margin:6px;
+  margin: 6px;
 }
 
-.active-card{
-  background-color: rgba(55,122,195,.95);
+.active-card {
+  background-color: rgba(55, 122, 195, 0.95);
   font-weight: bold;
   color: white;
 }
@@ -109,6 +110,14 @@ img {
   flex-basis: 70%;
 }
 
-#round-desks{
+#round-desks {
   height: 35vh;
-}
\ No newline at end of file
+}
+
+#round-desks .column {
+  overflow-y: auto;
+}
+
+#round-desks .columns {
+  max-height: 90%;
+}