refactor(frontend): replace for...in usages and forbid via lint rule
Replaces 33 for...in loops across 18 files with for...of + Object.keys/entries or indexed for loops. for...in iterates enumerable string keys including inherited ones, which is especially risky on reactive arrays (tasks, labels, assignees, etc.) where polyfilled properties may appear. Loops that mutate via splice during iteration now iterate backwards to avoid index-shift bugs. Adds a no-restricted-syntax ESLint rule forbidding ForInStatement to prevent regressions. Closes #513
This commit is contained in:
parent
95180a341d
commit
2c6029eac4
|
|
@ -112,6 +112,11 @@ export default [
|
||||||
|
|
||||||
'depend/ban-dependencies': 'warn',
|
'depend/ban-dependencies': 'warn',
|
||||||
|
|
||||||
|
'no-restricted-syntax': ['error', {
|
||||||
|
selector: 'ForInStatement',
|
||||||
|
message: 'Use for...of with Object.keys/entries, or .forEach, instead of for...in. See https://github.com/go-vikunja/vikunja/issues/513',
|
||||||
|
}],
|
||||||
|
|
||||||
'@typescript-eslint/no-unused-vars': [
|
'@typescript-eslint/no-unused-vars': [
|
||||||
'error',
|
'error',
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -448,7 +448,7 @@ function createOrSelectOnEnter() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function remove(item: T) {
|
function remove(item: T) {
|
||||||
for (const ind in internalValue.value) {
|
for (let ind = 0; ind < internalValue.value.length; ind++) {
|
||||||
if (internalValue.value[ind] === item) {
|
if (internalValue.value[ind] === item) {
|
||||||
internalValue.value.splice(ind, 1)
|
internalValue.value.splice(ind, 1)
|
||||||
break
|
break
|
||||||
|
|
|
||||||
|
|
@ -235,7 +235,7 @@ function updateTasks(updatedTask: ITask) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const t in tasks.value) {
|
for (let t = 0; t < tasks.value.length; t++) {
|
||||||
if (tasks.value[t].id === updatedTask.id) {
|
if (tasks.value[t].id === updatedTask.id) {
|
||||||
tasks.value[t] = updatedTask
|
tasks.value[t] = updatedTask
|
||||||
break
|
break
|
||||||
|
|
|
||||||
|
|
@ -291,7 +291,7 @@ async function deleteSharable() {
|
||||||
|
|
||||||
await stuffService.delete(stuffModel)
|
await stuffService.delete(stuffModel)
|
||||||
showDeleteModal.value = false
|
showDeleteModal.value = false
|
||||||
for (const i in sharables.value) {
|
for (let i = sharables.value.length - 1; i >= 0; i--) {
|
||||||
if (
|
if (
|
||||||
(sharables.value[i].username === stuffModel.username && props.shareType === 'user') ||
|
(sharables.value[i].username === stuffModel.username && props.shareType === 'user') ||
|
||||||
(sharables.value[i].id === stuffModel.teamId && props.shareType === 'team')
|
(sharables.value[i].id === stuffModel.teamId && props.shareType === 'team')
|
||||||
|
|
@ -344,15 +344,15 @@ async function toggleType(sharable) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const r = await stuffService.update(stuffModel)
|
const r = await stuffService.update(stuffModel)
|
||||||
for (const i in sharables.value) {
|
for (const sharableEntry of sharables.value) {
|
||||||
if (
|
if (
|
||||||
(sharables.value[i].username ===
|
(sharableEntry.username ===
|
||||||
stuffModel.username &&
|
stuffModel.username &&
|
||||||
props.shareType === 'user') ||
|
props.shareType === 'user') ||
|
||||||
(sharables.value[i].id === stuffModel.teamId &&
|
(sharableEntry.id === stuffModel.teamId &&
|
||||||
props.shareType === 'team')
|
props.shareType === 'team')
|
||||||
) {
|
) {
|
||||||
sharables.value[i].permission = r.permission
|
sharableEntry.permission = r.permission
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
success({message: t('project.share.userTeam.updatedSuccess', {type: shareTypeName.value})})
|
success({message: t('project.share.userTeam.updatedSuccess', {type: shareTypeName.value})})
|
||||||
|
|
|
||||||
|
|
@ -478,7 +478,7 @@ async function editComment() {
|
||||||
commentEdit.taskId = props.taskId
|
commentEdit.taskId = props.taskId
|
||||||
try {
|
try {
|
||||||
const comment = await taskCommentService.update(commentEdit)
|
const comment = await taskCommentService.update(commentEdit)
|
||||||
for (const c in comments.value) {
|
for (let c = 0; c < comments.value.length; c++) {
|
||||||
if (comments.value[c].id === commentEdit.id) {
|
if (comments.value[c].id === commentEdit.id) {
|
||||||
comments.value[c] = comment
|
comments.value[c] = comment
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ async function removeAssignee(user: IUser) {
|
||||||
await taskStore.removeAssignee({user: user, taskId: props.taskId})
|
await taskStore.removeAssignee({user: user, taskId: props.taskId})
|
||||||
|
|
||||||
// Remove the assignee from the project
|
// Remove the assignee from the project
|
||||||
for (const a in assignees.value) {
|
for (let a = assignees.value.length - 1; a >= 0; a--) {
|
||||||
if (assignees.value[a].id === user.id) {
|
if (assignees.value[a].id === user.id) {
|
||||||
assignees.value.splice(a, 1)
|
assignees.value.splice(a, 1)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -124,9 +124,9 @@ async function removeLabel(label: ILabel) {
|
||||||
await taskStore.removeLabel({label, taskId: props.taskId})
|
await taskStore.removeLabel({label, taskId: props.taskId})
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const l in labels.value) {
|
for (let l = labels.value.length - 1; l >= 0; l--) {
|
||||||
if (labels.value[l].id === label.id) {
|
if (labels.value[l].id === label.id) {
|
||||||
labels.value.splice(l, 1) // FIXME: l should be index
|
labels.value.splice(l, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
emit('update:modelValue', labels.value)
|
emit('update:modelValue', labels.value)
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ export function objectToCamelCase(object: Record<string, any>) {
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const parsedObject: Record<string, any> = {}
|
const parsedObject: Record<string, any> = {}
|
||||||
for (const m in object) {
|
for (const m of Object.keys(object)) {
|
||||||
parsedObject[camelCase(m)] = object[m]
|
parsedObject[camelCase(m)] = object[m]
|
||||||
|
|
||||||
// Recursive processing
|
// Recursive processing
|
||||||
|
|
@ -51,7 +51,7 @@ export function objectToSnakeCase(object: Record<string, any>) {
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const parsedObject: Record<string, any> = {}
|
const parsedObject: Record<string, any> = {}
|
||||||
for (const m in object) {
|
for (const m of Object.keys(object)) {
|
||||||
parsedObject[snakeCase(m)] = object[m]
|
parsedObject[snakeCase(m)] = object[m]
|
||||||
|
|
||||||
// Recursive processing
|
// Recursive processing
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,11 @@ describe('Filter Transformation', () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('For API', () => {
|
describe('For API', () => {
|
||||||
for (const c in fieldCases) {
|
for (const [c, snakeCase] of Object.entries(fieldCases)) {
|
||||||
it('should transform all filter params for ' + c + ' to snake_case', () => {
|
it('should transform all filter params for ' + c + ' to snake_case', () => {
|
||||||
const transformed = transformFilterStringForApi(c + ' = ipsum', nullTitleToIdResolver, nullTitleToIdResolver)
|
const transformed = transformFilterStringForApi(c + ' = ipsum', nullTitleToIdResolver, nullTitleToIdResolver)
|
||||||
|
|
||||||
expect(transformed).toBe(fieldCases[c] + ' = ipsum')
|
expect(transformed).toBe(snakeCase + ' = ipsum')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -416,9 +416,9 @@ describe('Filter Transformation', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('To API', () => {
|
describe('To API', () => {
|
||||||
for (const c in fieldCases) {
|
for (const [c, snakeCase] of Object.entries(fieldCases)) {
|
||||||
it('should transform all filter params for ' + c + ' to snake_case', () => {
|
it('should transform all filter params for ' + c + ' to snake_case', () => {
|
||||||
const transformed = transformFilterStringFromApi(fieldCases[c] + ' = ipsum', nullTitleToIdResolver, nullTitleToIdResolver)
|
const transformed = transformFilterStringFromApi(snakeCase + ' = ipsum', nullTitleToIdResolver, nullTitleToIdResolver)
|
||||||
|
|
||||||
expect(transformed).toBe(c + ' = ipsum')
|
expect(transformed).toBe(c + ' = ipsum')
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ export const saveCollapsedBucketState = (
|
||||||
) => {
|
) => {
|
||||||
const state = getAllState()
|
const state = getAllState()
|
||||||
state[projectId] = collapsedBuckets
|
state[projectId] = collapsedBuckets
|
||||||
for (const bucketId in state[projectId]) {
|
for (const bucketId of Object.keys(state[projectId])) {
|
||||||
if (!state[projectId][bucketId]) {
|
if (!state[projectId][bucketId]) {
|
||||||
delete state[projectId][bucketId]
|
delete state[projectId][bucketId]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,13 +12,13 @@ const days = {
|
||||||
sunday: 0,
|
sunday: 0,
|
||||||
} as Record<string, number>
|
} as Record<string, number>
|
||||||
|
|
||||||
for (const n in days) {
|
for (const n of Object.keys(days)) {
|
||||||
test(`today on a ${n}`, () => {
|
test(`today on a ${n}`, () => {
|
||||||
expect(calculateDayInterval('today', days[n])).toBe(0)
|
expect(calculateDayInterval('today', days[n])).toBe(0)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const n in days) {
|
for (const n of Object.keys(days)) {
|
||||||
test(`tomorrow on a ${n}`, () => {
|
test(`tomorrow on a ${n}`, () => {
|
||||||
expect(calculateDayInterval('tomorrow', days[n])).toBe(1)
|
expect(calculateDayInterval('tomorrow', days[n])).toBe(1)
|
||||||
})
|
})
|
||||||
|
|
@ -34,7 +34,7 @@ const nextMonday = {
|
||||||
sunday: 1,
|
sunday: 1,
|
||||||
} as Record<string, number>
|
} as Record<string, number>
|
||||||
|
|
||||||
for (const n in nextMonday) {
|
for (const n of Object.keys(nextMonday)) {
|
||||||
test(`next monday on a ${n}`, () => {
|
test(`next monday on a ${n}`, () => {
|
||||||
expect(calculateDayInterval('nextMonday', days[n])).toBe(nextMonday[n])
|
expect(calculateDayInterval('nextMonday', days[n])).toBe(nextMonday[n])
|
||||||
})
|
})
|
||||||
|
|
@ -50,7 +50,7 @@ const thisWeekend = {
|
||||||
sunday: 0,
|
sunday: 0,
|
||||||
} as Record<string, number>
|
} as Record<string, number>
|
||||||
|
|
||||||
for (const n in thisWeekend) {
|
for (const n of Object.keys(thisWeekend)) {
|
||||||
test(`this weekend on a ${n}`, () => {
|
test(`this weekend on a ${n}`, () => {
|
||||||
expect(calculateDayInterval('thisWeekend', days[n])).toBe(thisWeekend[n])
|
expect(calculateDayInterval('thisWeekend', days[n])).toBe(thisWeekend[n])
|
||||||
})
|
})
|
||||||
|
|
@ -66,7 +66,7 @@ const laterThisWeek = {
|
||||||
sunday: 0,
|
sunday: 0,
|
||||||
} as Record<string, number>
|
} as Record<string, number>
|
||||||
|
|
||||||
for (const n in laterThisWeek) {
|
for (const n of Object.keys(laterThisWeek)) {
|
||||||
test(`later this week on a ${n}`, () => {
|
test(`later this week on a ${n}`, () => {
|
||||||
expect(calculateDayInterval('laterThisWeek', days[n])).toBe(laterThisWeek[n])
|
expect(calculateDayInterval('laterThisWeek', days[n])).toBe(laterThisWeek[n])
|
||||||
})
|
})
|
||||||
|
|
@ -82,13 +82,13 @@ const laterNextWeek = {
|
||||||
sunday: 7 + 0,
|
sunday: 7 + 0,
|
||||||
} as Record<string, number>
|
} as Record<string, number>
|
||||||
|
|
||||||
for (const n in laterNextWeek) {
|
for (const n of Object.keys(laterNextWeek)) {
|
||||||
test(`later next week on a ${n} (this week)`, () => {
|
test(`later next week on a ${n} (this week)`, () => {
|
||||||
expect(calculateDayInterval('laterNextWeek', days[n])).toBe(laterNextWeek[n])
|
expect(calculateDayInterval('laterNextWeek', days[n])).toBe(laterNextWeek[n])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const n in days) {
|
for (const n of Object.keys(days)) {
|
||||||
test(`next week on a ${n}`, () => {
|
test(`next week on a ${n}`, () => {
|
||||||
expect(calculateDayInterval('nextWeek', days[n])).toBe(7)
|
expect(calculateDayInterval('nextWeek', days[n])).toBe(7)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,7 @@ describe('Parse Task Text', () => {
|
||||||
'at 12:00 am': '0:0',
|
'at 12:00 am': '0:0',
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
for (const c in cases) {
|
for (const c of Object.keys(cases)) {
|
||||||
it(`should recognize today with a time ${c}`, () => {
|
it(`should recognize today with a time ${c}`, () => {
|
||||||
const result = parseTaskText(`Lorem Ipsum today ${c}`)
|
const result = parseTaskText(`Lorem Ipsum today ${c}`)
|
||||||
|
|
||||||
|
|
@ -526,7 +526,7 @@ describe('Parse Task Text', () => {
|
||||||
]
|
]
|
||||||
|
|
||||||
prefix.forEach(p => {
|
prefix.forEach(p => {
|
||||||
for (const d in days) {
|
for (const d of Object.keys(days)) {
|
||||||
it(`should recognize ${p}${d}`, () => {
|
it(`should recognize ${p}${d}`, () => {
|
||||||
const result = parseTaskText(`Lorem Ipsum ${p}${d}`)
|
const result = parseTaskText(`Lorem Ipsum ${p}${d}`)
|
||||||
|
|
||||||
|
|
@ -556,7 +556,7 @@ describe('Parse Task Text', () => {
|
||||||
|
|
||||||
// This tests only standalone days are recognized and not things like "github", "monitor" or "renewed".
|
// This tests only standalone days are recognized and not things like "github", "monitor" or "renewed".
|
||||||
// We're not using real words here to generate tests for all days on the fly.
|
// We're not using real words here to generate tests for all days on the fly.
|
||||||
for (const d in days) {
|
for (const d of Object.keys(days)) {
|
||||||
it(`should not recognize ${d} with a space before it but none after it`, () => {
|
it(`should not recognize ${d} with a space before it but none after it`, () => {
|
||||||
const text = `Lorem Ipsum ${d}ipsum`
|
const text = `Lorem Ipsum ${d}ipsum`
|
||||||
const result = parseTaskText(text)
|
const result = parseTaskText(text)
|
||||||
|
|
@ -660,7 +660,7 @@ describe('Parse Task Text', () => {
|
||||||
'01.02.25': '2025-2-1',
|
'01.02.25': '2025-2-1',
|
||||||
} as Record<string, string | null>
|
} as Record<string, string | null>
|
||||||
|
|
||||||
for (const c in cases) {
|
for (const c of Object.keys(cases)) {
|
||||||
const assertResult = ({date, text}: ParsedTaskText) => {
|
const assertResult = ({date, text}: ParsedTaskText) => {
|
||||||
if (date === null && cases[c] === null) {
|
if (date === null && cases[c] === null) {
|
||||||
expect(date).toBeNull()
|
expect(date).toBeNull()
|
||||||
|
|
@ -722,7 +722,7 @@ describe('Parse Task Text', () => {
|
||||||
'5th Mar at 3pm': '2021-3-5 15:0',
|
'5th Mar at 3pm': '2021-3-5 15:0',
|
||||||
} as Record<string, string>
|
} as Record<string, string>
|
||||||
|
|
||||||
for (const c in cases) {
|
for (const c of Object.keys(cases)) {
|
||||||
it(`should parse '${c}' as '${cases[c]}'`, () => {
|
it(`should parse '${c}' as '${cases[c]}'`, () => {
|
||||||
const {date} = parseDate(c, now)
|
const {date} = parseDate(c, now)
|
||||||
if (date === null && cases[c] === null) {
|
if (date === null && cases[c] === null) {
|
||||||
|
|
@ -846,7 +846,7 @@ describe('Parse Task Text', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('Priority', () => {
|
describe('Priority', () => {
|
||||||
for (const p in PRIORITIES) {
|
for (const p of Object.keys(PRIORITIES) as Array<keyof typeof PRIORITIES>) {
|
||||||
it(`should parse priority ${p}`, () => {
|
it(`should parse priority ${p}`, () => {
|
||||||
const result = parseTaskText(`Lorem Ipsum !${PRIORITIES[p]}`)
|
const result = parseTaskText(`Lorem Ipsum !${PRIORITIES[p]}`)
|
||||||
|
|
||||||
|
|
@ -969,7 +969,7 @@ describe('Parse Task Text', () => {
|
||||||
'yearly': {type: 'years', amount: 1},
|
'yearly': {type: 'years', amount: 1},
|
||||||
} as Record<string, IRepeatAfter>
|
} as Record<string, IRepeatAfter>
|
||||||
|
|
||||||
for (const c in cases) {
|
for (const c of Object.keys(cases)) {
|
||||||
it(`should parse ${c} as recurring date every ${cases[c].amount} ${cases[c].type}`, () => {
|
it(`should parse ${c} as recurring date every ${cases[c].amount} ${cases[c].type}`, () => {
|
||||||
const result = parseTaskText(`Lorem Ipsum ${c}`)
|
const result = parseTaskText(`Lorem Ipsum ${c}`)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ interface Paths {
|
||||||
reset?: string
|
reset?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertObject(o: Record<string, unknown>) {
|
function convertObject(o: unknown) {
|
||||||
if (o instanceof Date) {
|
if (o instanceof Date) {
|
||||||
return o.toISOString()
|
return o.toISOString()
|
||||||
}
|
}
|
||||||
|
|
@ -28,13 +28,14 @@ function prepareParams(params: Record<string, unknown | unknown[]>) {
|
||||||
return params
|
return params
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const p in params) {
|
for (const p of Object.keys(params)) {
|
||||||
if (Array.isArray(params[p])) {
|
const val = params[p]
|
||||||
params[p] = params[p].map(convertObject)
|
if (Array.isArray(val)) {
|
||||||
|
params[p] = val.map(convertObject)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
params[p] = convertObject(params[p])
|
params[p] = convertObject(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
return objectToSnakeCase(params)
|
return objectToSnakeCase(params)
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ export default class TaskService extends AbstractService<ITask> {
|
||||||
|
|
||||||
model.reminderDates = null
|
model.reminderDates = null
|
||||||
// remove all nulls, these would create empty reminders
|
// remove all nulls, these would create empty reminders
|
||||||
for (const index in model.reminders) {
|
for (let index = model.reminders.length - 1; index >= 0; index--) {
|
||||||
if (model.reminders[index] === null) {
|
if (model.reminders[index] === null) {
|
||||||
model.reminders.splice(index, 1)
|
model.reminders.splice(index, 1)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -124,9 +124,9 @@ export const useKanbanStore = defineStore('kanban', () => {
|
||||||
|
|
||||||
let found = false
|
let found = false
|
||||||
|
|
||||||
const findAndUpdate = b => {
|
const findAndUpdate = (b: number) => {
|
||||||
for (const t in buckets.value[b].tasks) {
|
for (const [t, taskInBucket] of buckets.value[b].tasks.entries()) {
|
||||||
if (buckets.value[b].tasks[t].id === task.id) {
|
if (taskInBucket.id === task.id) {
|
||||||
const bucket = buckets.value[b]
|
const bucket = buckets.value[b]
|
||||||
bucket.tasks[t] = task
|
bucket.tasks[t] = task
|
||||||
|
|
||||||
|
|
@ -138,7 +138,7 @@ export const useKanbanStore = defineStore('kanban', () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const b in buckets.value) {
|
for (let b = 0; b < buckets.value.length; b++) {
|
||||||
findAndUpdate(b)
|
findAndUpdate(b)
|
||||||
if (found) {
|
if (found) {
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -287,7 +287,7 @@ async function loadPendingTasks(from: Date|string, to: Date|string, filterId: nu
|
||||||
|
|
||||||
// FIXME: this modification should happen in the store
|
// FIXME: this modification should happen in the store
|
||||||
function updateTasks(updatedTask: ITask) {
|
function updateTasks(updatedTask: ITask) {
|
||||||
for (const t in tasks.value) {
|
for (let t = 0; t < tasks.value.length; t++) {
|
||||||
if (tasks.value[t].id === updatedTask.id) {
|
if (tasks.value[t].id === updatedTask.id) {
|
||||||
tasks.value[t] = updatedTask
|
tasks.value[t] = updatedTask
|
||||||
// Move the task to the end of the done tasks if it is now done
|
// Move the task to the end of the done tasks if it is now done
|
||||||
|
|
|
||||||
|
|
@ -1174,9 +1174,12 @@ function setRelatedTasksActive() {
|
||||||
|
|
||||||
// If the related tasks are already available, show the form again
|
// If the related tasks are already available, show the form again
|
||||||
const el = activeFieldElements['relatedTasks']
|
const el = activeFieldElements['relatedTasks']
|
||||||
for (const child in el?.children) {
|
if (!el) {
|
||||||
if (el?.children[child]?.id === 'showRelatedTasksFormButton') {
|
return
|
||||||
el?.children[child]?.click()
|
}
|
||||||
|
for (const child of Array.from(el.children)) {
|
||||||
|
if ((child as HTMLElement).id === 'showRelatedTasksFormButton') {
|
||||||
|
(child as HTMLElement).click()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -349,9 +349,9 @@ async function toggleUserType(member: ITeamMember) {
|
||||||
member.admin = !member.admin
|
member.admin = !member.admin
|
||||||
member.teamId = teamId.value
|
member.teamId = teamId.value
|
||||||
const r = await teamMemberService.value.update(member)
|
const r = await teamMemberService.value.update(member)
|
||||||
for (const tm in team.value.members) {
|
for (const tm of team.value.members) {
|
||||||
if (team.value.members[tm].id === member.id) {
|
if (tm.id === member.id) {
|
||||||
team.value.members[tm].admin = r.admin
|
tm.admin = r.admin
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue