fix: teams edit modal + race conditions on currentUser
This commit is contained in:
@@ -33,7 +33,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul v-for="(member, index) in teamMembers" :key="`new-${index}`">
|
<ul v-for="(member, index) in members" :key="`new-${index}`">
|
||||||
<li>
|
<li>
|
||||||
<input
|
<input
|
||||||
:placeholder="$t('email')"
|
:placeholder="$t('email')"
|
||||||
@@ -84,7 +84,7 @@
|
|||||||
</li>
|
</li>
|
||||||
</div>
|
</div>
|
||||||
</ul>
|
</ul>
|
||||||
<ul v-for="(member, index) in members" :key="index">
|
<ul v-for="(member, index) in newMembers" :key="index">
|
||||||
<li>
|
<li>
|
||||||
<input
|
<input
|
||||||
:placeholder="$t('email')"
|
:placeholder="$t('email')"
|
||||||
@@ -164,122 +164,9 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import * as team_utils from "~/helpers/teams/utils"
|
import * as team_utils from "~/helpers/teams/utils"
|
||||||
import gql from "graphql-tag"
|
import cloneDeep from "lodash/cloneDeep"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
apollo: {
|
|
||||||
teamMembers: {
|
|
||||||
query: gql`
|
|
||||||
query GetMyTeams {
|
|
||||||
myTeams {
|
|
||||||
id
|
|
||||||
members {
|
|
||||||
user {
|
|
||||||
displayName
|
|
||||||
email
|
|
||||||
uid
|
|
||||||
}
|
|
||||||
role
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
subscribeToMore: [
|
|
||||||
{
|
|
||||||
document: gql`
|
|
||||||
subscription teamMemberAdded($teamID: String!) {
|
|
||||||
teamMemberAdded(teamID: $teamID) {
|
|
||||||
role
|
|
||||||
user {
|
|
||||||
displayName
|
|
||||||
email
|
|
||||||
uid
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
variables() {
|
|
||||||
return { teamID: this.$props.editingteamID }
|
|
||||||
},
|
|
||||||
skip() {
|
|
||||||
return this.$props.editingteamID === ""
|
|
||||||
},
|
|
||||||
updateQuery(previousResult, { subscriptionData }) {
|
|
||||||
const teamIdx = previousResult.myTeams.findIndex(
|
|
||||||
(x) => x.id === this.$props.editingteamID
|
|
||||||
)
|
|
||||||
previousResult.myTeams[teamIdx].members.push(subscriptionData.data.teamMemberAdded)
|
|
||||||
return previousResult
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
document: gql`
|
|
||||||
subscription teamMemberUpdated($teamID: String!) {
|
|
||||||
teamMemberUpdated(teamID: $teamID) {
|
|
||||||
role
|
|
||||||
user {
|
|
||||||
displayName
|
|
||||||
email
|
|
||||||
uid
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
variables() {
|
|
||||||
return { teamID: this.$props.editingteamID }
|
|
||||||
},
|
|
||||||
skip() {
|
|
||||||
return this.$props.editingteamID === ""
|
|
||||||
},
|
|
||||||
updateQuery(previousResult, { subscriptionData }) {
|
|
||||||
const teamIdx = previousResult.myTeams.findIndex(
|
|
||||||
(x) => x.id === this.$props.editingteamID
|
|
||||||
)
|
|
||||||
const memberIdx = previousResult.myTeams[teamIdx].members.findIndex(
|
|
||||||
(x) => x.user.uid === subscriptionData.data.teamMemberUpdated.user.uid
|
|
||||||
)
|
|
||||||
previousResult.myTeams[teamIdx].members[memberIdx].user =
|
|
||||||
subscriptionData.data.teamMemberUpdated.user
|
|
||||||
previousResult.myTeams[teamIdx].members[memberIdx].role =
|
|
||||||
subscriptionData.data.teamMemberUpdated.role
|
|
||||||
|
|
||||||
return previousResult
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
document: gql`
|
|
||||||
subscription teamMemberRemoved($teamID: String!) {
|
|
||||||
teamMemberRemoved(teamID: $teamID)
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
variables() {
|
|
||||||
return { teamID: this.$props.editingteamID }
|
|
||||||
},
|
|
||||||
skip() {
|
|
||||||
return this.$props.editingteamID === ""
|
|
||||||
},
|
|
||||||
updateQuery(previousResult, { subscriptionData }) {
|
|
||||||
const teamIdx = previousResult.myTeams.findIndex(
|
|
||||||
(x) => x.id === this.$props.editingteamID
|
|
||||||
)
|
|
||||||
const memberIdx = previousResult.myTeams[teamIdx].members.findIndex(
|
|
||||||
(x) => x.user.id === subscriptionData.data.teamMemberRemoved.id
|
|
||||||
)
|
|
||||||
if (memberIdx !== -1) previousResult.myTeams[teamIdx].members.splice(memberIdx, 1)
|
|
||||||
|
|
||||||
return previousResult
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
update(response) {
|
|
||||||
const teamIdx = response.myTeams.findIndex((x) => x.id === this.$props.editingteamID)
|
|
||||||
return response.myTeams[teamIdx].members
|
|
||||||
},
|
|
||||||
skip() {
|
|
||||||
return this.$props.editingteamID === ""
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
props: {
|
props: {
|
||||||
show: Boolean,
|
show: Boolean,
|
||||||
editingTeam: Object,
|
editingTeam: Object,
|
||||||
@@ -292,6 +179,7 @@ export default {
|
|||||||
members: [],
|
members: [],
|
||||||
membersSubject: null,
|
membersSubject: null,
|
||||||
membersSubscription: null,
|
membersSubscription: null,
|
||||||
|
newMembers: [],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@@ -301,7 +189,7 @@ export default {
|
|||||||
|
|
||||||
this.membersSubscription = this.membersSubject.subscribe((memberList) => {
|
this.membersSubscription = this.membersSubject.subscribe((memberList) => {
|
||||||
console.log(memberList)
|
console.log(memberList)
|
||||||
this.members = memberList
|
this.members = cloneDeep(memberList)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -321,11 +209,12 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateRole(id, role) {
|
updateRole(id, role) {
|
||||||
this.teamMembers[id].role = role
|
console.log(this.members, id)
|
||||||
|
this.members[id].role = role
|
||||||
},
|
},
|
||||||
addTeamMember() {
|
addTeamMember() {
|
||||||
let value = { key: "", value: "" }
|
let value = { key: "", value: "" }
|
||||||
this.members.push(value)
|
this.newMembers.push(value)
|
||||||
console.log("addTeamMember")
|
console.log("addTeamMember")
|
||||||
},
|
},
|
||||||
removeExistingTeamMember(userID) {
|
removeExistingTeamMember(userID) {
|
||||||
@@ -347,7 +236,7 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
removeTeamMember(index) {
|
removeTeamMember(index) {
|
||||||
this.members.splice(index, 1)
|
this.newMembers.splice(index, 1)
|
||||||
console.log("removeTeamMember")
|
console.log("removeTeamMember")
|
||||||
},
|
},
|
||||||
validateEmail(emailID) {
|
validateEmail(emailID) {
|
||||||
@@ -364,8 +253,7 @@ export default {
|
|||||||
console.log("String length less than 6")
|
console.log("String length less than 6")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
console.log("saveTeam", this.members)
|
this.$data.newMembers.forEach((element) => {
|
||||||
this.$data.members.forEach((element) => {
|
|
||||||
if (!this.validateEmail(element.key)) {
|
if (!this.validateEmail(element.key)) {
|
||||||
this.$toast.error(this.$t("invalid_emailID_format"), {
|
this.$toast.error(this.$t("invalid_emailID_format"), {
|
||||||
icon: "error",
|
icon: "error",
|
||||||
@@ -374,7 +262,7 @@ export default {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.$data.members.forEach((element) => {
|
this.$data.newMembers.forEach((element) => {
|
||||||
// Call to the graphql mutation
|
// Call to the graphql mutation
|
||||||
team_utils
|
team_utils
|
||||||
.addTeamMemberByEmail(this.$apollo, element.value, element.key, this.editingteamID)
|
.addTeamMemberByEmail(this.$apollo, element.value, element.key, this.editingteamID)
|
||||||
@@ -394,7 +282,7 @@ export default {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
let messageShown = true
|
let messageShown = true
|
||||||
this.teamMembers.forEach((element) => {
|
this.members.forEach((element) => {
|
||||||
team_utils
|
team_utils
|
||||||
.updateTeamMemberRole(this.$apollo, element.user.uid, element.role, this.editingteamID)
|
.updateTeamMemberRole(this.$apollo, element.user.uid, element.role, this.editingteamID)
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
@@ -444,7 +332,7 @@ export default {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.hideModal()
|
this.hideModal()
|
||||||
this.members = []
|
this.newMembers = []
|
||||||
},
|
},
|
||||||
hideModal() {
|
hideModal() {
|
||||||
this.$emit("hide-modal")
|
this.$emit("hide-modal")
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<button
|
<button
|
||||||
class="icon"
|
class="icon"
|
||||||
@click="team.myRole === 'OWNER' ? $emit('edit-team') : ''"
|
@click="team.myRole === 'OWNER' ? $emit('edit-team') : ''"
|
||||||
v-tooltip.right="$t('edit')"
|
v-tooltip.right="team.myRole === 'OWNER' ? $t('edit') : ''"
|
||||||
>
|
>
|
||||||
<i class="material-icons">group</i>
|
<i class="material-icons">group</i>
|
||||||
<span>{{ team.name }}</span>
|
<span>{{ team.name }}</span>
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<AppSection class="green" icon="history" :label="$t('teams')" ref="teams" no-legend>
|
<AppSection class="green" icon="history" :label="$t('teams')" ref="teams" no-legend>
|
||||||
<!-- debug start -->
|
|
||||||
<pre>me: {{ me }}</pre>
|
|
||||||
<pre>myTeams: {{ myTeams }}</pre>
|
|
||||||
<!-- debug end -->
|
|
||||||
<TeamsAdd :show="showModalAdd" @hide-modal="displayModalAdd(false)" />
|
<TeamsAdd :show="showModalAdd" @hide-modal="displayModalAdd(false)" />
|
||||||
<TeamsEdit
|
<TeamsEdit
|
||||||
:team="myTeams[0]"
|
:team="myTeams[0]"
|
||||||
@@ -12,11 +8,11 @@
|
|||||||
:editingteamID="editingteamID"
|
:editingteamID="editingteamID"
|
||||||
@hide-modal="displayModalEdit(false)"
|
@hide-modal="displayModalEdit(false)"
|
||||||
/>
|
/>
|
||||||
<TeamsImportExport
|
<!-- <TeamsImportExport
|
||||||
:show="showModalImportExport"
|
:show="showModalImportExport"
|
||||||
:teams="myTeams"
|
:teams="myTeams"
|
||||||
@hide-modal="displayModalImportExport(false)"
|
@hide-modal="displayModalImportExport(false)"
|
||||||
/>
|
/> -->
|
||||||
<div class="row-wrapper">
|
<div class="row-wrapper">
|
||||||
<div>
|
<div>
|
||||||
<button class="icon" @click="displayModalAdd(true)">
|
<button class="icon" @click="displayModalAdd(true)">
|
||||||
@@ -24,11 +20,11 @@
|
|||||||
<span>{{ $t("new") }}</span>
|
<span>{{ $t("new") }}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<!-- <div>
|
||||||
<button class="icon" @click="displayModalImportExport(true)">
|
<button class="icon" @click="displayModalImportExport(true)">
|
||||||
{{ $t("import_export") }}
|
{{ $t("import_export") }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
<p v-if="$apollo.queries.myTeams.loading" class="info">{{ $t("loading") }}</p>
|
<p v-if="$apollo.queries.myTeams.loading" class="info">{{ $t("loading") }}</p>
|
||||||
<p v-if="myTeams.length === 0" class="info">
|
<p v-if="myTeams.length === 0" class="info">
|
||||||
@@ -76,6 +72,7 @@ export default {
|
|||||||
query GetMe {
|
query GetMe {
|
||||||
me {
|
me {
|
||||||
uid
|
uid
|
||||||
|
eaInvited
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
|
|||||||
@@ -4,15 +4,27 @@ import { setContext } from "@apollo/client/link/context"
|
|||||||
import { fb } from "./fb"
|
import { fb } from "./fb"
|
||||||
import { getMainDefinition } from "@apollo/client/utilities"
|
import { getMainDefinition } from "@apollo/client/utilities"
|
||||||
|
|
||||||
|
let authToken: String | null = null
|
||||||
|
|
||||||
|
export function registerApolloAuthUpdate() {
|
||||||
|
fb.idToken$.subscribe((token: String | null) => {
|
||||||
|
console.log(token, "from sub")
|
||||||
|
|
||||||
|
authToken = token
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injects auth token if available
|
* Injects auth token if available
|
||||||
*/
|
*/
|
||||||
const authLink = setContext((_, { headers }) => {
|
const authLink = setContext((_, { headers }) => {
|
||||||
if (fb.idToken) {
|
console.log(authToken)
|
||||||
|
|
||||||
|
if (authToken) {
|
||||||
return {
|
return {
|
||||||
headers: {
|
headers: {
|
||||||
...headers,
|
...headers,
|
||||||
authorization: `Bearer ${fb.idToken}`,
|
authorization: `Bearer ${authToken}`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -38,11 +50,11 @@ const wsLink = new WebSocketLink({
|
|||||||
reconnect: true,
|
reconnect: true,
|
||||||
lazy: true,
|
lazy: true,
|
||||||
connectionParams: () => {
|
connectionParams: () => {
|
||||||
if (fb.idToken) {
|
if (authToken) {
|
||||||
return {}
|
return {}
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
authorization: `Bearer ${fb.idToken}`,
|
authorization: `Bearer ${authToken}`,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -42,12 +42,14 @@ export const currentUserInfo$ = new BehaviorSubject<UserInfo | null>(null)
|
|||||||
/**
|
/**
|
||||||
* Initializes the currenUserInfo$ view and sets up its update mechanism
|
* Initializes the currenUserInfo$ view and sets up its update mechanism
|
||||||
*/
|
*/
|
||||||
export function initUserInfo() {
|
export async function initUserInfo() {
|
||||||
updateUserInfo()
|
await updateUserInfo()
|
||||||
|
console.log("updated")
|
||||||
|
|
||||||
fb.idToken$.subscribe(token => {
|
fb.idToken$.subscribe((token) => {
|
||||||
if (token) {
|
if (token) {
|
||||||
updateUserInfo()
|
updateUserInfo()
|
||||||
|
console.log(token, "updateUserInfo")
|
||||||
} else {
|
} else {
|
||||||
currentUserInfo$.next(null)
|
currentUserInfo$.next(null)
|
||||||
}
|
}
|
||||||
@@ -63,22 +65,24 @@ async function updateUserInfo() {
|
|||||||
query: gql`
|
query: gql`
|
||||||
query GetUserInfo {
|
query GetUserInfo {
|
||||||
me {
|
me {
|
||||||
uid,
|
uid
|
||||||
displayName,
|
displayName
|
||||||
email,
|
email
|
||||||
photoURL,
|
photoURL
|
||||||
eaInvited
|
eaInvited
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
console.log(data)
|
||||||
|
|
||||||
currentUserInfo$.next({
|
currentUserInfo$.next({
|
||||||
uid: data.me.uid,
|
uid: data.me.uid,
|
||||||
displayName: data.me.displayName,
|
displayName: data.me.displayName,
|
||||||
email: data.me.email,
|
email: data.me.email,
|
||||||
photoURL : data.me.photoURL,
|
photoURL: data.me.photoURL,
|
||||||
eaInvited: data.me.eaInvited
|
eaInvited: data.me.eaInvited,
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
currentUserInfo$.next(null)
|
currentUserInfo$.next(null)
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ export async function getLiveTeamMembersList(apollo, teamID) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
debugger
|
|
||||||
subject.next(data.team.members)
|
subject.next(data.team.members)
|
||||||
|
|
||||||
const addedSub = apollo
|
const addedSub = apollo
|
||||||
@@ -53,6 +52,7 @@ export async function getLiveTeamMembersList(apollo, teamID) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
.subscribe(({ data }) => {
|
.subscribe(({ data }) => {
|
||||||
|
console.log(data)
|
||||||
subject.next([...subject.value, data.teamMemberAdded])
|
subject.next([...subject.value, data.teamMemberAdded])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -17,9 +17,12 @@
|
|||||||
import { setupLocalPersistence } from "~/newstore/localpersistence"
|
import { setupLocalPersistence } from "~/newstore/localpersistence"
|
||||||
import { performMigrations } from "~/helpers/migrations"
|
import { performMigrations } from "~/helpers/migrations"
|
||||||
import { initUserInfo } from "~/helpers/teams/BackendUserInfo"
|
import { initUserInfo } from "~/helpers/teams/BackendUserInfo"
|
||||||
|
import { registerApolloAuthUpdate } from "~/helpers/apollo"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
beforeMount() {
|
beforeMount() {
|
||||||
|
registerApolloAuthUpdate()
|
||||||
|
|
||||||
let color = localStorage.getItem("THEME_COLOR") || "green"
|
let color = localStorage.getItem("THEME_COLOR") || "green"
|
||||||
document.documentElement.setAttribute("data-accent", color)
|
document.documentElement.setAttribute("data-accent", color)
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="page">
|
<div class="page">
|
||||||
<div v-if="fb.currentUser">
|
<div v-if="currentUser && currentUser.eaInvited">
|
||||||
<Teams />
|
<Teams />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -202,6 +202,7 @@ import {
|
|||||||
defaultSettings,
|
defaultSettings,
|
||||||
} from "~/newstore/settings"
|
} from "~/newstore/settings"
|
||||||
import type { KeysMatching } from "~/types/ts-utils"
|
import type { KeysMatching } from "~/types/ts-utils"
|
||||||
|
import { currentUserInfo$ } from "~/helpers/teams/BackendUserInfo"
|
||||||
|
|
||||||
import Vue from "vue"
|
import Vue from "vue"
|
||||||
|
|
||||||
@@ -243,6 +244,9 @@ export default Vue.extend({
|
|||||||
SYNC_COLLECTIONS: getSettingSubject("syncCollections"),
|
SYNC_COLLECTIONS: getSettingSubject("syncCollections"),
|
||||||
SYNC_ENVIRONMENTS: getSettingSubject("syncEnvironments"),
|
SYNC_ENVIRONMENTS: getSettingSubject("syncEnvironments"),
|
||||||
SYNC_HISTORY: getSettingSubject("syncHistory"),
|
SYNC_HISTORY: getSettingSubject("syncHistory"),
|
||||||
|
|
||||||
|
// Teams feature flag
|
||||||
|
currentUser: currentUserInfo$,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
|||||||
Reference in New Issue
Block a user