diff --git a/src/main/java/org/codelibs/fess/app/web/admin/storage/AdminStorageAction.java b/src/main/java/org/codelibs/fess/app/web/admin/storage/AdminStorageAction.java
index 9846c40c3a5c8fcd5b712a7fd020eef4768918e5..8321b0640a907ab7504eba9ef3462bb703c16bb6 100644
--- a/src/main/java/org/codelibs/fess/app/web/admin/storage/AdminStorageAction.java
+++ b/src/main/java/org/codelibs/fess/app/web/admin/storage/AdminStorageAction.java
@@ -73,17 +73,25 @@ public class AdminStorageAction extends FessAdminAction {
         if (form.uploadFile == null) {
             throwValidationError(messages -> messages.addErrorsStorageNoUploadFile(GLOBAL), () -> asListHtml(form.path));
         }
+        logger.debug("form.path = {}", form.path);
         verifyToken(() -> asListHtml(form.path));
-        final String fileName = form.uploadFile.getFileName();
+        final String objectName = getObjectName(form.path, form.uploadFile.getFileName());
         try (final InputStream in = form.uploadFile.getInputStream()) {
             final MinioClient minioClient = createClient(fessConfig);
-            minioClient.putObject(fessConfig.getStorageBucket(), form.uploadFile.getFileName(), in, (long) form.uploadFile.getFileSize(),
-                    null, null, "application/octet-stream");
+            minioClient.putObject(fessConfig.getStorageBucket(), objectName, in, (long) form.uploadFile.getFileSize(), null, null,
+                    "application/octet-stream");
         } catch (final Exception e) {
-            throwValidationError(messages -> messages.addErrorsStorageFileUploadFailure(GLOBAL, fileName), () -> asListHtml(form.path));
+            if (logger.isDebugEnabled()) {
+                logger.debug("Failed to upload {}", objectName, e);
+            }
+            throwValidationError(messages -> messages.addErrorsStorageFileUploadFailure(GLOBAL, e.getLocalizedMessage()),
+                    () -> asListHtml(form.path));
+        }
+        saveInfo(messages -> messages.addSuccessUploadFileToStorage(GLOBAL, form.uploadFile.getFileName()));
+        if (StringUtil.isEmpty(form.path)) {
+            return redirect(getClass());
         }
-        saveInfo(messages -> messages.addSuccessUploadFileToStorage(GLOBAL, fileName));
-        return redirect(getClass()); // no-op
+        return redirectWith(getClass(), moreUrl("list/" + encodeId(form.path)));
     }
 
     @Execute
@@ -96,7 +104,7 @@ public class AdminStorageAction extends FessAdminAction {
     public ActionResponse download(final String id) {
         final String[] values = decodeId(id);
         if (StringUtil.isEmpty(values[1])) {
-            throwValidationError(messages -> messages.addErrorsStorageFileNotFound(GLOBAL), () -> asListHtml(values[0]));
+            throwValidationError(messages -> messages.addErrorsStorageFileNotFound(GLOBAL), () -> asListHtml(encodeId(values[0])));
         }
         return asStream(values[1]).contentTypeOctetStream().stream(
                 out -> {
@@ -107,11 +115,43 @@ public class AdminStorageAction extends FessAdminAction {
                             logger.debug("Failed to access {}", fessConfig.getStorageEndpoint(), e);
                         }
                         throwValidationError(messages -> messages.addErrorsStorageAccessError(GLOBAL, e.getLocalizedMessage()),
-                                () -> asListHtml(values[0]));
+                                () -> asListHtml(encodeId(values[0])));
                     }
                 });
     }
 
+    @Execute
+    public HtmlResponse delete(final String id) {
+        final String[] values = decodeId(id);
+        if (StringUtil.isEmpty(values[1])) {
+            throwValidationError(messages -> messages.addErrorsStorageFileNotFound(GLOBAL), () -> asListHtml(encodeId(values[0])));
+        }
+        logger.debug("values[0] = {}, values[1] = {}", values[0], values[1]);
+        final String objectName = getObjectName(values[0], values[1]);
+        try {
+            final MinioClient minioClient = createClient(fessConfig);
+            minioClient.removeObject(fessConfig.getStorageBucket(), objectName);
+        } catch (final Exception e) {
+            logger.debug("Failed to delete {}", values[1], e);
+            throwValidationError(messages -> messages.addErrorsFailedToDeleteFile(GLOBAL, e.getLocalizedMessage()),
+                    () -> asListHtml(encodeId(values[0])));
+        }
+        saveInfo(messages -> messages.addSuccessDeleteFile(GLOBAL, values[1]));
+        if (StringUtil.isEmpty(values[0])) {
+            return redirect(getClass());
+        }
+        return redirectWith(getClass(), moreUrl("list/" + encodeId(values[0])));
+    }
+
+    @Execute
+    public HtmlResponse createDir(final ItemForm form) {
+        validate(form, messages -> {}, () -> asListHtml(form.path));
+        if (StringUtil.isBlank(form.name)) {
+            throwValidationError(messages -> messages.addErrorsStorageDirectoryNameIsInvalid(GLOBAL), () -> asListHtml(form.path));
+        }
+        return redirectWith(getClass(), moreUrl("list/" + encodeId(getObjectName(form.path, form.name))));
+    }
+
     public static List<Map<String, Object>> getFileItems(final String prefix) {
         final FessConfig fessConfig = ComponentUtil.getFessConfig();
         final ArrayList<Map<String, Object>> list = new ArrayList<>();
@@ -124,7 +164,8 @@ public class AdminStorageAction extends FessAdminAction {
                 final String objectName = item.objectName();
                 map.put("id", URLEncoder.encode(objectName, Constants.UTF_8_CHARSET));
                 map.put("name", getName(objectName));
-                map.put("size", item.size());
+                map.put("hashCode", item.hashCode());
+                map.put("size", item.objectSize());
                 map.put("directory", item.isDir());
                 if (!item.isDir()) {
                     map.put("lastModified", item.lastModified());
@@ -201,7 +242,7 @@ public class AdminStorageAction extends FessAdminAction {
                 }
                 buf.append(values[i]);
             }
-            return URLEncoder.encode(buf.toString(), Constants.UTF_8_CHARSET);
+            return urlEncode(buf.toString());
         }
         return StringUtil.EMPTY;
     }
@@ -215,13 +256,32 @@ public class AdminStorageAction extends FessAdminAction {
             }
             buf.append(s);
             final Map<String, String> map = new HashMap<>();
-            map.put("id", URLEncoder.encode(buf.toString(), Constants.UTF_8_CHARSET));
+            map.put("id", urlEncode(buf.toString()));
             map.put("name", s);
             list.add(map);
         }));
         return list;
     }
 
+    protected static String getPathPrefix(final String path) {
+        return StringUtil.isEmpty(path) ? StringUtil.EMPTY : path + "/";
+    }
+
+    protected static String getObjectName(final String path, final String name) {
+        return getPathPrefix(path) + name;
+    }
+
+    protected static String urlEncode(final String str) {
+        if (str == null) {
+            return null;
+        }
+        return URLEncoder.encode(str, Constants.UTF_8_CHARSET);
+    }
+
+    protected static String encodeId(final String str) {
+        return urlEncode(urlEncode(str));
+    }
+
     private HtmlResponse asListHtml(final String prefix) {
         return asHtml(path_AdminStorage_AdminStorageJsp).useForm(ItemForm.class).renderWith(data -> {
             RenderDataUtil.register(data, "endpoint", fessConfig.getStorageEndpoint());
diff --git a/src/main/java/org/codelibs/fess/app/web/admin/storage/ItemForm.java b/src/main/java/org/codelibs/fess/app/web/admin/storage/ItemForm.java
index 3b6a6a90e3ed8e7f59e12d144da143ccc05f4f68..a2ea1577bb64f7c76dec1a21c280747be0eca7e5 100644
--- a/src/main/java/org/codelibs/fess/app/web/admin/storage/ItemForm.java
+++ b/src/main/java/org/codelibs/fess/app/web/admin/storage/ItemForm.java
@@ -18,10 +18,9 @@ package org.codelibs.fess.app.web.admin.storage;
 import javax.validation.constraints.Size;
 
 import org.lastaflute.web.ruts.multipart.MultipartFormFile;
-import org.lastaflute.web.validation.Required;
 
 public class ItemForm {
-    @Required
+
     public String path;
 
     @Size(max = 100)
diff --git a/src/main/java/org/codelibs/fess/mylasta/action/FessMessages.java b/src/main/java/org/codelibs/fess/mylasta/action/FessMessages.java
index 3a0cd40ad19a4d7e0d17fbc736b4131d1a9d2b88..4bf3a75f13a9ef04842a8bca4cf10a480702b807 100644
--- a/src/main/java/org/codelibs/fess/mylasta/action/FessMessages.java
+++ b/src/main/java/org/codelibs/fess/mylasta/action/FessMessages.java
@@ -419,6 +419,9 @@ public class FessMessages extends FessLabels {
     /** The key of the message: Upload file is required. */
     public static final String ERRORS_storage_no_upload_file = "{errors.storage_no_upload_file}";
 
+    /** The key of the message: Directory name is invalid. */
+    public static final String ERRORS_storage_directory_name_is_invalid = "{errors.storage_directory_name_is_invalid}";
+
     /** The key of the message: Updated parameters. */
     public static final String SUCCESS_update_crawler_params = "{success.update_crawler_params}";
 
@@ -2414,6 +2417,20 @@ public class FessMessages extends FessLabels {
         return this;
     }
 
+    /**
+     * Add the created action message for the key 'errors.storage_directory_name_is_invalid' with parameters.
+     * <pre>
+     * message: Directory name is invalid.
+     * </pre>
+     * @param property The property name for the message. (NotNull)
+     * @return this. (NotNull)
+     */
+    public FessMessages addErrorsStorageDirectoryNameIsInvalid(String property) {
+        assertPropertyNotNull(property);
+        add(property, new UserMessage(ERRORS_storage_directory_name_is_invalid));
+        return this;
+    }
+
     /**
      * Add the created action message for the key 'success.update_crawler_params' with parameters.
      * <pre>
diff --git a/src/main/resources/fess_message.properties b/src/main/resources/fess_message.properties
index 3f0c3c7034486ae3a748b2dcc2055aa2b21dbcd3..c9bed1343ad4422c6537e747da7cd19ec7fd245d 100644
--- a/src/main/resources/fess_message.properties
+++ b/src/main/resources/fess_message.properties
@@ -165,6 +165,7 @@ errors.storage_file_not_found=The target file is not found in Storage.
 errors.storage_file_download_failure=Failed to download {0}.
 errors.storage_access_error=Storage access error: {0}
 errors.storage_no_upload_file=Upload file is required.
+errors.storage_directory_name_is_invalid=Directory name is invalid.
 
 success.update_crawler_params=Updated parameters.
 success.delete_doc_from_index=Started a process to delete the document from index.
diff --git a/src/main/webapp/WEB-INF/view/admin/storage/admin_storage.jsp b/src/main/webapp/WEB-INF/view/admin/storage/admin_storage.jsp
index 6666a627323de06c6c1bc70d806080cf2b93e267..8270a7228ce3a9f73d2caec62d41447e1ce04745 100644
--- a/src/main/webapp/WEB-INF/view/admin/storage/admin_storage.jsp
+++ b/src/main/webapp/WEB-INF/view/admin/storage/admin_storage.jsp
@@ -42,20 +42,100 @@
 								<div class="data-wrapper">
 									<div class="row">
 										<div class="col-sm-12">
-											Path: ${f:h(endpoint)}/${f:h(bucket)}<c:forEach var="item" varStatus="s" items="${pathItems}">/<a href="${contextPath}/admin/storage/list/${f:u(item.id)}/">${f:h(item.name)}</a></c:forEach>
+											<a  class="fa fa-home" aria-hidden="true" href="${contextPath}/admin/storage/">(Bucket: ${f:h(endpoint)}/${f:h(bucket)})</a>
+											<c:forEach var="item" varStatus="s" items="${pathItems}">
+												<i class="fa fa-chevron-right" aria-hidden="true"></i>
+												<span><a href="${contextPath}/admin/storage/list/${f:u(item.id)}/">${f:h(item.name)}</a></span>
+											</c:forEach>
+											<i class="fa fa-chevron-right" aria-hidden="true"></i>
+
+											<div type="button" class="btn btn-success btn-xs" name="createDir" data-toggle="modal"
+													data-target="#createDir">
+												<i class="fa fa-plus" aria-hidden="true"></i>
+											</div>
+
+											<div class="modal modal-primary" id="createDir"
+												 tabindex="-1" role="dialog"
+											>
+												<div class="modal-dialog">
+													<div class="modal-content">
+														<div class="modal-header">
+															<button type="button" class="close" data-dismiss="modal" aria-label="Close">
+																<span aria-hidden="true">×</span>
+															</button>
+															<h4 class="modal-title">
+																<la:message key="labels.crud_title_create" />
+															</h4>
+														</div>
+														<div class="modal-body col-sm-12">
+															<la:form action="/admin/storage/createDir/" enctype="multipart/form-data" styleClass="form-inline">
+																<div class="form-group">
+																	<input type="text" name="name" class="form-control" />
+																</div>
+																<input type="hidden" name="path" value="${path}" />
+																<button type="submit" class="btn btn-success" name="createDir">
+																	<em class="fa fa-make"></em>
+																	<la:message key="labels.crud_button_create" />
+																</button>
+															</la:form>
+														</div>
+														<div class="modal-footer">
+															<button type="button" class="btn btn-outline pull-left" data-dismiss="modal">
+																<la:message key="labels.crud_button_cancel" />
+															</button>
+														</div>
+													</div>
+												</div>
+											</div>
 										</div>
+									</div>
+
+									<div class="row">
 										<div class="col-sm-12">
-											<la:form action="/admin/storage/upload/" enctype="multipart/form-data" styleClass="form-inline">
-												<div class="form-group">
-													<label for="uploadFile"> <la:message key="labels.storage_upload_file" />
-													</label> <input type="file" name="uploadFile" class="form-control" />
+											<div type="button" class="btn btn-success pull-right" name="upload" data-toggle="modal"
+													data-target="#uploadeFile"
+													value="<la:message key="labels.storage_button_upload" />"
+											>
+												<em class="fa fa-upload"></em>
+												<la:message key="labels.storage_button_upload" />
+											</div>
+											<div class="modal modal-primary" id="uploadeFile"
+												 tabindex="-1" role="dialog"
+											>
+												<div class="modal-dialog">
+													<div class="modal-content">
+														<div class="modal-header">
+															<button type="button" class="close" data-dismiss="modal" aria-label="Close">
+																<span aria-hidden="true">×</span>
+															</button>
+															<h4 class="modal-title">
+																<la:message key="labels.storage_upload_file" />
+															</h4>
+														</div>
+														<div class="modal-body col-sm-12">
+															<la:form action="/admin/storage/upload/" enctype="multipart/form-data" styleClass="form-inline">
+																<div class="form-group">
+																	<input type="file" name="uploadFile" class="form-control" />
+																</div>
+																<input type="hidden" name="path" value="${path}" />
+																<button type="submit" class="btn btn-success" name="upload">
+																	<em class="fa fa-upload"></em>
+																	<la:message key="labels.storage_button_upload" />
+																</button>
+															</la:form>
+														</div>
+														<div class="modal-footer">
+															<button type="button" class="btn btn-outline pull-left" data-dismiss="modal">
+																<la:message key="labels.crud_button_cancel" />
+															</button>
+														</div>
+													</div>
 												</div>
-												<button type="submit" class="btn btn-success" name="upload">
-													<em class="fa fa-upload"></em>
-													<la:message key="labels.storage_button_upload" />
-												</button>
-											</la:form>
+											</div>
 										</div>
+									</div>
+
+									<div class="row">
 										<div class="col-sm-12">
 											<table class="table table-bordered table-striped dataTable">
 												<tbody>
@@ -77,23 +157,81 @@
 														<td>..</td>
 														<td></td>
 														<td></td>
+														<td></td>
 													</tr></c:if>
 													<c:forEach var="data" varStatus="s" items="${fileItems}">
 														<c:if test="${not data.directory}">
-														<tr
-															data-href="${contextPath}/admin/storage/download/${f:u(data.id)}/">
-															<td>${f:h(data.name)}</td>
+														<tr>
+															<td>
+																<em class="fa fa-file"></em>
+																	${f:h(data.name)}
+															</td>
 															<td>${f:h(data.size)}</td>
-															<td>${f:h(data.lastModifed)}</td>
-														</tr>
-														</c:if><c:if test="${data.directory.booleanValue()}">
+															<td>${f:h(data.lastModified)}</td>
+														</c:if>
+														<c:if test="${data.directory.booleanValue()}">
 														<tr
 															data-href="${contextPath}/admin/storage/list/${f:u(data.id)}/">
-															<td>${f:h(data.name)}</td>
+															<td>
+																<em class="fa fa-folder-open"></em>
+																	${f:h(data.name)}
+															</td>
 															<td></td>
 															<td></td>
-														</tr>
 														</c:if>
+														<td>
+															<c:if test="${not data.directory}">
+																<a class="btn btn-primary btn-xs" role="button" name="download" data-toggle="modal"
+																		href="${contextPath}/admin/storage/download/${f:u(data.id)}/" download="${f:u(data.name)}"
+																	value="<la:message key="labels.design_download_button" />"
+																	>
+																	<em class="fa fa-download"></em>
+																	<la:message key="labels.design_download_button" />
+																</a>
+																<button type="button" class="btn btn-danger btn-xs" name="delete" data-toggle="modal"
+																		data-target="#confirmToDelete-${f:h(data.hashCode)}"
+																		value="<la:message key="labels.design_delete_button" />"
+																>
+																	<em class="fa fa-times"></em>
+																	<la:message key="labels.design_delete_button" />
+																</button>
+																<div class="modal modal-danger fade" id="confirmToDelete-${f:h(data.hashCode)}"
+																	 tabindex="-1" role="dialog"
+																>
+																	<div class="modal-dialog">
+																		<div class="modal-content">
+																			<div class="modal-header">
+																				<button type="button" class="close" data-dismiss="modal" aria-label="Close">
+																					<span aria-hidden="true">×</span>
+																				</button>
+																				<h4 class="modal-title">
+																					<la:message key="labels.crud_title_delete" /> : ${f:h(data.name)}
+																				</h4>
+																			</div>
+																			<div class="modal-body">
+																				<p>
+																					<la:message key="labels.crud_delete_confirmation" />
+																				</p>
+																			</div>
+																			<div class="modal-footer">
+																				<button type="button" class="btn btn-outline pull-left" data-dismiss="modal">
+																					<la:message key="labels.crud_button_cancel" />
+																				</button>
+																				<la:form action="${contextPath}/admin/storage/delete/${f:u(data.id)}/" styleClass="form-horizontal">
+																					<button type="submit" class="btn btn-outline btn-danger" name="delete"
+																							value="<la:message key="labels.crud_button_delete" />"
+																					>
+																						<em class="fa fa-trash"></em>
+																						<la:message key="labels.crud_button_delete" />
+																					</button>
+																				</la:form>
+																			</div>
+																		</div>
+																	</div>
+																</div>
+															</c:if>
+														</td>
+														</tr>
 													</c:forEach>
 												</tbody>
 											</table>
@@ -114,4 +252,3 @@
 	<jsp:include page="/WEB-INF/view/common/admin/foot.jsp"></jsp:include>
 </body>
 </html>
-