-
Notifications
You must be signed in to change notification settings - Fork 29
Add Account Settings page #8672
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
60 commits
Select commit
Hold shift + click to select a range
8f2428c
Update navbar links and add account settings route
hotzenklotz 58c2d49
Refactor account settings view and add profile management
hotzenklotz 9367076
WIP account setting sub page styling
hotzenklotz 33b0b1a
formatting
hotzenklotz 4a4c460
fix typeing
hotzenklotz 8e18e2a
added breadcrumbs
hotzenklotz 77e602a
added redirects to old routes
hotzenklotz 09d50ea
apply feedback
hotzenklotz 14e624b
fix typo
hotzenklotz cb70499
move account related views into separate directory
hotzenklotz dd6c8e6
style background
hotzenklotz 4cd2ecd
refactor orga settings in new style
hotzenklotz 6a4b559
Merge branch 'master' of github.com:scalableminds/webknossos into acc…
hotzenklotz d022413
Merge branch 'account-settings-page' into orga-settings-page
hotzenklotz 82fd616
Refactor account settings components and update organization navigation
hotzenklotz aa95b90
Enhance organization management UI and functionality
hotzenklotz a2002cb
formatting
hotzenklotz b7543ea
Enhance organization-related components and UI
hotzenklotz 749861a
fix setting cards buttons
hotzenklotz 44e0966
changelog
hotzenklotz 76616d0
Merge branch 'master' of github.com:scalableminds/webknossos into acc…
hotzenklotz 8716091
Merge branch 'account-settings-page' into orga-settings-page
hotzenklotz 55bf833
Update frontend/javascripts/admin/organization/pricing_plan_utils.ts
hotzenklotz 513011b
applied PR feedback
hotzenklotz 01ae877
Merge branch 'orga-settings-page' of github.com:scalableminds/webknos…
hotzenklotz 67e8819
Show owner email in notifications
hotzenklotz 121c91a
fix pricing plan label
hotzenklotz 9ee0b24
Merge branch 'master' of github.com:scalableminds/webknossos into acc…
hotzenklotz 203ae75
Merge branch 'account-settings-page' into orga-settings-page
hotzenklotz df8e81d
do not show upgrade options for custom plans yet
hotzenklotz b094806
update the account settings page with card style
hotzenklotz a91f88b
Update frontend/javascripts/router.tsx
hotzenklotz 38c426e
Update frontend/javascripts/admin/account/account_password_view.tsx
hotzenklotz 511c4fb
Merge branch 'master' into account-settings-page
hotzenklotz d0cd5b3
more stuff
hotzenklotz 66086aa
fix null / infinity on update
hotzenklotz 1903218
appled PR feedback
hotzenklotz d61a522
apply PR feedback
hotzenklotz f2ee79d
fix linitng
hotzenklotz 2ed707a
Merge branch 'account-settings-page' into orga-settings-page
hotzenklotz 1f74811
Merge branch 'orga-settings-page' into account-settings-page-cards
hotzenklotz 125ed0f
formatting
hotzenklotz e489f9d
Rework organization page (#8679)
hotzenklotz c8e6a4e
Merge branch 'account-settings-page-cards' into account-settings-page
hotzenklotz a84f9fc
Merge branch 'master' of github.com:scalableminds/webknossos into acc…
hotzenklotz 0418bbf
refinement
hotzenklotz c12b0a3
changelog
hotzenklotz b3ef603
Merge branch 'master' of github.com:scalableminds/webknossos into acc…
hotzenklotz 58af2a4
apply coderabbit feedback
hotzenklotz 52728d5
redirect after orga removal
hotzenklotz 235be66
apply feedback
hotzenklotz f734e92
Update unreleased_changes/8672.md
hotzenklotz 0260a0e
Merge branch 'master' of github.com:scalableminds/webknossos into acc…
hotzenklotz 8b8fb57
apply PR feedback
hotzenklotz 0bb572d
Update unreleased_changes/8679.md
hotzenklotz 6762eee
Merge branch 'master' of github.com:scalableminds/webknossos into acc…
hotzenklotz e6a69d5
Merge branch 'account-settings-page' of github.com:scalableminds/webk…
hotzenklotz 6e8e483
add theme switching to command palette
philippotto c3be491
add toast.error
philippotto 7d98ca1
sort imports
philippotto File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
108 changes: 108 additions & 0 deletions
108
frontend/javascripts/admin/account/account_auth_token_view.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import { ExportOutlined, SwapOutlined } from "@ant-design/icons"; | ||
import { getAuthToken, revokeAuthToken } from "admin/rest_api"; | ||
import { Button, Col, Row, Spin, Typography } from "antd"; | ||
import { useWkSelector } from "libs/react_hooks"; | ||
import Toast from "libs/toast"; | ||
import { useEffect, useState } from "react"; | ||
import { SettingsCard } from "./helpers/settings_card"; | ||
import { SettingsTitle } from "./helpers/settings_title"; | ||
|
||
const { Text } = Typography; | ||
|
||
function AccountAuthTokenView() { | ||
const activeUser = useWkSelector((state) => state.activeUser); | ||
const [isLoading, setIsLoading] = useState<boolean>(true); | ||
const [currentToken, setCurrentToken] = useState<string>(""); | ||
|
||
useEffect(() => { | ||
fetchData(); | ||
}, []); | ||
|
||
async function fetchData(): Promise<void> { | ||
try { | ||
const token = await getAuthToken(); | ||
setCurrentToken(token); | ||
} catch (error) { | ||
Toast.error("Failed to fetch auth token. Please refresh the page to try again."); | ||
console.error("Failed to fetch auth token:", error); | ||
} finally { | ||
setIsLoading(false); | ||
} | ||
} | ||
|
||
const handleRevokeToken = async (): Promise<void> => { | ||
try { | ||
setIsLoading(true); | ||
await revokeAuthToken(); | ||
const token = await getAuthToken(); | ||
setCurrentToken(token); | ||
} finally { | ||
setIsLoading(false); | ||
} | ||
}; | ||
|
||
const APIitems = [ | ||
{ | ||
title: "Auth Token", | ||
value: ( | ||
<Text code copyable> | ||
{currentToken} | ||
</Text> | ||
), | ||
}, | ||
{ | ||
title: "Token Revocation", | ||
explanation: | ||
"Revoke your token if it has been compromised or if you suspect someone else has gained access to it. This will invalidate all active sessions.", | ||
value: ( | ||
<Button icon={<SwapOutlined />} type="primary" ghost onClick={handleRevokeToken}> | ||
Revoke and Generate New Token | ||
</Button> | ||
), | ||
}, | ||
...(activeUser | ||
? [ | ||
{ | ||
title: "Organization ID", | ||
value: ( | ||
<Text code copyable> | ||
{activeUser.organization} | ||
</Text> | ||
), | ||
}, | ||
] | ||
: []), | ||
{ | ||
title: "API Documentation", | ||
value: ( | ||
<a href="https://docs.webknossos.org/webknossos-py/index.html"> | ||
Read the docs <ExportOutlined /> | ||
</a> | ||
), | ||
}, | ||
]; | ||
|
||
return ( | ||
<div> | ||
<SettingsTitle | ||
title="API Authorization" | ||
description="Access the WEBKNOSSO Python API with your API token" | ||
/> | ||
<Spin size="large" spinning={isLoading}> | ||
<Row gutter={[24, 24]} style={{ marginBottom: 24 }}> | ||
{APIitems.map((item) => ( | ||
<Col span={12} key={item.title}> | ||
<SettingsCard | ||
title={item.title} | ||
description={item.value} | ||
explanation={item.explanation} | ||
/> | ||
</Col> | ||
))} | ||
</Row> | ||
</Spin> | ||
</div> | ||
); | ||
} | ||
|
||
export default AccountAuthTokenView; |
200 changes: 200 additions & 0 deletions
200
frontend/javascripts/admin/account/account_password_view.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
import { EditOutlined, LockOutlined } from "@ant-design/icons"; | ||
import { changePassword, logoutUser } from "admin/rest_api"; | ||
import { Alert, Button, Col, Form, Input, Row, Space } from "antd"; | ||
import Toast from "libs/toast"; | ||
import messages from "messages"; | ||
import { useState } from "react"; | ||
import { useHistory } from "react-router-dom"; | ||
import { logoutUserAction } from "viewer/model/actions/user_actions"; | ||
import Store from "viewer/store"; | ||
import { SettingsCard } from "./helpers/settings_card"; | ||
import { SettingsTitle } from "./helpers/settings_title"; | ||
const FormItem = Form.Item; | ||
const { Password } = Input; | ||
|
||
const MIN_PASSWORD_LENGTH = 8; | ||
|
||
function AccountPasswordView() { | ||
const history = useHistory(); | ||
const [form] = Form.useForm(); | ||
const [isResetPasswordVisible, setResetPasswordVisible] = useState(false); | ||
|
||
function onFinish(formValues: Record<string, any>) { | ||
changePassword(formValues) | ||
.then(async () => { | ||
Toast.success(messages["auth.reset_pw_confirmation"]); | ||
await logoutUser(); | ||
Store.dispatch(logoutUserAction()); | ||
history.push("/auth/login"); | ||
}) | ||
.catch((error) => { | ||
console.error("Password change failed:", error); | ||
Toast.error("Failed to change password. Please try again."); | ||
}); | ||
} | ||
|
||
function checkPasswordsAreMatching(value: string, otherPasswordFieldKey: string[]) { | ||
const otherFieldValue = form.getFieldValue(otherPasswordFieldKey); | ||
|
||
if (value && otherFieldValue) { | ||
if (value !== otherFieldValue) { | ||
return Promise.reject(new Error(messages["auth.registration_password_mismatch"])); | ||
} else if (form.getFieldError(otherPasswordFieldKey).length > 0) { | ||
// If the other password field still has errors, revalidate it. | ||
form.validateFields([otherPasswordFieldKey]); | ||
} | ||
} | ||
|
||
return Promise.resolve(); | ||
} | ||
|
||
function getPasswordComponent() { | ||
return isResetPasswordVisible ? ( | ||
<Form onFinish={onFinish} form={form}> | ||
<FormItem | ||
name="oldPassword" | ||
rules={[ | ||
{ | ||
required: true, | ||
message: messages["auth.reset_old_password"], | ||
}, | ||
]} | ||
> | ||
<Password | ||
prefix={ | ||
<LockOutlined | ||
style={{ | ||
fontSize: 13, | ||
}} | ||
/> | ||
} | ||
placeholder="Old Password" | ||
/> | ||
</FormItem> | ||
<FormItem | ||
hasFeedback | ||
name={["password", "password1"]} | ||
rules={[ | ||
{ | ||
required: true, | ||
message: messages["auth.reset_new_password"], | ||
}, | ||
{ | ||
min: MIN_PASSWORD_LENGTH, | ||
message: messages["auth.registration_password_length"], | ||
}, | ||
{ | ||
validator: (_, value: string) => | ||
checkPasswordsAreMatching(value, ["password", "password2"]), | ||
}, | ||
]} | ||
> | ||
<Password | ||
prefix={ | ||
<LockOutlined | ||
style={{ | ||
fontSize: 13, | ||
}} | ||
/> | ||
} | ||
placeholder="New Password" | ||
/> | ||
</FormItem> | ||
<FormItem | ||
hasFeedback | ||
name={["password", "password2"]} | ||
rules={[ | ||
{ | ||
required: true, | ||
message: messages["auth.reset_new_password2"], | ||
}, | ||
{ | ||
min: MIN_PASSWORD_LENGTH, | ||
message: messages["auth.registration_password_length"], | ||
}, | ||
{ | ||
validator: (_, value: string) => | ||
checkPasswordsAreMatching(value, ["password", "password1"]), | ||
}, | ||
]} | ||
> | ||
<Password | ||
prefix={ | ||
<LockOutlined | ||
style={{ | ||
fontSize: 13, | ||
}} | ||
/> | ||
} | ||
placeholder="Confirm New Password" | ||
/> | ||
</FormItem> | ||
<Alert | ||
type="info" | ||
message={messages["auth.reset_logout"]} | ||
showIcon | ||
style={{ | ||
marginBottom: 24, | ||
}} | ||
/> | ||
<FormItem> | ||
<Space> | ||
<Button onClick={() => setResetPasswordVisible(false)}>Cancel</Button> | ||
<Button type="primary" htmlType="submit"> | ||
Update Password | ||
</Button> | ||
</Space> | ||
</FormItem> | ||
</Form> | ||
) : ( | ||
"***********" | ||
); | ||
} | ||
|
||
function handleResetPassword() { | ||
setResetPasswordVisible(true); | ||
} | ||
|
||
const passKeyList = [ | ||
{ | ||
title: "Coming soon", | ||
value: "Passwordless login with passkeys is coming soon", | ||
// action: <Button type="default" shape="circle" icon={<DeleteOutlined />} size="small" />, | ||
action: undefined, | ||
}, | ||
]; | ||
|
||
return ( | ||
<div> | ||
<SettingsTitle title="Password" description="Manage and update your password" /> | ||
<Row gutter={[24, 24]} style={{ marginBottom: 24 }}> | ||
<Col span={12}> | ||
<SettingsCard | ||
title="Password" | ||
description={getPasswordComponent()} | ||
action={ | ||
<Button | ||
type="default" | ||
shape="circle" | ||
icon={<EditOutlined />} | ||
size="small" | ||
onClick={handleResetPassword} | ||
/> | ||
} | ||
/> | ||
</Col> | ||
</Row> | ||
|
||
<SettingsTitle title="Passkeys" description="Login passwordless with Passkeys" /> | ||
<Row gutter={[24, 24]} style={{ marginBottom: 24 }}> | ||
{passKeyList.map((item) => ( | ||
<Col span={12} key={item.title}> | ||
<SettingsCard title={item.title} description={item.value} action={item.action} /> | ||
</Col> | ||
))} | ||
</Row> | ||
</div> | ||
); | ||
} | ||
|
||
export default AccountPasswordView; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.