diff --git a/ui/src/App.vue b/ui/src/App.vue
index ed66128..5d99e9c 100644
--- a/ui/src/App.vue
+++ b/ui/src/App.vue
@@ -57,6 +57,9 @@ export default {
closeAllInteractions() {
this.$store.dispatch("files/closeAllInteractions");
+ this.$store.dispatch("access/closeAllInteractions");
+
+ // close dropdrowns in access page and buckets if it has any
}
},
watch: {
diff --git a/ui/src/components/Access.vue b/ui/src/components/Access.vue
new file mode 100644
index 0000000..accdc0e
--- /dev/null
+++ b/ui/src/components/Access.vue
@@ -0,0 +1,65 @@
+
+
+
+ Keys
+
+
+
+
+
+
+
+
diff --git a/ui/src/components/AccessTableHeader.vue b/ui/src/components/AccessTableHeader.vue
new file mode 100644
index 0000000..ae2d873
--- /dev/null
+++ b/ui/src/components/AccessTableHeader.vue
@@ -0,0 +1,269 @@
+
+
+
+
+
+
+
+
+ {{ date }}
+
+
+
+
+
+
+
+
+
diff --git a/ui/src/lib/satellite.js b/ui/src/lib/satellite.js
index f5e1eaf..082676e 100644
--- a/ui/src/lib/satellite.js
+++ b/ui/src/lib/satellite.js
@@ -153,3 +153,87 @@ export async function createApiKey({ token, projectId, name }) {
return { key };
}
+
+export async function getAccessKeys({
+ token,
+ projectId,
+ limit,
+ search,
+ page,
+ order,
+ orderDirection
+}) {
+ const response = await fetch("/api/v0/graphql", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ Cookie: `_tokenKey=${token}`
+ },
+ body: JSON.stringify({
+ query: `query ($projectId: String!, $limit: Int!, $search: String!, $page: Int!, $order: Int!, $orderDirection: Int!) {
+ project(id: $projectId) {
+ apiKeys(cursor: {limit: $limit, search: $search, page: $page, order: $order, orderDirection: $orderDirection}) {
+ apiKeys {
+ id
+ name
+ createdAt
+ }
+ search
+ limit
+ order
+ pageCount
+ currentPage
+ totalCount
+ __typename
+ }
+ __typename
+ }
+ }`,
+ variables: {
+ projectId,
+ limit,
+ search,
+ page,
+ order,
+ orderDirection
+ }
+ })
+ });
+
+ const {
+ data: {
+ project: {
+ apiKeys: { apiKeys, pageCount }
+ }
+ }
+ } = await response.json();
+
+ return { apiKeys, pageCount };
+}
+
+export async function deleteAccessKeys({ token, id }) {
+ const response = await fetch("/api/v0/graphql", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ Cookie: `_tokenKey=${token}`
+ },
+ body: JSON.stringify({
+ query: `mutation ($id: [String!]!) {
+ deleteAPIKeys(id: $id) {
+ id
+ __typename
+ }
+ }`,
+ variables: {
+ id
+ }
+ })
+ });
+
+ const {
+ data: { deleteAPIKeys }
+ } = await response.json();
+
+ return deleteAPIKeys;
+}
diff --git a/ui/src/router/index.js b/ui/src/router/index.js
index aab546f..b8d8e25 100644
--- a/ui/src/router/index.js
+++ b/ui/src/router/index.js
@@ -11,6 +11,7 @@ import Unlock from "../components/Unlock";
import Browse from "../components/Browse";
import Backup from "../components/Backup";
import Usage from "../components/Usage";
+import Access from "../components/Access";
import UpgradeForm from "../components/UpgradeForm";
const routes = [
@@ -43,6 +44,11 @@ const routes = [
path: "usage",
component: Usage
},
+ {
+ name: "access",
+ path: "access",
+ component: Access
+ },
{
name: "upgrade-form",
path: "usage/upgrade-form",
diff --git a/ui/src/store/access.js b/ui/src/store/access.js
new file mode 100644
index 0000000..233490f
--- /dev/null
+++ b/ui/src/store/access.js
@@ -0,0 +1,166 @@
+import { getAccessKeys, deleteAccessKeys } from "../lib/satellite";
+
+export default {
+ namespaced: true,
+ state: () => ({
+ accessKeys: [],
+ headingSorted: "name",
+ orderBy: "asc",
+ asc: 2,
+ desc: 1,
+ pageCount: 1,
+ nameHeadingOrder: 1,
+ dateCreatedHeadingOrder: 2,
+ openedDropdown: null,
+ accessCreationModal: null,
+ accessKeysBeingDeleted: [],
+ accessTableDropdown: null,
+ selectedAccessKeys: [],
+ satellite: {
+ limit: 10,
+ page: 1,
+ search: "",
+ order: 1,
+ orderDirection: 2
+ }
+ }),
+ getters: {},
+ mutations: {
+ setAccessKey(state, key) {
+ state.accessKeys = [...state.accessKeys, key];
+ },
+ updateAccessKeys(state, keys) {
+ state.accessKeys = keys;
+ },
+ setDropdown(state, id) {
+ state.openedDropdown = id;
+ },
+ setAccessTableDropdown(state, value) {
+ state.accessTableDropdown = value;
+ },
+ setHeadingSorted(state, heading) {
+ state.headingSorted = heading;
+ },
+ setOrderBy(state, order) {
+ state.orderBy = order;
+ },
+ setAccessCreationModal(state, value) {
+ state.accessCreationModal = value;
+ },
+ setAccessKeysBeingDeleted(state, keys) {
+ state.accessKeysBeingDeleted = [
+ ...state.accessKeysBeingDeleted,
+ ...keys
+ ];
+ },
+ removeAllAccessKeyBeingDeleted(state) {
+ state.accessKeysBeingDeleted = [];
+ },
+ setSelectedAccessKey(state, key) {
+ state.selectedAccessKeys = [...state.selectedAccessKeys, key];
+ },
+ removeSelectedAccessKey(state, key) {
+ state.selectedAccessKeys = state.selectedAccessKeys.filter(
+ (accessKey) => accessKey !== key
+ );
+ },
+ removeAllSelectedAccessKeys(state) {
+ state.selectedAccessKeys = [];
+ },
+ setPageCount(state, count) {
+ state.pageCount = count;
+ },
+ updateSatelliteRequestObject(state) {
+ if (state.headingSorted === "name") {
+ state.satellite.order = state.nameHeadingOrder;
+ } else {
+ state.satellite.order = state.dateCreatedHeadingOrder;
+ }
+
+ if (state.orderBy === "asc") {
+ state.satellite.orderDirection = state.asc;
+ } else {
+ state.satellite.orderDirection = state.desc;
+ }
+ }
+ },
+ actions: {
+ async list({ commit, state, rootState }) {
+ const { token, projectId } = rootState.account;
+ const { limit, search, page, order, orderDirection } =
+ state.satellite;
+
+ const data = await getAccessKeys({
+ token,
+ projectId,
+ limit,
+ search,
+ page,
+ order,
+ orderDirection
+ });
+ const { apiKeys, pageCount } = data;
+
+ commit("updateAccessKeys", apiKeys);
+ commit("setPageCount", pageCount);
+ },
+ async createAccessKey({ commit }, { key }) {
+ // create access key
+ // commit("setAccessKey", key);
+ },
+ async deleteAccessKeys({ commit, rootState, dispatch }, keyIDs) {
+ const { token } = rootState.account;
+
+ if (!Array.isArray(keyIDs)) {
+ keyIDs = [keyIDs];
+ }
+
+ commit("setAccessKeysBeingDeleted", keyIDs);
+ await deleteAccessKeys({ token, id: keyIDs });
+ commit("removeAllAccessKeyBeingDeleted");
+ dispatch("list");
+ },
+ addSelectedAccessKey({ commit }, key) {
+ commit("setSelectedAccessKey", key);
+ },
+ deleteSelectedAccessKey({ commit }, key) {
+ commit("removeSelectedAccessKey", key);
+ },
+ async deleteSelectedAccessKeys({ dispatch, commit, state }) {
+ dispatch("deleteAccessKeys", [...state.selectedAccessKeys]);
+ commit("removeAllSelectedAccessKeys");
+ },
+ openDropdown({ commit }, id) {
+ commit("setDropdown", id);
+ },
+ closeDropdown({ commit }) {
+ commit("setDropdown", null);
+ },
+ openAccessTableDropdown({ commit }) {
+ commit("setAccessTableDropdown", true);
+ },
+ closeAccessTableDropdown({ commit }) {
+ commit("setAccessTableDropdown", null);
+ },
+ sort({ commit, state, dispatch }, heading) {
+ const flip = (orderBy) => (orderBy === "asc" ? "desc" : "asc");
+
+ const order =
+ state.headingSorted === heading ? flip(state.orderBy) : "asc";
+
+ commit("setOrderBy", order);
+ commit("setHeadingSorted", heading);
+ commit("updateSatelliteRequestObject");
+ dispatch("list");
+ },
+ closeAllInteractions({ state, dispatch }) {
+ if (state.openedDropdown) {
+ dispatch("closeDropdown");
+ }
+
+ if (state.accessTableDropdown) {
+ dispatch("closeAccessTableDropdown");
+ }
+ }
+ }
+};
diff --git a/ui/src/store/index.js b/ui/src/store/index.js
index a7efa8c..d6ddf8c 100644
--- a/ui/src/store/index.js
+++ b/ui/src/store/index.js
@@ -3,6 +3,7 @@ import { createStore } from "vuex";
import account from "./account";
import gateway from "./gateway";
import buckets from "./buckets";
+import access from "./access";
import files from "../../browser/src/store/files";
export default createStore({
@@ -13,6 +14,7 @@ export default createStore({
account,
gateway,
buckets,
+ access,
files
}
});
diff --git a/ui/src/views/Dashboard.vue b/ui/src/views/Dashboard.vue
index 16630ef..fc32e5f 100644
--- a/ui/src/views/Dashboard.vue
+++ b/ui/src/views/Dashboard.vue
@@ -159,8 +159,11 @@
Backup
-
+
+
+
+
+
+
+