diff --git a/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/UserFilter.java b/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/UserFilter.java
new file mode 100644
index 0000000000000000000000000000000000000000..40e7293e7ce5665aba7b8dfc02b326aee88926d6
--- /dev/null
+++ b/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/UserFilter.java
@@ -0,0 +1,48 @@
+package it.inaf.ia2.vospace.ui;
+
+import it.inaf.ia2.aa.data.User;
+import java.io.IOException;
+import java.security.Principal;
+import java.util.ArrayList;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import javax.servlet.http.HttpSession;
+
+/**
+ * Extracts user from the session and set it as request Principal.
+ */
+public class UserFilter implements Filter {
+
+    @Override
+    public void doFilter(ServletRequest req, ServletResponse res, FilterChain fc) throws IOException, ServletException {
+        HttpServletRequestWrapper requestWithPrincipal = new RequestWithPrincipal((HttpServletRequest) req);
+        fc.doFilter(requestWithPrincipal, res);
+    }
+
+    private static class RequestWithPrincipal extends HttpServletRequestWrapper {
+
+        private final User user;
+
+        public RequestWithPrincipal(HttpServletRequest request) {
+            super(request);
+            HttpSession session = request.getSession(false);
+            if (session == null || session.getAttribute("user_data") == null) {
+                this.user = new User()
+                        .setUserId("anonymous").setUserLabel("Anonymous")
+                        .setGroups(new ArrayList<>());
+            } else {
+                this.user = (User) session.getAttribute("user_data");
+            }
+        }
+
+        @Override
+        public Principal getUserPrincipal() {
+            return user;
+        }
+    }
+}
diff --git a/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/VOSpaceUiApplication.java b/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/VOSpaceUiApplication.java
index a015518a7b14ed090c3ade06c89761b04563b849..8d16a8ad4ffa6538d7f5a1ca380f5c8109a9959a 100644
--- a/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/VOSpaceUiApplication.java
+++ b/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/VOSpaceUiApplication.java
@@ -35,6 +35,14 @@ public class VOSpaceUiApplication {
         return registration;
     }
 
+    @Bean
+    public FilterRegistrationBean userFilterRegistration() {
+        FilterRegistrationBean registration = new FilterRegistrationBean();
+        registration.setFilter(new UserFilter());
+        registration.addUrlPatterns("/*");
+        return registration;
+    }
+
     @Bean
     public UserManager userManager() {
         return ServiceLocator.getInstance().getUserManager();
diff --git a/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/controller/NodesController.java b/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/controller/NodesController.java
index 73f129979593a4fb8d39fbf306b701d5f8d24472..4e12e12c2b6c5a03285241fb7a6de52fead5650f 100644
--- a/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/controller/NodesController.java
+++ b/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/controller/NodesController.java
@@ -1,6 +1,8 @@
 package it.inaf.ia2.vospace.ui.controller;
 
+import it.inaf.ia2.aa.data.User;
 import it.inaf.ia2.vospace.ui.client.VOSpaceClient;
+import it.inaf.ia2.vospace.ui.data.ListNodeData;
 import it.inaf.ia2.vospace.ui.service.NodesService;
 import java.util.Map;
 import javax.servlet.http.HttpServletRequest;
@@ -35,20 +37,12 @@ public class NodesController extends BaseController {
     @Autowired
     private HttpServletRequest servletRequest;
 
-    /**
-     * This is the only API endpoint that returns HTML code instead of JSON. The
-     * reason is that JavaScript frameworks are not very efficient in handling
-     * very long lists and tables, so this part of the code is generated
-     * server-side. The content type is set to text/plain even if it is an HTML
-     * fragment to avoid browser parsing issues since it is not a complete HTML
-     * document.
-     */
-    @GetMapping(value = {"/nodes", "/nodes/**"}, produces = MediaType.TEXT_PLAIN_VALUE)
-    public String listNodes() throws Exception {
+    @GetMapping(value = {"/nodes", "/nodes/**"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    public ResponseEntity<ListNodeData> listNodes(User principal) throws Exception {
 
         String path = getPath("/nodes/");
 
-        return nodesService.generateNodesHtml(path);
+        return ResponseEntity.ok(nodesService.generateNodesHtml(path, principal));
     }
 
     @DeleteMapping(value = {"/nodes", "/nodes/**"})
diff --git a/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/data/Job.java b/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/data/Job.java
index 180fc322c76945e2f62e6d1fdeac211398972fdb..6515a507096921c6d72a95a5b9181c7ac0f92acb 100644
--- a/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/data/Job.java
+++ b/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/data/Job.java
@@ -29,6 +29,9 @@ public class Job {
     }
 
     private String formatCreationTime(XMLGregorianCalendar calendar) {
+        if (calendar == null) {
+            return null;
+        }
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
         return sdf.format(calendar.toGregorianCalendar().getTime());
     }
diff --git a/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/data/ListNodeData.java b/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/data/ListNodeData.java
new file mode 100644
index 0000000000000000000000000000000000000000..2692ef404bcd62392e5dd134ae8674a24e3efce0
--- /dev/null
+++ b/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/data/ListNodeData.java
@@ -0,0 +1,23 @@
+package it.inaf.ia2.vospace.ui.data;
+
+public class ListNodeData {
+
+    private String htmlTable;
+    private boolean writable;
+
+    public String getHtmlTable() {
+        return htmlTable;
+    }
+
+    public void setHtmlTable(String htmlTable) {
+        this.htmlTable = htmlTable;
+    }
+
+    public boolean isWritable() {
+        return writable;
+    }
+
+    public void setWritable(boolean writable) {
+        this.writable = writable;
+    }
+}
diff --git a/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/service/NodeInfo.java b/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/service/NodeInfo.java
index 82d66fd030b6b9cb055ae41b4a423d9196989861..987886a40184ebb99b6058791ca5d28464ab14d0 100644
--- a/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/service/NodeInfo.java
+++ b/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/service/NodeInfo.java
@@ -1,9 +1,13 @@
 package it.inaf.ia2.vospace.ui.service;
 
 import it.inaf.ia2.vospace.ui.exception.VOSpaceException;
+import it.inaf.oats.vospace.datamodel.NodeProperties;
+import java.util.List;
 import java.util.Optional;
+import net.ivoa.xml.vospace.v2.DataNode;
 import net.ivoa.xml.vospace.v2.Node;
 import net.ivoa.xml.vospace.v2.Property;
+import net.ivoa.xml.vospace.v2.View;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -17,10 +21,13 @@ public class NodeInfo {
     private final String name;
     private final String size;
     private final String type;
+    private final String creator;
     private final String groupRead;
     private final String groupWrite;
     private final boolean isPublic;
     private final boolean asyncTrans;
+    private final boolean busy;
+    private final boolean listOfFiles;
 
     public NodeInfo(Node node, String authority) {
         this.authority = authority;
@@ -28,10 +35,13 @@ public class NodeInfo {
         this.name = path.substring(path.lastIndexOf("/") + 1);
         this.size = getSize(node);
         this.type = node.getType();
+        this.creator = getCreator(node);
         this.groupRead = getGroupRead(node);
         this.groupWrite = getGroupWrite(node);
         this.isPublic = isPublic(node);
         this.asyncTrans = isAsyncTrans(node);
+        this.busy = isBusy(node);
+        this.listOfFiles = isListOfFiles(node);
     }
 
     private String getPath(Node node) {
@@ -46,22 +56,45 @@ public class NodeInfo {
 
         return uri.substring(prefix.length());
     }
+    
+    private String getCreator(Node node) {
+        return getProperty(node, NodeProperties.CREATOR_URI).orElse("");
+    }
 
     private String getGroupRead(Node node) {
-        return getProperty(node, "ivo://ivoa.net/vospace/core#groupread").orElse("");
+        return getProperty(node, NodeProperties.GROUP_READ_URI).orElse("");
     }
 
     private String getGroupWrite(Node node) {
-        return getProperty(node, "ivo://ivoa.net/vospace/core#groupwrite").orElse("");
+        return getProperty(node, NodeProperties.GROUP_WRITE_URI).orElse("");
     }
 
     private boolean isPublic(Node node) {
-        return getProperty(node, "ivo://ivoa.net/vospace/core#ispublic").map(value -> "t".equals(value)).orElse(false);
+        return getProperty(node, NodeProperties.PUBLIC_READ_URI).map(value -> "t".equals(value)).orElse(false);
     }
 
     private boolean isAsyncTrans(Node node) {
         return getProperty(node, "urn:async_trans").map(value -> "t".equals(value)).orElse(false);
     }
+    
+    private boolean isBusy(Node node) {
+        return node instanceof DataNode && ((DataNode) node).isBusy();
+    }
+
+    private boolean isListOfFiles(Node node) {
+        if (node instanceof DataNode) {
+            DataNode dataNode = (DataNode) node;
+            List<View> provides = dataNode.getProvides();
+            if (provides != null) {
+                for (View provide : provides) {
+                    if ("urn:list-of-files".equals(provide.getUri())) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
 
     private Optional<String> getProperty(Node node, String uri) {
         if (node.getProperties() != null && node.getProperties() != null) {
@@ -122,6 +155,10 @@ public class NodeInfo {
         return size;
     }
 
+    public String getCreator() {
+        return creator;
+    }
+
     public String getGroupRead() {
         return groupRead;
     }
@@ -137,4 +174,12 @@ public class NodeInfo {
     public boolean isAsyncTrans() {
         return asyncTrans;
     }
+
+    public boolean isBusy() {
+        return busy;
+    }
+
+    public boolean isListOfFiles() {
+        return listOfFiles;
+    }
 }
diff --git a/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/service/NodesService.java b/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/service/NodesService.java
index 5d347db12aee6063680d1ec6639b227c2fd82aa5..4c3b4bfa816c7ce9a97cea44f177ad55e01de9dd 100644
--- a/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/service/NodesService.java
+++ b/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/service/NodesService.java
@@ -1,9 +1,14 @@
 package it.inaf.ia2.vospace.ui.service;
 
+import it.inaf.ia2.aa.data.User;
 import it.inaf.ia2.vospace.ui.client.VOSpaceClient;
+import it.inaf.ia2.vospace.ui.data.ListNodeData;
+import it.inaf.oats.vospace.datamodel.NodeUtils;
 import java.io.IOException;
 import java.io.StringWriter;
 import java.io.UncheckedIOException;
+import java.util.Arrays;
+import java.util.List;
 import net.ivoa.xml.vospace.v2.ContainerNode;
 import net.ivoa.xml.vospace.v2.Node;
 import org.slf4j.Logger;
@@ -23,32 +28,38 @@ public class NodesService {
     @Value("${vospace-authority}")
     private String authority;
 
-    public String generateNodesHtml(String path) {
+    public ListNodeData generateNodesHtml(String path, User user) {
 
+        ListNodeData listNodeData = new ListNodeData();
+        
         Node node = client.getNode(path);
+        
+        listNodeData.setWritable(NodeUtils.checkIfWritable(node, user.getName(), user.getGroups()));
 
-        try ( StringWriter sw = new StringWriter()) {
+        try (StringWriter sw = new StringWriter()) {
 
             if (node instanceof ContainerNode) {
                 ContainerNode folder = (ContainerNode) node;
                 sw.write("<tbody id=\"nodes\">");
                 for (Node child : folder.getNodes()) {
-                    sw.write(getNodeHtml(child));
+                    sw.write(getNodeHtml(child, user));
                 }
                 sw.write("</tbody>");
             }
 
-            return sw.toString();
+            listNodeData.setHtmlTable(sw.toString());
+            
+            return listNodeData;
         } catch (IOException ex) {
             throw new UncheckedIOException(ex);
         }
     }
 
-    private String getNodeHtml(Node node) {
+    private String getNodeHtml(Node node, User user) {
 
         NodeInfo nodeInfo = new NodeInfo(node, authority);
 
-        if (nodeInfo.getName().startsWith(".")) {
+        if (nodeInfo.isListOfFiles()) {
             // hidden file
             return "";
         }
@@ -59,31 +70,39 @@ public class NodesService {
             html += "class=\"async\"";
         }
         html += "/></td>";
-        html += "<td>" + getIcon(nodeInfo) + getLink(nodeInfo) + "</td>";
+        html += "<td>" + getIcon(nodeInfo) + getLink(nodeInfo, user) + "</td>";
         html += "<td>" + nodeInfo.getSize() + "</td>";
         html += "<td>" + nodeInfo.getGroupRead() + "</td>";
         html += "<td>" + nodeInfo.getGroupWrite() + "</td>";
-        html += "<td><span class=\"icon trash-icon pointer\" onclick=\"deleteNode('" + nodeInfo.getPath() + "')\"></span></td>";
+        html += "<td>";
+        if (NodeUtils.checkIfWritable(node, user.getName(), user.getGroups())) {
+            html += "<span class=\"icon trash-icon pointer\" onclick=\"deleteNode('" + nodeInfo.getPath() + "')\"></span>";
+        }
+        html += "</td>";
         html += "</tr>";
         return html;
     }
 
     private String getIcon(NodeInfo nodeInfo) {
         String html = "<span class=\"icon ";
-        if (nodeInfo.isFolder()) {
-            html += "folder";
+        if (nodeInfo.isFile() && nodeInfo.isBusy()) {
+            html += "gear";
         } else {
-            html += "file";
-        }
-        if (nodeInfo.isAsyncTrans()) {
-            html += "-x";
+            if (nodeInfo.isFolder()) {
+                html += "folder";
+            } else {
+                html += "file";
+            }
+            if (nodeInfo.isAsyncTrans()) {
+                html += "-x";
+            }
         }
         html += "-icon\"></span>&nbsp;";
         return html;
     }
 
-    private String getLink(NodeInfo nodeInfo) {
-        if (isDownloadable(nodeInfo)) {
+    private String getLink(NodeInfo nodeInfo, User user) {
+        if (isDownloadable(nodeInfo, user)) {
             if (nodeInfo.isFolder()) {
                 return "<a href=\"#/nodes" + nodeInfo.getPath() + "\">" + nodeInfo.getName() + "</a>";
             } else {
@@ -93,14 +112,29 @@ public class NodesService {
         return nodeInfo.getName();
     }
 
-    private boolean isDownloadable(NodeInfo nodeInfo) {
-        if (nodeInfo.isFile() && nodeInfo.isAsyncTrans()) {
-            return false;
+    private boolean isDownloadable(NodeInfo nodeInfo, User user) {
+        if (nodeInfo.isFile()) {
+            if (nodeInfo.isAsyncTrans() || nodeInfo.isBusy()) {
+                return false;
+            }
         }
         if (nodeInfo.isPublic()) {
             return true;
         }
-        // TODO: check user group
-        return true; // temporary always true
+        
+        if (nodeInfo.getCreator().equals(user.getName())) {
+            return true;
+        }
+
+        if (user.getGroups() != null && !user.getGroups().isEmpty() && !nodeInfo.getGroupRead().isEmpty()) {
+            List<String> groupRead = Arrays.asList(nodeInfo.getGroupRead().split(" "));
+            for (String group : groupRead) {
+                if (user.getGroups().contains(group)) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
     }
 }
diff --git a/vospace-ui-backend/src/test/java/it/inaf/ia2/vospace/ui/controller/NodesControllerTest.java b/vospace-ui-backend/src/test/java/it/inaf/ia2/vospace/ui/controller/NodesControllerTest.java
index d4291fb3c2a090bef5519a9e73897e788ecd37fc..085b3f22f704aabb419365db1b8fbbfc89578261 100644
--- a/vospace-ui-backend/src/test/java/it/inaf/ia2/vospace/ui/controller/NodesControllerTest.java
+++ b/vospace-ui-backend/src/test/java/it/inaf/ia2/vospace/ui/controller/NodesControllerTest.java
@@ -2,6 +2,7 @@ package it.inaf.ia2.vospace.ui.controller;
 
 import it.inaf.ia2.vospace.ui.service.NodesService;
 import org.junit.jupiter.api.Test;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.verify;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -21,14 +22,14 @@ public class NodesControllerTest {
 
     @Autowired
     private MockMvc mockMvc;
-
+    
     @Test
     public void testListNodesEmpty() throws Exception {
 
         mockMvc.perform(get("/nodes"))
                 .andExpect(status().isOk());
 
-        verify(nodesService).generateNodesHtml(eq("/"));
+        verify(nodesService).generateNodesHtml(eq("/"), any());
     }
 
     @Test
@@ -37,7 +38,7 @@ public class NodesControllerTest {
         mockMvc.perform(get("/nodes/"))
                 .andExpect(status().isOk());
 
-        verify(nodesService).generateNodesHtml(eq("/"));
+        verify(nodesService).generateNodesHtml(eq("/"), any());
     }
 
     @Test
@@ -46,6 +47,6 @@ public class NodesControllerTest {
         mockMvc.perform(get("/nodes/a/b/c"))
                 .andExpect(status().isOk());
 
-        verify(nodesService).generateNodesHtml(eq("/a/b/c"));
+        verify(nodesService).generateNodesHtml(eq("/a/b/c"), any());
     }
 }
diff --git a/vospace-ui-frontend/src/api/mock/data/nodes/folder1.html b/vospace-ui-frontend/src/api/mock/data/nodes/folder1.html
deleted file mode 100644
index cacb3e10a71ada0a8ea50143c63c2ae4a3c3a88c..0000000000000000000000000000000000000000
--- a/vospace-ui-frontend/src/api/mock/data/nodes/folder1.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<tbody id="nodes">
-  <tr>
-    <td><input type="checkbox" class="async" data-node="/folder1/folder2" /></td>
-    <td>
-      <span class="icon folder-x-icon"></span>
-      <a href="#/nodes/folder1/folder2">folder2</a>
-    </td>
-    <td>0 B</td>
-    <td>group1</td>
-    <td>group2</td>
-    <td></td>
-  </tr>
-  <tr>
-    <td><input type="checkbox" data-node="/folder1/file2" /></td>
-    <td>
-      <span class="icon file-icon"></span>
-      <a href="download/file2">file2</a>
-    </td>
-    <td>30 KB</td>
-    <td>group1</td>
-    <td>group2</td>
-    <td></td>
-  </tr>
-  <tr>
-    <td><input type="checkbox" class="async" data-node="/folder1/file3" /></td>
-    <td>
-      <span class="icon file-x-icon"></span>
-      file3
-    </td>
-    <td>12 MB</td>
-    <td>group3</td>
-    <td>group4</td>
-    <td></td>
-  </tr>
-</tbody>
diff --git a/vospace-ui-frontend/src/api/mock/data/nodes/folder1.json b/vospace-ui-frontend/src/api/mock/data/nodes/folder1.json
new file mode 100644
index 0000000000000000000000000000000000000000..2527b190cc2166c84b163caf6d1cebfe630fc7fd
--- /dev/null
+++ b/vospace-ui-frontend/src/api/mock/data/nodes/folder1.json
@@ -0,0 +1,4 @@
+{
+  "writable": true,
+  "htmlTable": "<tbody id=\"nodes\">  <tr>    <td><input type=\"checkbox\" class=\"async\" data-node=\"/folder1/folder2\" /></td>    <td>      <span class=\"icon folder-x-icon\"></span>      <a href=\"#/nodes/folder1/folder2\">folder2</a>    </td>    <td>0 B</td>    <td>group1</td>    <td>group2</td>    <td></td>  </tr>  <tr>    <td><input type=\"checkbox\" data-node=\"/folder1/file2\" /></td>    <td>      <span class=\"icon file-icon\"></span>      <a href=\"download/file2\">file2</a>    </td>    <td>30 KB</td>    <td>group1</td>    <td>group2</td>    <td></td>  </tr>  <tr>    <td><input type=\"checkbox\" class=\"async\" data-node=\"/folder1/file3\" /></td>    <td>      <span class=\"icon file-x-icon\"></span>      file3    </td>    <td>12 MB</td>    <td>group3</td>    <td>group4</td>    <td></td>  </tr></tbody>"
+}
diff --git a/vospace-ui-frontend/src/api/mock/data/nodes/folder2.html b/vospace-ui-frontend/src/api/mock/data/nodes/folder2.html
deleted file mode 100644
index 2c52dd94f004b9b9769f2c619248fd5600ad3cb2..0000000000000000000000000000000000000000
--- a/vospace-ui-frontend/src/api/mock/data/nodes/folder2.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<tbody id="nodes">
-  <tr>
-    <td><input type="checkbox" class="async" data-node="/folder1/folder2/file4" /></td>
-    <td>
-      <span class="icon file-x-icon"></span>
-      file4
-    </td>
-    <td>10 KB</td>
-    <td>group1</td>
-    <td>group2</td>
-    <td></td>
-  </tr>
-  <tr>
-    <td><input type="checkbox" class="async" data-node="/folder1/folder2/file5" /></td>
-    <td>
-      <span class="icon file-x-icon"></span>
-      file5
-    </td>
-    <td>15 MB</td>
-    <td>group3</td>
-    <td>group4</td>
-    <td></td>
-  </tr>
-</tbody>
diff --git a/vospace-ui-frontend/src/api/mock/data/nodes/folder2.json b/vospace-ui-frontend/src/api/mock/data/nodes/folder2.json
new file mode 100644
index 0000000000000000000000000000000000000000..be52e8203e87de9972b10dabfea1050d340837c6
--- /dev/null
+++ b/vospace-ui-frontend/src/api/mock/data/nodes/folder2.json
@@ -0,0 +1,4 @@
+{
+  "writable": false,
+  "htmlTable": "<tbody id=\"nodes\">  <tr>    <td><input type=\"checkbox\" class=\"async\" data-node=\"/folder1/folder2/file4\" /></td>    <td>      <span class=\"icon file-x-icon\"></span>      file4    </td>    <td>10 KB</td>    <td>group1</td>    <td>group2</td>    <td></td>  </tr>  <tr>    <td><input type=\"checkbox\" class=\"async\" data-node=\"/folder1/folder2/file5\" /></td>    <td>      <span class=\"icon file-x-icon\"></span>      file5    </td>    <td>15 MB</td>    <td>group3</td>    <td>group4</td>    <td></td>  </tr></tbody>"
+}
diff --git a/vospace-ui-frontend/src/api/mock/data/nodes/root.html b/vospace-ui-frontend/src/api/mock/data/nodes/root.html
deleted file mode 100644
index d6143ada2949a9b7bf83839faaf6936292cb9ce3..0000000000000000000000000000000000000000
--- a/vospace-ui-frontend/src/api/mock/data/nodes/root.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<tbody id="nodes">
-  <tr>
-    <td><input type="checkbox" data-node="/folder1" /></td>
-    <td>
-      <span class="icon folder-icon"></span>
-      <a href="#/nodes/folder1">folder1</a>
-    </td>
-    <td>0 B</td>
-    <td>group1</td>
-    <td>group2</td>
-    <td>
-      <span class="icon trash-icon pointer" onclick="deleteNode('/folder1')"></span>
-    </td>
-  </tr>
-  <tr>
-    <td><input type="checkbox" data-node="/file1" /></td>
-    <td>
-      <span class="icon file-icon"></span>
-      <a href="download/file1">file1</a>
-    </td>
-    <td>12 MB</td>
-    <td>group1</td>
-    <td>group2</td>
-    <td></td>
-  </tr>
-</tbody>
diff --git a/vospace-ui-frontend/src/api/mock/data/nodes/root.json b/vospace-ui-frontend/src/api/mock/data/nodes/root.json
new file mode 100644
index 0000000000000000000000000000000000000000..dcd4c04815c6d060abf98aa7579b38931f4392c2
--- /dev/null
+++ b/vospace-ui-frontend/src/api/mock/data/nodes/root.json
@@ -0,0 +1,4 @@
+{
+  "writable": true,
+  "htmlTable": "<tbody id=\"nodes\">  <tr>    <td><input type=\"checkbox\" data-node=\"/folder1\" /></td>    <td>      <span class=\"icon folder-icon\"></span>      <a href=\"#/nodes/folder1\">folder1</a>    </td>    <td>0 B</td>    <td>group1</td>    <td>group2</td>    <td>      <span class=\"icon trash-icon pointer\" onclick=\"deleteNode('/folder1')\"></span>    </td>  </tr>  <tr>    <td><input type=\"checkbox\" data-node=\"/file1\" /></td>    <td>      <span class=\"icon file-icon\"></span>      <a href=\"download/file1\">file1</a>    </td>    <td>12 MB</td>    <td>group1</td>    <td>group2</td>    <td></td>  </tr></tbody>"
+}
diff --git a/vospace-ui-frontend/src/api/mock/index.js b/vospace-ui-frontend/src/api/mock/index.js
index 9de8cecf14206a496622264a0703b08b479c6de2..9924ec950efcf6aa1963bd3e47dbdfac6750c471 100644
--- a/vospace-ui-frontend/src/api/mock/index.js
+++ b/vospace-ui-frontend/src/api/mock/index.js
@@ -1,6 +1,6 @@
-import root from 'raw-loader!./data/nodes/root.html';
-import folder1 from 'raw-loader!./data/nodes/folder1.html';
-import folder2 from 'raw-loader!./data/nodes/folder2.html';
+import root from './data/nodes/root';
+import folder1 from './data/nodes/folder1';
+import folder2 from './data/nodes/folder2';
 import job from './data/job';
 import jobs from './data/jobs';
 import user from './data/user';
diff --git a/vospace-ui-frontend/src/components/Main.vue b/vospace-ui-frontend/src/components/Main.vue
index c1ce55f728d76e06926d765782d3b919da8bdce7..e9147d76018db4fb8247e89cb71cd3fd70033389 100644
--- a/vospace-ui-frontend/src/components/Main.vue
+++ b/vospace-ui-frontend/src/components/Main.vue
@@ -2,8 +2,8 @@
 <div class="container">
   <b-breadcrumb :items="breadcrumbs"></b-breadcrumb>
   <div class="mb-3">
-    <b-button variant="success" class="mr-2" :disabled="false" v-b-modal.create-folder-modal>New folder</b-button>
-    <b-button variant="success" class="mr-2" :disabled="false" v-b-modal.upload-files-modal>Upload files</b-button>
+    <b-button variant="success" class="mr-2" :disabled="!writable" v-b-modal.create-folder-modal>New folder</b-button>
+    <b-button variant="success" class="mr-2" :disabled="!writable" v-b-modal.upload-files-modal>Upload files</b-button>
     <b-button variant="primary" class="mr-2" v-if="asyncButtonEnabled" @click="startAsyncRecallJob">Async recall</b-button>
   </div>
   <b-card>
@@ -68,6 +68,9 @@ export default {
     },
     asyncButtonEnabled() {
       return this.$store.state.asyncButtonEnabled;
+    },
+    writable() {
+      return this.$store.state.writable;
     }
   },
   created() {
diff --git a/vospace-ui-frontend/src/store.js b/vospace-ui-frontend/src/store.js
index 628d91c43e3dce1b25a4d3364bd132a5ec5d0214..8cd9bd82cfc67cf72dd4044533e86f212af38986 100644
--- a/vospace-ui-frontend/src/store.js
+++ b/vospace-ui-frontend/src/store.js
@@ -14,7 +14,8 @@ export default new Vuex.Store({
     asyncButtonEnabled: false,
     jobs: [],
     user: 'anonymous',
-    nodeToDelete: null
+    nodeToDelete: null,
+    writable: false
   },
   mutations: {
     setLoading(state, loading) {
@@ -45,6 +46,9 @@ export default new Vuex.Store({
     },
     setNodeToDelete(state, path) {
       state.nodeToDelete = path;
+    },
+    setWritable(state, value) {
+      state.writable = value;
     }
   },
   actions: {
@@ -52,7 +56,8 @@ export default new Vuex.Store({
       commit('setPath', path);
       client.getNode(state.path)
         .then(res => {
-          document.getElementById('nodes').outerHTML = res;
+          commit('setWritable', res.writable);
+          document.getElementById('nodes').outerHTML = res.htmlTable;
           let checkboxes = document.querySelectorAll('#nodes input[type="checkbox"]');
           for (let i = 0; i < checkboxes.length; i++) {
             checkboxes[i].addEventListener('change', function() {