Satellite api keys frontend (#1039)

* api keys frontend

* fix linter

* fixes, copy to clipboard, disable account activation

* activation is removed in https://github.com/storj/storj/pull/1143
This commit is contained in:
Yaroslav Vorobiov 2019-02-01 18:19:30 +02:00 committed by GitHub
parent 7a85c5c1c6
commit ba07f337c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 388 additions and 69 deletions

3
package-lock.json generated Normal file
View File

@ -0,0 +1,3 @@
{
"lockfileVersion": 1
}

View File

@ -82,7 +82,6 @@ func (s *Service) CreateUser(ctx context.Context, user CreateUser) (u *User, err
})
// TODO: send "finish registration email" when email service will be ready
//activationToken, err := s.GenerateActivationToken(ctx, u.ID, email, u.CreatedAt.Add(tokenExpirationTime))
return u, err

View File

@ -21,6 +21,7 @@
"vue": "^2.5.17",
"vue-apollo": "^3.0.0-beta.25",
"vue-class-component": "^6.0.0",
"vue-clipboards": "^1.2.4",
"vue-property-decorator": "^7.0.0",
"vue-router": "^3.0.1",
"vuex": "^3.0.1"

View File

@ -31,6 +31,10 @@ import { APP_STATE_ACTIONS } from '@/utils/constants/actionNames';
'addTeamMemberPopupButton',
'addTeamMemberPopup',
'addTeamMemberPopupButtonSVG',
'addApiKeyPopup',
'addApiKeyPopupButton',
'addApiKeysPopupEmptyButton',
'addTeamMemberPopupButtonSVG',
'sortTeamMemberByDropdown',
'sortTeamMemberByDropdownButton',
]

View File

@ -0,0 +1,119 @@
// Copyright (C) 2018 Storj Labs, Inc.
// See LICENSE for copying information.
import apollo from '@/utils/apolloManager';
import gql from 'graphql-tag';
export async function fetchAPIKeys(projectID: string) {
let result: RequestResponse<any[]> = {
errorMessage: '',
isSuccess: false,
data: []
};
try {
let response: any = await apollo.query({
query: gql(
`query {
project(
id: "${projectID}",
) {
apiKeys {
id,
name,
createdAt
}
}
}`
),
fetchPolicy: 'no-cache'
});
if (response.errors) {
result.errorMessage = response.errors[0].message;
} else {
result.isSuccess = true;
result.data = response.data.project.apiKeys;
}
} catch (e) {
result.errorMessage = e.message;
}
return result;
}
export async function createAPIKey(projectID: string, name: string) {
let result: RequestResponse<any> = {
errorMessage: '',
isSuccess: false,
data: null
};
try {
let response: any = await apollo.mutate({
mutation: gql(
`mutation {
createAPIKey(
projectID: "${projectID}",
name: "${name}"
) {
key,
keyInfo {
id,
name,
createdAt
}
}
}`
),
fetchPolicy: 'no-cache'
});
if (response.errors) {
result.errorMessage = response.errors[0].message;
} else {
console.log('response', response)
result.isSuccess = true;
result.data = {
key: response.data.createAPIKey.key,
keyInfo: response.data.createAPIKey.keyInfo
}
}
} catch (e) {
result.errorMessage = e.message;
}
return result;
}
export async function deleteAPIKey(id: string) {
let result: RequestResponse<any> = {
errorMessage: '',
isSuccess: false,
data: null
};
try {
let response: any = await apollo.mutate({
mutation: gql(
`mutation {
deleteAPIKey(id: "${id}") {
id
}
}`
),
fetchPolicy: 'no-cache'
});
if (response.errors) {
result.errorMessage = response.errors[0].message;
} else {
result.isSuccess = true;
result.data = response.data.deleteAPIKey;
}
} catch (e) {
result.errorMessage = e.message;
}
return result;
}

View File

@ -3,13 +3,14 @@
<template>
<div class="add-api-key-popup-container">
<div v-if="true" class="add-api-key-popup">
<div id="addApiKeyPopup" v-if="!key" class="add-api-key-popup">
<div class="add-api-key-popup__info-panel-container">
<div v-html="imageSource"></div>
</div>
<div class="add-api-key-popup__form-container">
<h2 class="add-api-key-popup__form-container__main-label-text">New API Key</h2>
<HeaderedInput
<HeaderedInput
@setData="onChangeName"
label="Name"
additionalLabel="Up To 20 Characters"
placeholder="Enter API Key Name"
@ -17,25 +18,29 @@
width="100%" />
<div class="add-api-key-popup__form-container__button-container">
<Button label="Cancel" width="205px" height="48px" :onPress="onCloseClick" isWhite />
<Button label="Create API Key" width="205px" height="48px" />
<Button label="Create API Key" width="205px" height="48px" :onPress="onCreateClick" />
</div>
</div>
<div class="add-api-key-popup__close-cross-container">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" v-on:click="onCloseClick">
<div class="add-api-key-popup__close-cross-container" v-on:click="onCloseClick">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15.7071 1.70711C16.0976 1.31658 16.0976 0.683417 15.7071 0.292893C15.3166 -0.0976311 14.6834 -0.0976311 14.2929 0.292893L15.7071 1.70711ZM0.292893 14.2929C-0.0976311 14.6834 -0.0976311 15.3166 0.292893 15.7071C0.683417 16.0976 1.31658 16.0976 1.70711 15.7071L0.292893 14.2929ZM1.70711 0.292893C1.31658 -0.0976311 0.683417 -0.0976311 0.292893 0.292893C-0.0976311 0.683417 -0.0976311 1.31658 0.292893 1.70711L1.70711 0.292893ZM14.2929 15.7071C14.6834 16.0976 15.3166 16.0976 15.7071 15.7071C16.0976 15.3166 16.0976 14.6834 15.7071 14.2929L14.2929 15.7071ZM14.2929 0.292893L0.292893 14.2929L1.70711 15.7071L15.7071 1.70711L14.2929 0.292893ZM0.292893 1.70711L14.2929 15.7071L15.7071 14.2929L1.70711 0.292893L0.292893 1.70711Z" fill="#384B65"/>
</svg>
</div>
</div>
<CopyApiKeyPopup v-if="false" />
<CopyApiKeyPopup :apiKey="key" v-if="key" />
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import VueClipboards from 'vue-clipboards';
import HeaderedInput from '@/components/common/HeaderedInput.vue';
import CopyApiKeyPopup from './CopyApiKeyPopup.vue';
import Button from '@/components/common/Button.vue';
import { EMPTY_STATE_IMAGES } from '@/utils/constants/emptyStatesImages';
import { APP_STATE_ACTIONS, NOTIFICATION_ACTIONS, API_KEYS_ACTIONS } from "@/utils/constants/actionNames";
Vue.use(VueClipboards);
@Component(
{
@ -47,12 +52,27 @@ import { EMPTY_STATE_IMAGES } from '@/utils/constants/emptyStatesImages';
data: function () {
return {
imageSource: EMPTY_STATE_IMAGES.ADD_API_KEY,
name: '',
key: '',
};
},
methods: {
onCloseClick: function (): void {
// TODO: save popup states in store
this.$emit('onClose');
this.$store.dispatch(APP_STATE_ACTIONS.TOGGLE_NEW_API_KEY);
},
onCreateClick: async function (): Promise<any> {
let result: any = await this.$store.dispatch(API_KEYS_ACTIONS.CREATE, this.$data.name);
if (!result.isSuccess) {
this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, result.errorMessage);
return;
}
this.$store.dispatch(NOTIFICATION_ACTIONS.SUCCESS, "Successfully created new api key");
this.$data.key = result.data.key;
},
onChangeName: function (value: string): void {
this.$data.name = value;
},
},
components: {

View File

@ -3,24 +3,28 @@
<template>
<div>
<div v-if="apiKeyItems" class="api-keys-header">
<div v-if="!isEmpty" class="api-keys-header">
<HeaderArea/>
</div>
<div v-if="apiKeyItems" class="api-keys-container">
<div v-if="!isEmpty" class="api-keys-container">
<div class="api-keys-container__content">
<ApiKeysItem class="selected"/>
<ApiKeysItem />
<ApiKeysItem />
<div v-for="apiKey in apiKeys" v-on:click="toggleSelection(apiKey.id)">
<ApiKeysItem
v-bind:class="[apiKey.isSelected ? 'selected': null]"
:apiKey="apiKey" />
</div>
</div>
<Footer/>
<Footer v-if="isSelected"/>
</div>
<EmptyState
v-if="!apiKeyItems"
:onButtonClick="togglePopup"
v-if="isEmpty"
mainTitle="You have no API Keys yet"
additional-text="<p>We recommend you to create your first API Key for this project. API Keys allow developers to manage their project and build applications over Storj Network through our Uplink CLI.</p>"
:imageSource="emptyImage"
buttonLabel="New Api Key"
isButtonShown />
<AddAPIKeyPopup v-if="isPopupShown"/>
</div>
</template>
@ -30,23 +34,45 @@ import EmptyState from '@/components/common/EmptyStateArea.vue';
import HeaderArea from '@/components/apiKeys/headerArea/HeaderArea.vue';
import { EMPTY_STATE_IMAGES } from '@/utils/constants/emptyStatesImages';
import ApiKeysItem from '@/components/apiKeys/ApiKeysItem.vue';
import AddAPIKeyPopup from '@/components/apiKeys/AddApiKeyPopup.vue';
import Footer from '@/components/apiKeys/footerArea/Footer.vue';
import { API_KEYS_ACTIONS, APP_STATE_ACTIONS } from "@/utils/constants/actionNames";
@Component({
data: function () {
return {
emptyImage: EMPTY_STATE_IMAGES.API_KEY,
apiKeyItems: true,
};
},
methods: {},
computed: {},
methods: {
toggleSelection: function(id: string): void {
this.$store.dispatch(API_KEYS_ACTIONS.TOGGLE_SELECTION, id);
},
togglePopup: function (): void {
this.$store.dispatch(APP_STATE_ACTIONS.TOGGLE_NEW_API_KEY);
},
},
computed: {
apiKeys: function (): any {
return this.$store.state.apiKeysModule.apiKeys;
},
isEmpty: function (): boolean {
return this.$store.state.apiKeysModule.apiKeys.length === 0;
},
isSelected: function (): boolean {
return this.$store.getters.selectedAPIKeys.length > 0;
},
isPopupShown: function (): boolean {
return this.$store.state.appStateModule.appState.isNewAPIKeyPopupShown;
}
},
components: {
EmptyState,
HeaderArea,
ApiKeysItem,
AddAPIKeyPopup,
Footer
}
},
})
export default class ApiKeysArea extends Vue {

View File

@ -11,8 +11,8 @@
<path d="M10.7756 14.334C10.4108 14.334 10.1226 14.6283 10.1226 15.0007C10.1226 15.3731 10.4108 15.6673 10.7756 15.6673C11.1404 15.6673 11.4287 15.3731 11.4287 15.0007C11.4287 14.6283 11.1404 14.334 10.7756 14.334Z" fill="#2683FF"/>
</svg>
</div>
<p class="apikey-item-container__name">test</p>
<p class="apikey-item-container__date">date</p>
<p class="apikey-item-container__name">{{ apiKey.name }}</p>
<p class="apikey-item-container__date">{{ new Date(apiKey.createdAt).toLocaleDateString() }}</p>
</div>
</template>
@ -21,7 +21,9 @@ import { Component, Vue } from 'vue-property-decorator';
@Component(
{
props: {
apiKey: Object,
}
}
)
export default class ApiKeysItem extends Vue {}

View File

@ -2,15 +2,15 @@
// See LICENSE for copying information.
<template>
<div>
<div id="addApiKeyPopup">
<div class="save-api-popup" v-if="true">
<div class="save-api-popup__content">
<h1 class="save-api-popup__content__title">Save you API Key or download it in .txt file.</h1>
<p class="save-api-popup__content__name">You will need this to share access to the project with your team members.</p>
<div class="save-api-popup__content__copy-area">
<p class="save-api-popup__content__copy-area__save-api">ab4923re124NSVDLkvdmsfv mwm45678gnhab4923rewm45678gn</p>
<Button class="save-api-popup__content__copy-area__save-btn" label="Copy" width="140px" height="48px" />
<Button label="Download" width="140px" height="48px" isWhite/>
<p class="save-api-popup__content__copy-area__save-api">{{apiKey}}</p>
<Button class="save-api-popup__content__copy-area__save-btn" v-clipboard="apiKey" label="Copy" width="140px" height="48px" :onPress="onCopyClick" />
<!--<Button label="Download" width="140px" height="48px" isWhite/>-->
</div>
<div class="save-api-popup__content__info-area">
<img src="../../../static/images/register/ErrorInfo.svg"/>
@ -54,6 +54,7 @@ import { Component, Vue } from 'vue-property-decorator';
import Button from '@/components/common/Button.vue';
import HeaderedInput from '@/components/common/HeaderedInput.vue';
import { EMPTY_STATE_IMAGES } from '@/utils/constants/emptyStatesImages';
import { APP_STATE_ACTIONS, NOTIFICATION_ACTIONS } from "@/utils/constants/actionNames";
@Component(
{
@ -61,6 +62,7 @@ import { EMPTY_STATE_IMAGES } from '@/utils/constants/emptyStatesImages';
onClose: {
type: Function
},
apiKey: String
},
data: function () {
return {
@ -69,9 +71,12 @@ import { EMPTY_STATE_IMAGES } from '@/utils/constants/emptyStatesImages';
},
methods: {
onCloseClick: function (): void {
// TODO: save popup states in store
this.$emit('onClose');
this.$store.dispatch(APP_STATE_ACTIONS.TOGGLE_NEW_API_KEY);
},
onCopyClick: function (): void {
//TODO: save to clipboardt
this.$store.dispatch(NOTIFICATION_ACTIONS.SUCCESS, "Key saved to clipboard");
}
},
components: {
Button,

View File

@ -6,7 +6,7 @@
<div class="delete-api-key-container__wrap">
<div class="delete-api-key-container__selected-api-keys-count">
<span class="delete-api-key-container__selected-api-keys-count__button"></span>
<p class="delete-api-key-container__selected-api-keys-count__count">1</p>
<p class="delete-api-key-container__selected-api-keys-count__count">{{ count }}</p>
<p class="delete-api-key-container__selected-api-keys-count__total-count"> of <span>X</span> API Keys Selected</p>
</div>
<div class="delete-api-key-container__buttons-group">
@ -30,19 +30,25 @@
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import Button from '@/components/common/Button.vue';
import { API_KEYS_ACTIONS } from "@/utils/constants/actionNames";
@Component({
methods: {
onDelete: async function () {
let selectedKeys: any[] = this.$store.getters.selectedAPIKeys;
for (let i = 0; i < selectedKeys.length; i++) {
this.$store.dispatch(API_KEYS_ACTIONS.DELETE, selectedKeys[i].id);
}
},
onClearSelection: function (): void {
this.$store.dispatch(API_KEYS_ACTIONS.CLEAR_SELECTION);
},
onClearSelection: function () {
}
},
computed: {
count: function (): number {
return this.$store.getters.selectedAPIKeys.length;
}
},
components: {
Button

View File

@ -5,12 +5,13 @@
<div class="api-keys-header-container">
<div class="api-keys-header-container__item">
<SearchArea />
<Button label="New API Key" width="240px" height="54px" :onPress="toggleSelection" />
<div id="addApiKeyPopupButton">
<Button label="New API Key" width="240px" height="54px" :onPress="togglePopup" />
</div>
</div>
<div class="api-keys-header-container__item">
<!-- <SortApiKeysHeader /> -->
</div>
<AddApiKeyPopup v-if="isPopupShown" @onClose="toggleSelection" />
</div>
</template>
@ -19,25 +20,19 @@ import { Component, Vue } from 'vue-property-decorator';
import SearchArea from './SearchArea.vue';
import Button from '@/components/common/Button.vue';
import SortApiKeysHeader from '@/components/apiKeys/headerArea/SortApiKeysHeader.vue';
import AddApiKeyPopup from '@/components/apiKeys/AddApiKeyPopup.vue';
import { APP_STATE_ACTIONS } from "@/utils/constants/actionNames";
@Component({
data: function() {
return {
isPopupShown: false,
};
},
components: {
SearchArea,
Button,
SortApiKeysHeader,
AddApiKeyPopup,
},
methods: {
toggleSelection: function () {
this.$data.isPopupShown = !this.$data.isPopupShown;
}
}
togglePopup: function () {
this.$store.dispatch(APP_STATE_ACTIONS.TOGGLE_NEW_API_KEY);
},
},
})
export default class HeaderArea extends Vue {

View File

@ -5,13 +5,14 @@
<div class="empty-state">
<div class="empty-state__wrap">
<h1>{{mainTitle}}</h1>
<!--<p>{{additionalText}}</p>-->
<div class="empty-state__wrap__additional-text" v-html="additionalText"/>
<Button
v-if="isButtonShown"
@onPress="onButtonClick"
:label="buttonLabel"
width="170px" />
<div id="addApiKeysPopupEmptyButton">
<Button
v-if="isButtonShown"
:onPress="onButtonClick"
:label="buttonLabel"
width="170px" />
</div>
<div class="empty-state__wrap__img" v-html="imageSource"></div>
</div>
</div>
@ -59,6 +60,8 @@ export default class EmptyStateProjectArea extends Vue {
&__additional-text {
font-family: 'montserrat_regular';
font-size: 16px;
width: 50%;
margin-bottom: 10px;
b {
font-family: 'montserrat_bold' !important;

View File

@ -20,7 +20,7 @@
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import { APP_STATE_ACTIONS, PROJETS_ACTIONS, NOTIFICATION_ACTIONS, PM_ACTIONS } from '@/utils/constants/actionNames';
import { APP_STATE_ACTIONS, PROJETS_ACTIONS, NOTIFICATION_ACTIONS, PM_ACTIONS, API_KEYS_ACTIONS } from '@/utils/constants/actionNames';
@Component(
{
@ -33,15 +33,18 @@ import { APP_STATE_ACTIONS, PROJETS_ACTIONS, NOTIFICATION_ACTIONS, PM_ACTIONS }
onProjectSelected: async function (projectID: string): Promise<void> {
this.$store.dispatch(PROJETS_ACTIONS.SELECT, projectID);
this.$store.dispatch(APP_STATE_ACTIONS.TOGGLE_PROJECTS);
if (!this.$store.getters.selectedProject.id) return;
this.$store.dispatch(PM_ACTIONS.SET_SEARCH_QUERY, '');
const response = await this.$store.dispatch(PM_ACTIONS.FETCH);
if (response.isSuccess) return;
const pmResponse = await this.$store.dispatch(PM_ACTIONS.FETCH, {limit: 20, offset: 0});
const keysResponse = await this.$store.dispatch(API_KEYS_ACTIONS.FETCH);
this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, 'Unable to fetch project members');
if (!pmResponse.isSuccess) {
this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, 'Unable to fetch project members');
}
if (!keysResponse.isSuccess) {
this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, 'Unable to fetch api keys');
}
}
},
}

View File

@ -10,6 +10,7 @@ import { projectsModule } from '@/store/modules/projects';
import { projectMembersModule } from '@/store/modules/projectMembers';
import { notificationsModule } from '@/store/modules/notifications';
import { appStateModule } from '@/store/modules/appState';
import { apiKeysModule } from '@/store/modules/apiKeys';
Vue.use(Vuex);
@ -21,6 +22,7 @@ const store = new Vuex.Store({
projectMembersModule,
notificationsModule,
appStateModule,
apiKeysModule
}
});

View File

@ -0,0 +1,98 @@
// Copyright (C) 2018 Storj Labs, Inc.
// See LICENSE for copying information.
import { API_KEYS_MUTATIONS } from '../mutationConstants';
import { createAPIKey, deleteAPIKey, fetchAPIKeys } from "@/api/apiKeys";
import { API_KEYS_ACTIONS } from "@/utils/constants/actionNames";
export const apiKeysModule = {
state: {
apiKeys: [],
},
mutations: {
[API_KEYS_MUTATIONS.FETCH](state: any, apiKeys: any[]) {
state.apiKeys = apiKeys;
},
[API_KEYS_MUTATIONS.ADD](state: any, apiKey: any) {
state.apiKeys.push(apiKey);
},
[API_KEYS_MUTATIONS.DELETE](state: any, id: string) {
state.apiKeys = state.apiKeys.filter((key => key.id !== id))
},
[API_KEYS_MUTATIONS.TOGGLE_SELECTION](state: any, apiKeyID: string) {
state.apiKeys = state.apiKeys.map((apiKey: any) => {
if (apiKey.id === apiKeyID) {
apiKey.isSelected = !apiKey.isSelected;
}
return apiKey;
});
},
[API_KEYS_MUTATIONS.CLEAR_SELECTION](state: any) {
state.apiKeys = state.apiKeys.map((apiKey: any) => {
apiKey.isSelected = false;
return apiKey;
});
},
},
actions: {
[API_KEYS_ACTIONS.FETCH]: async function ({commit, rootGetters}): Promise<RequestResponse<any>> {
const projectId = rootGetters.selectedProject.id;
let fetchResult = await fetchAPIKeys(projectId);
if (fetchResult.isSuccess) {
commit(API_KEYS_MUTATIONS.FETCH, fetchResult.data);
}
return fetchResult;
},
[API_KEYS_ACTIONS.CREATE]: async function ({commit, rootGetters}: any, name: string): Promise<RequestResponse<any>> {
const projectId = rootGetters.selectedProject.id;
let result = await createAPIKey(projectId, name);
console.log(result);
if (result.isSuccess) {
commit(API_KEYS_MUTATIONS.ADD, result.data.keyInfo);
}
return result;
},
[API_KEYS_ACTIONS.DELETE]: async function({commit}: any, id: string): Promise<RequestResponse<any>> {
let result = await deleteAPIKey(id);
if (result.isSuccess) {
commit(API_KEYS_MUTATIONS.DELETE, result.data.id);
}
console.log(result);
return result;
},
[API_KEYS_ACTIONS.TOGGLE_SELECTION]: function({commit}, apiKeyID: string): void {
commit(API_KEYS_MUTATIONS.TOGGLE_SELECTION, apiKeyID);
},
[API_KEYS_ACTIONS.CLEAR_SELECTION]: function({commit}): void {
commit(API_KEYS_MUTATIONS.CLEAR_SELECTION);
},
[API_KEYS_ACTIONS.CLEAR]: function ({commit}): void {
commit(API_KEYS_MUTATIONS.FETCH, []);
},
},
getters: {
selectedAPIKeys: function (state: any): any[] {
let keys: any[] = state.apiKeys;
let selectedKeys: any[] = [];
for (let i = 0; i < keys.length; i++ ) {
if (keys[i].isSelected) {
selectedKeys.push(keys[i]);
}
}
return selectedKeys;
}
},
};

View File

@ -2,6 +2,7 @@
// See LICENSE for copying information.
import { APP_STATE_MUTATIONS } from '../mutationConstants';
import {APP_STATE_ACTIONS} from "@/utils/constants/actionNames";
export const appStateModule = {
state: {
@ -13,6 +14,7 @@ export const appStateModule = {
isAccountDropdownShown: false,
isDeleteProjectPopupShown: false,
isDeleteAccountPopupShown: false,
isNewAPIKeyPopupShown: false,
isSortProjectMembersByPopupShown: false,
},
},
@ -41,7 +43,6 @@ export const appStateModule = {
[APP_STATE_MUTATIONS.TOGGLE_DELETE_PROJECT_DROPDOWN](state: any): void {
state.appState.isDeleteProjectPopupShown = !state.appState.isDeleteProjectPopupShown;
},
// Mutation changing delete account popup visibility
[APP_STATE_MUTATIONS.TOGGLE_DELETE_ACCOUNT_DROPDOWN](state: any): void {
state.appState.isDeleteAccountPopupShown = !state.appState.isDeleteAccountPopupShown;
@ -50,6 +51,10 @@ export const appStateModule = {
[APP_STATE_MUTATIONS.TOGGLE_SORT_PM_BY_DROPDOWN](state: any): void {
state.appState.isSortProjectMembersByPopupShown = !state.appState.isSortProjectMembersByPopupShown;
},
// Mutation changing new api key popup visibility
[APP_STATE_MUTATIONS.TOGGLE_NEW_API_KEY_POPUP](state: any): void {
state.appState.isNewAPIKeyPopupShown = !state.appState.isNewAPIKeyPopupShown;
},
// Mutation that closes each popup/dropdown
[APP_STATE_MUTATIONS.CLOSE_ALL](state: any): void {
@ -60,6 +65,7 @@ export const appStateModule = {
state.appState.isDeleteProjectPopupShown = false;
state.appState.isDeleteAccountPopupShown = false;
state.appState.isSortProjectMembersByPopupShown = false;
state.appState.isNewAPIKeyPopupShown = false;
},
},
actions: {
@ -113,6 +119,13 @@ export const appStateModule = {
commit(APP_STATE_MUTATIONS.TOGGLE_SORT_PM_BY_DROPDOWN);
},
[APP_STATE_ACTIONS.TOGGLE_NEW_API_KEY]: function ({commit, state}: any): void {
if (!state.appState.isNewAPIKeyPopupShown) {
commit(APP_STATE_MUTATIONS.CLOSE_ALL);
}
commit(APP_STATE_MUTATIONS.TOGGLE_NEW_API_KEY_POPUP);
},
closePopups: function ({commit}: any): void {
commit(APP_STATE_MUTATIONS.CLOSE_ALL);
},

View File

@ -30,6 +30,15 @@ export const PROJECT_MEMBER_MUTATIONS = {
ADD_OFFSET:'ADD_OFFSET',
};
export const API_KEYS_MUTATIONS = {
FETCH: 'FETCH_API_KEYS',
ADD: 'ADD_API_KEY',
DELETE: 'DELETE_API_KEY',
TOGGLE_SELECTION: "TOGGLE_SELECTION",
CLEAR_SELECTION: "CLEAR_SELECTION",
CLEAR: 'CLEAR_API_KEYS',
}
export const NOTIFICATION_MUTATIONS = {
ADD: 'ADD_NOTIFICATION',
DELETE: 'DELETE_NOTIFICATION',
@ -45,5 +54,6 @@ export const APP_STATE_MUTATIONS = {
TOGGLE_DELETE_PROJECT_DROPDOWN: 'TOGGLE_DELETE_PROJECT_DROPDOWN',
TOGGLE_DELETE_ACCOUNT_DROPDOWN: 'TOGGLE_DELETE_ACCOUNT_DROPDOWN',
TOGGLE_SORT_PM_BY_DROPDOWN: 'TOGGLE_SORT_PM_BY_DROPDOWN',
TOGGLE_NEW_API_KEY_POPUP: "TOGGLE_NEW_API_KEY_POPUP",
CLOSE_ALL: 'CLOSE_ALL',
};

View File

@ -2,12 +2,13 @@
// See LICENSE for copying information.
export const APP_STATE_ACTIONS = {
TOGGLE_TEAM_MEMBERS: 'toggleAddTeamMembersPopup',
TOGGLE_NEW_PROJ: 'toggleNewProjectPopup',
TOGGLE_PROJECTS: 'toggleProjectsDropdown',
TOGGLE_ACCOUNT: 'toggleAccountDropdown',
TOGGLE_DEL_PROJ: 'toggleDeleteProjectPopup',
TOGGLE_DEL_ACCOUNT: 'toggleDeleteAccountPopup',
TOGGLE_TEAM_MEMBERS: 'toggleAddTeamMembersPopup',
TOGGLE_NEW_PROJ : 'toggleNewProjectPopup',
TOGGLE_PROJECTS: 'toggleProjectsDropdown',
TOGGLE_ACCOUNT: 'toggleAccountDropdown',
TOGGLE_DEL_PROJ: 'toggleDeleteProjectPopup',
TOGGLE_DEL_ACCOUNT: 'toggleDeleteAccountPopup',
TOGGLE_NEW_API_KEY: "toggleNewAPIKeyPopup",
TOGGLE_SORT_PM_BY_DROPDOWN: 'toggleSortProjectMembersByPopup',
CLOSE_POPUPS: 'closePopups',
};
@ -49,3 +50,12 @@ export const USER_ACTIONS = {
GET: 'getUser',
CLEAR: 'clearUser',
};
export const API_KEYS_ACTIONS = {
FETCH: 'fetchAPIKeys',
CREATE: 'createAPIKey',
DELETE: 'deleteAPIKey',
CLEAR: 'clearAPIKeys',
TOGGLE_SELECTION: 'toggleAPIKeySelection',
CLEAR_SELECTION: 'clearAPIKeySelection'
};