diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/SubscriptionPlanUpdateDialog.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/SubscriptionPlanUpdateDialog.tsx
index 280e43a0adf..e41ecd778cf 100644
--- a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/SubscriptionPlanUpdateDialog.tsx
+++ b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/SubscriptionPlanUpdateDialog.tsx
@@ -1,34 +1,36 @@
import { useQueryClient } from '@tanstack/react-query'
-import { InfoIcon, Check, ExternalLink } from 'lucide-react'
+import { Check, ExternalLink, InfoIcon } from 'lucide-react'
import Link from 'next/link'
-import { useState, useEffect } from 'react'
-import { toast } from 'sonner'
+import { useEffect, useState } from 'react'
import tweets from 'shared-data/tweets'
+import { toast } from 'sonner'
+import { billingPartnerLabel } from 'components/interfaces/Billing/Subscription/Subscription.utils'
import AlertError from 'components/ui/AlertError'
import ShimmeringLoader from 'components/ui/ShimmeringLoader'
+import { organizationKeys } from 'data/organizations/keys'
+import { OrganizationBillingSubscriptionPreviewResponse } from 'data/organizations/organization-billing-subscription-preview'
+import { useOrgSubscriptionUpdateMutation } from 'data/subscriptions/org-subscription-update-mutation'
+import { SubscriptionTier } from 'data/subscriptions/types'
+import { PRICING_TIER_PRODUCT_IDS } from 'lib/constants'
+import { formatCurrency } from 'lib/helpers'
import {
+ Badge,
+ Button,
+ Card,
+ CardContent,
+ Dialog,
+ DialogContent,
+ HoverCard,
+ HoverCardContent,
+ HoverCardTrigger,
Table,
TableBody,
TableCell,
TableRow,
- HoverCard,
- HoverCardContent,
- HoverCardTrigger,
- Card,
- CardContent,
- Badge,
} from 'ui'
-import { useOrgSubscriptionUpdateMutation } from 'data/subscriptions/org-subscription-update-mutation'
-import { organizationKeys } from 'data/organizations/keys'
-import { formatCurrency } from 'lib/helpers'
-import { PRICING_TIER_PRODUCT_IDS } from 'lib/constants'
-import { SubscriptionTier } from 'data/subscriptions/types'
-import { billingPartnerLabel } from 'components/interfaces/Billing/Subscription/Subscription.utils'
-import PaymentMethodSelection from './PaymentMethodSelection'
-import { Button, Dialog, DialogContent } from 'ui'
import { InfoTooltip } from 'ui-patterns/info-tooltip'
-import { OrganizationBillingSubscriptionPreviewResponse } from 'data/organizations/organization-billing-subscription-preview'
+import PaymentMethodSelection from './PaymentMethodSelection'
const getRandomTweet = () => {
const filteredTweets = tweets.filter((it) => it.text.length < 180)
@@ -576,7 +578,7 @@ const SubscriptionPlanUpdateDialog = ({
onClick={onUpdateSubscription}
className="flex-1"
>
- Confirm {planMeta?.change_type === 'downgrade' ? 'Downgrade' : 'Upgrade'}
+ Confirm {planMeta?.change_type === 'downgrade' ? 'downgrade' : 'upgrade'}
diff --git a/apps/studio/components/interfaces/Organization/TeamSettings/UpdateRolesPanel/UpdateRolesConfirmationModal.tsx b/apps/studio/components/interfaces/Organization/TeamSettings/UpdateRolesPanel/UpdateRolesConfirmationModal.tsx
index 1756678bdc9..fc37dd4fe91 100644
--- a/apps/studio/components/interfaces/Organization/TeamSettings/UpdateRolesPanel/UpdateRolesConfirmationModal.tsx
+++ b/apps/studio/components/interfaces/Organization/TeamSettings/UpdateRolesPanel/UpdateRolesConfirmationModal.tsx
@@ -219,7 +219,7 @@ export const UpdateRolesConfirmationModal = ({
return (
From {originalRoleName} to{' '}
- {updatedRole?.name} on{' '}
+ {updatedRole?.name ?? 'Unknown'} on{' '}
{project?.name ?? 'organization'}
diff --git a/apps/studio/components/interfaces/Organization/TeamSettings/UpdateRolesPanel/UpdateRolesPanel.tsx b/apps/studio/components/interfaces/Organization/TeamSettings/UpdateRolesPanel/UpdateRolesPanel.tsx
index 93091c695d6..4782245ccd3 100644
--- a/apps/studio/components/interfaces/Organization/TeamSettings/UpdateRolesPanel/UpdateRolesPanel.tsx
+++ b/apps/studio/components/interfaces/Organization/TeamSettings/UpdateRolesPanel/UpdateRolesPanel.tsx
@@ -3,6 +3,7 @@ import { X } from 'lucide-react'
import { useEffect, useState } from 'react'
import { useParams } from 'common'
+import { ButtonTooltip } from 'components/ui/ButtonTooltip'
import { DocsButton } from 'components/ui/DocsButton'
import { useOrganizationRolesV2Query } from 'data/organization-members/organization-roles-query'
import { OrganizationMember } from 'data/organizations/organization-members-query'
@@ -85,21 +86,26 @@ export const UpdateRolesPanel = ({ visible, member, onClose }: UpdateRolesPanelP
allRoles !== undefined
? formatMemberRoleToProjectRoleConfiguration(member, allRoles, projects ?? [])
: []
+ const originalConfigurationType =
+ originalConfiguration.length === 1 &&
+ !!orgScopedRoles.find((r) => r.id === originalConfiguration[0].roleId)
+ ? 'org-scope'
+ : 'project-scope'
+
const orgProjects = (projects ?? []).filter((p) => p.organization_id === organization?.id)
const isApplyingRoleToAllProjects =
projectsRoleConfiguration.length === 1 && projectsRoleConfiguration[0]?.ref === undefined
const canSaveRoles = projectsRoleConfiguration.length > 0
const lowerPermissionsRole = orgScopedRoles.find((r) => r.name === 'Developer')?.id
- const sortByObject: any = ['Owner', 'Administrator', 'Developer'].reduce((obj, item, index) => {
- return { ...obj, [item]: index }
- }, {})
const noAccessProjects = orgProjects.filter((project) => {
return !projectsRoleConfiguration.some((p) => p.ref === project.ref)
})
const numberOfProjectsWithAccess = orgProjects.length - noAccessProjects.length
const numberOfAccessHasChanges = originalConfiguration.length !== noAccessProjects.length
+ const hasNoChanges = isEqual(projectsRoleConfiguration, originalConfiguration)
+
const onSelectProject = (ref: string) => {
setProjectsRoleConfiguration(
projectsRoleConfiguration.concat({
@@ -131,17 +137,27 @@ export const UpdateRolesPanel = ({ visible, member, onClose }: UpdateRolesPanelP
}
}
- const onToggleApplyToAllProjects = () => {
- const roleIdToApply =
- projectsRoleConfiguration[0]?.roleId ?? lowerPermissionsRole ?? orgScopedRoles[0].id
- if (isApplyingRoleToAllProjects) {
- setProjectsRoleConfiguration(
- orgProjects.map((p) => {
- return { ref: p.ref, projectId: p.id, roleId: roleIdToApply }
- })
- )
+ const onToggleApplyToAllProjects = (isApplyAllProjects: boolean) => {
+ const roleIdToApply = lowerPermissionsRole ?? orgScopedRoles[0].id
+
+ if (isApplyAllProjects) {
+ if (originalConfigurationType === 'org-scope') {
+ console.log('Reset: Org scoped')
+ setProjectsRoleConfiguration(originalConfiguration)
+ } else {
+ setProjectsRoleConfiguration([{ ref: undefined, roleId: roleIdToApply }])
+ }
} else {
- setProjectsRoleConfiguration([{ ref: undefined, roleId: roleIdToApply }])
+ if (originalConfigurationType === 'project-scope') {
+ console.log('Reset: Project scoped')
+ setProjectsRoleConfiguration(originalConfiguration)
+ } else {
+ setProjectsRoleConfiguration(
+ orgProjects.map((p) => {
+ return { ref: p.ref, projectId: p.id, roleId: roleIdToApply }
+ })
+ )
+ }
}
}
@@ -275,7 +291,7 @@ export const UpdateRolesPanel = ({ visible, member, onClose }: UpdateRolesPanelP
{role.name}
@@ -288,22 +304,21 @@ export const UpdateRolesPanel = ({ visible, member, onClose }: UpdateRolesPanelP
)}
{!isApplyingRoleToAllProjects && (
-
-
- }
- onClick={() => onRemoveProject(project?.ref)}
- />
-
- {!canRemoveRole && (
-
- Additional permission required to remove role from member
-
- )}
-
+ }
+ onClick={() => onRemoveProject(project?.ref)}
+ tooltip={{
+ content: {
+ side: 'bottom',
+ text: !canRemoveRole
+ ? 'Additional permission required to remove role from member'
+ : 'Remove access to project',
+ },
+ }}
+ />
)}
@@ -363,13 +378,9 @@ export const UpdateRolesPanel = ({ visible, member, onClose }: UpdateRolesPanelP