From 4fc0c43fe03eec1e1673a08e7628cfeafa4fceb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4ki?= Date: Mon, 8 Dec 2025 16:22:35 +0200 Subject: [PATCH 1/3] Disable team profile form for non-owner members Backend requires owner-level permissions so no point waste other member's time by letting them fiddle with the form. I considered creating entirely separate component for viewing the data, which would save us from having to set up strongForm for no reason, but given there's no reusable components, it would repeat a lot of markup and lead to poor maintainability. --- .../app/settings/teams/team/tabs/Profile/Profile.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/cyberstorm-remix/app/settings/teams/team/tabs/Profile/Profile.tsx b/apps/cyberstorm-remix/app/settings/teams/team/tabs/Profile/Profile.tsx index d76552e27..8ea0b2f05 100644 --- a/apps/cyberstorm-remix/app/settings/teams/team/tabs/Profile/Profile.tsx +++ b/apps/cyberstorm-remix/app/settings/teams/team/tabs/Profile/Profile.tsx @@ -15,6 +15,7 @@ import { import { type OutletContextShape } from "app/root"; import { makeTeamSettingsTabLoader } from "cyberstorm/utils/dapperClientLoaders"; +import { isTeamOwner } from "cyberstorm/utils/permissions"; import { useStrongForm } from "cyberstorm/utils/StrongForm/useStrongForm"; import "./Profile.css"; @@ -49,6 +50,8 @@ function ProfileForm(props: { team: TeamDetails }) { const revalidator = useRevalidator(); const toast = useToast(); + const formDisabled = !isTeamOwner(team.name, outletContext.currentUser); + function formFieldUpdateAction( state: TeamDetailsEditRequestData, action: { @@ -128,10 +131,15 @@ function ProfileForm(props: { team: TeamDetails }) { }) } rootClasses="team-profile__input" + disabled={formDisabled} /> - + Save changes From 5eace68406a83464eb8b76cda1aeef50ee915f5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4ki?= Date: Mon, 8 Dec 2025 16:30:06 +0200 Subject: [PATCH 2/3] Disable hover highlight styles from disabled text inputs Change the on-hover cursor when to indicate the input is disabled. --- .../src/components/TextInput/TextInput.css | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/cyberstorm-theme/src/components/TextInput/TextInput.css b/packages/cyberstorm-theme/src/components/TextInput/TextInput.css index 7ddf33bb6..818b73f41 100644 --- a/packages/cyberstorm-theme/src/components/TextInput/TextInput.css +++ b/packages/cyberstorm-theme/src/components/TextInput/TextInput.css @@ -67,12 +67,16 @@ --text-input-border-color: var(--input-border-color--invalid); } - .text-input:hover { + .text-input:disabled { + cursor: not-allowed; + } + + .text-input:hover:not(:disabled) { --text-input-background-color: var(--input-bg-color--hover); --text-input-border-color: var(--input-border-color--hover); } - .text-input:focus-within { + .text-input:focus-within:not(:disabled) { --text-input-text-color: var(--input-text-color--focus); --text-input-background-color: var(--input-bg-color--focus); --text-input-border-color: var(--input-border-color--focus); From 036d512bfba6fc2d4fff90f66e2003339ebf263a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4ki?= Date: Mon, 8 Dec 2025 16:53:14 +0200 Subject: [PATCH 3/3] Disable hover highlight styles from disabled buttons Remove pointer-events: none rule from disabled buttons so they show the default on-hover cursor for them. --- .../src/components/Button/Button.css | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/packages/cyberstorm-theme/src/components/Button/Button.css b/packages/cyberstorm-theme/src/components/Button/Button.css index d9ae95aca..75ca95960 100644 --- a/packages/cyberstorm-theme/src/components/Button/Button.css +++ b/packages/cyberstorm-theme/src/components/Button/Button.css @@ -55,14 +55,14 @@ --button-text-color: var(--button-primary-text-color--default); --button-icon-color: var(--button-primary-icon-color--default); - &:where(:hover), + &:where(:hover:not(:disabled)), &[data-state="open"] { --button-background-color: var(--button-primary-bg-color--hover); --button-text-color: var(--button-primary-text-color--hover); --button-icon-color: var(--button-primary-icon-color--hover); } - &:where(:active) { + &:where(:active:not(:disabled)) { --button-background-color: var(--button-primary-bg-color--active); --button-text-color: var(--button-primary-text-color--active); --button-icon-color: var(--button-primary-icon-color--active); @@ -74,14 +74,14 @@ --button-text-color: var(--button-secondary-text-color--default); --button-icon-color: var(--button-secondary-icon-color--default); - &:where(:hover), + &:where(:hover:not(:disabled)), &[data-state="open"] { --button-background-color: var(--button-secondary-bg-color--hover); --button-text-color: var(--button-secondary-text-color--hover); --button-icon-color: var(--button-secondary-icon-color--hover); } - &:where(:active) { + &:where(:active:not(:disabled)) { --button-background-color: var(--button-secondary-bg-color--active); --button-text-color: var(--button-secondary-text-color--active); --button-icon-color: var(--button-secondary-icon-color--active); @@ -93,14 +93,14 @@ --button-text-color: var(--button-accent-text-color--default); --button-icon-color: var(--button-accent-icon-color--default); - &:where(:hover), + &:where(:hover:not(:disabled)), &[data-state="open"] { --button-background-color: var(--button-accent-bg-color--hover); --button-text-color: var(--button-accent-text-color--hover); --button-icon-color: var(--button-accent-icon-color--hover); } - &:where(:active) { + &:where(:active:not(:disabled)) { --button-background-color: var(--button-accent-bg-color--active); --button-text-color: var(--button-accent-text-color--active); --button-icon-color: var(--button-accent-icon-color--active); @@ -115,7 +115,7 @@ background: var(--button-special-background--default); - &:where(:hover), + &:where(:hover:not(:disabled)), &[data-state="open"] { --button-text-color: var(--button-special-text-color--hover); --button-icon-color: var(--button-special-icon-color--hover); @@ -125,7 +125,7 @@ background: var(--button-special-background--hover); } - &:where(:active) { + &:where(:active:not(:disabled)) { --button-text-color: var(--button-special-text-color--active); --button-icon-color: var(--button-special-icon-color--active); --button-border: var(--button-special-border--active); @@ -140,14 +140,14 @@ --button-text-color: var(--button-success-text-color--default); --button-icon-color: var(--button-success-icon-color--default); - &:where(:hover), + &:where(:hover:not(:disabled)), &[data-state="open"] { --button-background-color: var(--button-success-bg-color--hover); --button-text-color: var(--button-success-text-color--hover); --button-icon-color: var(--button-success-icon-color--hover); } - &:where(:active) { + &:where(:active:not(:disabled)) { --button-background-color: var(--button-success-bg-color--active); --button-text-color: var(--button-success-text-color--active); --button-icon-color: var(--button-success-icon-color--active); @@ -159,14 +159,14 @@ --button-text-color: var(--button-info-text-color--default); --button-icon-color: var(--button-info-icon-color--default); - &:where(:hover), + &:where(:hover:not(:disabled)), &[data-state="open"] { --button-background-color: var(--button-info-bg-color--hover); --button-text-color: var(--button-info-text-color--hover); --button-icon-color: var(--button-info-icon-color--hover); } - &:where(:active) { + &:where(:active:not(:disabled)) { --button-background-color: var(--button-info-bg-color--active); --button-text-color: var(--button-info-text-color--active); --button-icon-color: var(--button-info-icon-color--active); @@ -178,14 +178,14 @@ --button-text-color: var(--button-warning-text-color--default); --button-icon-color: var(--button-warning-icon-color--default); - &:where(:hover), + &:where(:hover:not(:disabled)), &[data-state="open"] { --button-background-color: var(--button-warning-bg-color--hover); --button-text-color: var(--button-warning-text-color--hover); --button-icon-color: var(--button-warning-icon-color--hover); } - &:where(:active) { + &:where(:active:not(:disabled)) { --button-background-color: var(--button-warning-bg-color--active); --button-text-color: var(--button-warning-text-color--active); --button-icon-color: var(--button-warning-icon-color--active); @@ -197,14 +197,14 @@ --button-text-color: var(--button-danger-text-color--default); --button-icon-color: var(--button-danger-icon-color--default); - &:where(:hover), + &:where(:hover:not(:disabled)), &[data-state="open"] { --button-background-color: var(--button-danger-bg-color--hover); --button-text-color: var(--button-danger-text-color--hover); --button-icon-color: var(--button-danger-icon-color--hover); } - &:where(:active) { + &:where(:active:not(:disabled)) { --button-background-color: var(--button-danger-bg-color--active); --button-text-color: var(--button-danger-text-color--active); --button-icon-color: var(--button-danger-icon-color--active); @@ -226,7 +226,6 @@ .button[disabled] { opacity: 0.5; - pointer-events: none; } .button:where(.button--only-icon) {