mirror of https://github.com/logseq/logseq
Feat: The new login UI (#8865)
Built-in login UI instead of callback --------- Co-authored-by: rcmerci <rcmerci@gmail.com> Co-authored-by: Konstantinos Kaloutas <konstantinos@logseq.com> Co-authored-by: Tienson Qin <tiensonqin@gmail.com>pull/8909/head
parent
2b15702bea
commit
95c5cba9db
|
@ -0,0 +1,2 @@
|
|||
.parcel-cache
|
||||
dist
|
|
@ -0,0 +1,16 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport"
|
||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>Document</title>
|
||||
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
|
||||
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="./index.tsx"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,87 @@
|
|||
import * as React from 'react'
|
||||
import * as ReactDOM from 'react-dom'
|
||||
import { Amplify } from 'aws-amplify'
|
||||
import { Authenticator } from '@aws-amplify/ui-react'
|
||||
import '@aws-amplify/ui-react/styles.css'
|
||||
|
||||
function setupConfigure () {
|
||||
Amplify.configure({
|
||||
Auth: {
|
||||
// REQUIRED only for Federated Authentication - Amazon Cognito Identity Pool ID
|
||||
// identityPoolId: 'XX-XXXX-X:XXXXXXXX-XXXX-1234-abcd-1234567890ab',
|
||||
|
||||
// REQUIRED - Amazon Cognito Region
|
||||
region: 'us-east-1',
|
||||
|
||||
// OPTIONAL - Amazon Cognito Federated Identity Pool Region
|
||||
// Required only if it's different from Amazon Cognito Region
|
||||
// identityPoolRegion: 'XX-XXXX-X',
|
||||
|
||||
// OPTIONAL - Amazon Cognito User Pool ID
|
||||
userPoolId: 'us-east-1_ldvDmC9Fe',
|
||||
|
||||
// OPTIONAL - Amazon Cognito Web Client ID (26-char alphanumeric string)
|
||||
userPoolWebClientId: '41m82unjghlea984vjpk887qcr',
|
||||
|
||||
// OPTIONAL - Enforce user authentication prior to accessing AWS resources or not
|
||||
// mandatorySignIn: false,
|
||||
|
||||
// OPTIONAL - This is used when autoSignIn is enabled for Auth.signUp
|
||||
// 'code' is used for Auth.confirmSignUp, 'link' is used for email link verification
|
||||
// signUpVerificationMethod: 'code', // 'code' | 'link'
|
||||
|
||||
// OPTIONAL - Configuration for cookie storage
|
||||
// Note: if the secure flag is set to true, then the cookie transmission requires a secure protocol
|
||||
cookieStorage: {
|
||||
domain: 'localhost',
|
||||
path: '/',
|
||||
expires: 365,
|
||||
sameSite: 'strict',
|
||||
secure: true,
|
||||
},
|
||||
|
||||
// OPTIONAL - customized storage object
|
||||
// storage: MyStorage,
|
||||
|
||||
// OPTIONAL - Manually set the authentication flow type. Default is 'USER_SRP_AUTH'
|
||||
authenticationFlowType: 'USER_SRP_AUTH',
|
||||
|
||||
//
|
||||
// // OPTIONAL - Manually set key value pairs that can be passed to Cognito Lambda Triggers
|
||||
// clientMetadata: {myCustomKey: 'myCustomValue'},
|
||||
//
|
||||
// // OPTIONAL - Hosted UI configuration
|
||||
// oauth: {
|
||||
// domain: 'your_cognito_domain',
|
||||
// scope: ['phone', 'email', 'profile', 'openid', 'aws.cognito.signin.user.admin'],
|
||||
// redirectSignIn: 'http://localhost:3000/',
|
||||
// redirectSignOut: 'http://localhost:3000/',
|
||||
// responseType: 'code' // or 'token', note that REFRESH token will only be generated when the responseType is code
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default function App () {
|
||||
return (
|
||||
<div style={{ display: 'flex', justifyContent: 'center', height: '90vh', alignItems: 'center' }}>
|
||||
<Authenticator signUpAttributes={['email']}
|
||||
socialProviders={['google']}>
|
||||
{({ signOut, user }) => (
|
||||
<main>
|
||||
<h1>Hello {user.username}</h1>
|
||||
<button onClick={signOut}>Sign out</button>
|
||||
</main>
|
||||
)}
|
||||
</Authenticator>
|
||||
</div>)
|
||||
}
|
||||
|
||||
function main () {
|
||||
setupConfigure()
|
||||
|
||||
// mount
|
||||
ReactDOM.render(<App/>, document.getElementById('app'))
|
||||
}
|
||||
|
||||
// bootstrap
|
||||
main()
|
|
@ -0,0 +1,42 @@
|
|||
{
|
||||
"name": "logseq-amplify",
|
||||
"version": "0.0.1",
|
||||
"description": "Amplify components for Logseq",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"dev:amplify": "parcel watch ./src/amplify.ts --dist-dir ../src/main/frontend/ --no-hmr --no-source-maps",
|
||||
"dev:examples": "parcel serve ./examples/index.html",
|
||||
"build:amplify": "parcel build ./src/amplify.ts --dist-dir ../../resources/js --no-source-maps && mv ../../resources/js/amplify.css ../../resources/css/"
|
||||
},
|
||||
"devDependencies": {
|
||||
"buffer": "^5.5.0",
|
||||
"parcel": "^2.8.3",
|
||||
"punycode": "^1.4.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-amplify/ui-react": "^4.3.8",
|
||||
"aws-amplify": "^5.0.15",
|
||||
"aws-amplify-react": "^5.1.43",
|
||||
"react": "^17",
|
||||
"react-dom": "^17"
|
||||
},
|
||||
"alias": {
|
||||
"react": {
|
||||
"global": "React"
|
||||
},
|
||||
"react-dom": {
|
||||
"global": "ReactDOM"
|
||||
},
|
||||
"react/jsx-dev-runtime": "./node_modules/react/jsx-dev-runtime.js",
|
||||
"react/jsx-runtime": "./node_modules/react/jsx-runtime.js"
|
||||
},
|
||||
"targets": {
|
||||
"default": {
|
||||
"outputFormat": "global",
|
||||
"includeNodeModules": {
|
||||
"react": false,
|
||||
"react-dom": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
import { Authenticator, CheckboxField, useAuthenticator, AccountSettings } from '@aws-amplify/ui-react'
|
||||
|
||||
export function LSAuthenticator({ termsLink, children }: any) {
|
||||
return (<div>
|
||||
<Authenticator
|
||||
formFields={{
|
||||
signUp: {
|
||||
email: { order: 1 },
|
||||
username: { order: 2 },
|
||||
password: { order: 3 },
|
||||
confirm_password: { order: 4 },
|
||||
}
|
||||
}}
|
||||
loginMechanisms={['username']}
|
||||
socialProviders={['google']}
|
||||
components={{
|
||||
SignUp: {
|
||||
FormFields() {
|
||||
const { validationErrors } = useAuthenticator()
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Re-use default `Authenticator.SignUp.FormFields` */}
|
||||
<Authenticator.SignUp.FormFields/>
|
||||
|
||||
{/* Append & require Terms & Conditions field to sign up */}
|
||||
<CheckboxField
|
||||
errorMessage={validationErrors.acknowledgement as string}
|
||||
hasError={!!validationErrors.acknowledgement}
|
||||
name="acknowledgement"
|
||||
value="yes"
|
||||
label={(<a href={termsLink}>I agree with the Terms & Conditions</a>)}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
},
|
||||
},
|
||||
}}
|
||||
services={{
|
||||
async validateCustomSignUp(formData) {
|
||||
if (!formData.acknowledgement) {
|
||||
return {
|
||||
acknowledgement: '',
|
||||
}
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Authenticator>
|
||||
</div>)
|
||||
}
|
||||
|
||||
export function LSAuthenticatorChangePassword(
|
||||
{onSuccess, onError}
|
||||
) {
|
||||
return (
|
||||
<AccountSettings.ChangePassword onSuccess={onSuccess} onError={onError}/>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
import '@aws-amplify/ui-react/styles.css'
|
||||
import { Amplify, Auth, Hub, I18n } from 'aws-amplify'
|
||||
import { LSAuthenticator, LSAuthenticatorChangePassword } from './LSAuthenticator'
|
||||
import { dict } from 'aws-amplify-react/lib-esm/AmplifyI18n'
|
||||
|
||||
// fix i18n
|
||||
dict.zh['Reset Password'] = '重置密码'
|
||||
dict.zh['Enter your username'] = '请输入用户名'
|
||||
dict.zh['Enter your email'] = '请输入邮箱'
|
||||
dict.zh['Enter your password'] = '请输入密码'
|
||||
dict.zh['Confirm Password'] = '确认密码'
|
||||
dict.zh['Please confirm your Password'] = '请确认密码'
|
||||
dict.zh['Incorrect username or password.'] = '用户名或者密码不正确。如果您的邮箱未验证,请尝试使用用户名(非邮箱)登录,以保证再次邮箱验证流程。'
|
||||
|
||||
// @ts-ignore attach defaults
|
||||
dict.en = {
|
||||
'Incorrect username or password.': 'Incorrect username or password! ' +
|
||||
'For unconfirmed users, please input your username instead of Email to receive the code.'
|
||||
}
|
||||
|
||||
const fixesMapping = {
|
||||
'Sign Up': ['Sign up', 'Create Account'],
|
||||
'Sign In': ['Sign in'],
|
||||
'Sign Out': 'Sign out',
|
||||
'Send Code': 'Send code',
|
||||
'Forgot Password': ['Forgot your password?'],
|
||||
'Enter your email': ['Enter your Email'],
|
||||
'Enter your password': ['Enter your Password'],
|
||||
'Enter your username': ['Enter your Username']
|
||||
}
|
||||
|
||||
Object.keys(dict).forEach((k) => {
|
||||
const target = dict[k]
|
||||
Object.entries(fixesMapping).forEach(([k1, v1]) => {
|
||||
if (target?.hasOwnProperty(k1)) {
|
||||
const vs = Array.isArray(v1) ? v1 : [v1]
|
||||
vs.forEach(it => {
|
||||
target[it] = target[k1]
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
I18n.putVocabularies(dict)
|
||||
|
||||
function setupAuthConfigure(config) {
|
||||
|
||||
const {
|
||||
region,
|
||||
userPoolId,
|
||||
userPoolWebClientId,
|
||||
identityPoolId,
|
||||
oauthDomain,
|
||||
oauthProviders
|
||||
} = config
|
||||
|
||||
Amplify.configure({
|
||||
'aws_project_region': region,
|
||||
'aws_cognito_identity_pool_id': identityPoolId,
|
||||
'aws_cognito_region': region,
|
||||
'aws_user_pools_id': userPoolId,
|
||||
'aws_user_pools_web_client_id': userPoolWebClientId,
|
||||
'authenticationFlowType': 'USER_SRP_AUTH',
|
||||
'oauth': {
|
||||
'domain': oauthDomain,
|
||||
'scope': [
|
||||
'phone',
|
||||
'email',
|
||||
'openid',
|
||||
'profile',
|
||||
'aws.cognito.signin.user.admin'
|
||||
],
|
||||
'redirectSignIn': 'https://logseq.com/public/auth_callback.html',
|
||||
'redirectSignOut': 'https://logseq.com/public/auth_callback.html',
|
||||
'responseType': 'code'
|
||||
},
|
||||
'federationTarget': 'COGNITO_USER_POOLS',
|
||||
'aws_cognito_social_providers': oauthProviders || [
|
||||
'GOOGLE'
|
||||
],
|
||||
'aws_cognito_signup_attributes': [
|
||||
'EMAIL'
|
||||
],
|
||||
'aws_cognito_password_protection_settings': {
|
||||
'passwordPolicyMinLength': 8,
|
||||
'passwordPolicyCharacters': []
|
||||
},
|
||||
'aws_cognito_verification_mechanisms': [
|
||||
'EMAIL'
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
window.LSAmplify = {
|
||||
setupAuthConfigure,
|
||||
LSAuthenticator, LSAuthenticatorChangePassword,
|
||||
Auth, Amplify, Hub, I18n
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -51,6 +51,7 @@
|
|||
<script defer src="/static/js/highlight.min.js"></script>
|
||||
<script defer src="/static/js/interact.min.js"></script>
|
||||
<script defer src="/static/js/main.js"></script>
|
||||
<script defer src="/static/js/amplify.js"></script>
|
||||
<script defer src="/static/js/tabler.min.js"></script>
|
||||
<script defer src="/static/js/code-editor.js"></script>
|
||||
<script defer src="/static/js/tldraw.js"></script>
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -52,6 +52,7 @@ const portal = new MagicPortal(worker);
|
|||
<script defer src="./js/interact.min.js"></script>
|
||||
<script defer src="./js/lsplugin.core.js"></script>
|
||||
<script defer src="./js/main.js"></script>
|
||||
<script defer src="./js/amplify.js"></script>
|
||||
<script defer src="./js/tabler.min.js"></script>
|
||||
<script defer src="./js/code-editor.js"></script>
|
||||
<script defer src="./js/excalidraw.js"></script>
|
||||
|
|
|
@ -51,6 +51,7 @@ const portal = new MagicPortal(worker);
|
|||
<script defer src="./js/interact.min.js"></script>
|
||||
<script defer src="./js/lsplugin.core.js"></script>
|
||||
<script defer src="./js/main.js"></script>
|
||||
<script defer src="./js/amplify.js"></script>
|
||||
<script defer src="./js/tabler.min.js"></script>
|
||||
<script defer src="./js/code-editor.js"></script>
|
||||
<script defer src="./js/excalidraw.js"></script>
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -90,9 +90,6 @@
|
|||
[^js win parsed-url]
|
||||
(let [url-host (.-host parsed-url)] ;; return "" when no pathname provided
|
||||
(cond
|
||||
(= "auth-callback" url-host)
|
||||
(send-to-renderer win "loginCallback" (.get (.-searchParams parsed-url) "code"))
|
||||
|
||||
(= "x-callback-url" url-host)
|
||||
(x-callback-url-handler win parsed-url)
|
||||
|
||||
|
|
|
@ -46,10 +46,12 @@
|
|||
(when-not (or config/publishing?
|
||||
logged?
|
||||
(not sync-enabled?))
|
||||
[:a.button.text-sm.font-medium.block {:on-click #(js/window.open config/LOGIN-URL)}
|
||||
[:span.flex.space-x-2
|
||||
[:a.button.text-sm.font-medium.block
|
||||
{:on-click #(state/pub-event! [:user/login])}
|
||||
[:span (t :login)]
|
||||
(when loading?
|
||||
[:span.ml-2 (ui/loading "")])])))
|
||||
[:span.ml-2 (ui/loading "")])]])))
|
||||
|
||||
(rum/defc left-menu-button < rum/reactive
|
||||
< {:key-fn #(identity "left-menu-toggle-button")}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
import {Amplify} from '@aws-amplify/core';
|
||||
|
||||
Amplify.configure({
|
||||
Auth: {
|
||||
// REQUIRED only for Federated Authentication - Amazon Cognito Identity Pool ID
|
||||
// identityPoolId: 'XX-XXXX-X:XXXXXXXX-XXXX-1234-abcd-1234567890ab',
|
||||
|
||||
// REQUIRED - Amazon Cognito Region
|
||||
region: 'us-east-1',
|
||||
|
||||
// OPTIONAL - Amazon Cognito Federated Identity Pool Region
|
||||
// Required only if it's different from Amazon Cognito Region
|
||||
// identityPoolRegion: 'XX-XXXX-X',
|
||||
|
||||
// OPTIONAL - Amazon Cognito User Pool ID
|
||||
userPoolId: 'us-east-1_ldvDmC9Fe',
|
||||
|
||||
// OPTIONAL - Amazon Cognito Web Client ID (26-char alphanumeric string)
|
||||
userPoolWebClientId: '41m82unjghlea984vjpk887qcr',
|
||||
|
||||
// OPTIONAL - Enforce user authentication prior to accessing AWS resources or not
|
||||
// mandatorySignIn: false,
|
||||
|
||||
// OPTIONAL - This is used when autoSignIn is enabled for Auth.signUp
|
||||
// 'code' is used for Auth.confirmSignUp, 'link' is used for email link verification
|
||||
// signUpVerificationMethod: 'code', // 'code' | 'link'
|
||||
|
||||
// OPTIONAL - Configuration for cookie storage
|
||||
// Note: if the secure flag is set to true, then the cookie transmission requires a secure protocol
|
||||
cookieStorage: {
|
||||
domain: "localhost",
|
||||
path: "/",
|
||||
expires: 365,
|
||||
sameSite: "strict",
|
||||
secure: true,
|
||||
},
|
||||
|
||||
// OPTIONAL - customized storage object
|
||||
// storage: MyStorage,
|
||||
|
||||
// OPTIONAL - Manually set the authentication flow type. Default is 'USER_SRP_AUTH'
|
||||
authenticationFlowType: 'USER_SRP_AUTH',
|
||||
|
||||
//
|
||||
// // OPTIONAL - Manually set key value pairs that can be passed to Cognito Lambda Triggers
|
||||
// clientMetadata: {myCustomKey: 'myCustomValue'},
|
||||
//
|
||||
// // OPTIONAL - Hosted UI configuration
|
||||
// oauth: {
|
||||
// domain: 'your_cognito_domain',
|
||||
// scope: ['phone', 'email', 'profile', 'openid', 'aws.cognito.signin.user.admin'],
|
||||
// redirectSignIn: 'http://localhost:3000/',
|
||||
// redirectSignOut: 'http://localhost:3000/',
|
||||
// responseType: 'code' // or 'token', note that REFRESH token will only be generated when the responseType is code
|
||||
}
|
||||
});
|
|
@ -0,0 +1,87 @@
|
|||
(ns frontend.components.user.login
|
||||
(:require [rum.core :as rum]
|
||||
[frontend.rum :refer [adapt-class]]
|
||||
[frontend.modules.shortcut.core :as shortcut]
|
||||
[frontend.handler.user :as user]
|
||||
[cljs-bean.core :as bean]
|
||||
[frontend.handler.notification :as notification]
|
||||
[frontend.state :as state]
|
||||
[frontend.config :as config]))
|
||||
|
||||
(declare setupAuthConfigure! LSAuthenticator)
|
||||
|
||||
(defn sign-out!
|
||||
[]
|
||||
(try (.signOut js/LSAmplify.Auth)
|
||||
(catch :default e (js/console.warn e))))
|
||||
|
||||
(defn- setup-configure!
|
||||
[]
|
||||
#_:clj-kondo/ignore
|
||||
(def setupAuthConfigure! (.-setupAuthConfigure js/LSAmplify))
|
||||
#_:clj-kondo/ignore
|
||||
(def LSAuthenticator
|
||||
(adapt-class (.-LSAuthenticator js/LSAmplify)))
|
||||
|
||||
(.setLanguage js/LSAmplify.I18n (or (:preferred-language @state/state) "en"))
|
||||
(setupAuthConfigure!
|
||||
#js {:region config/REGION,
|
||||
:userPoolId config/USER-POOL-ID,
|
||||
:userPoolWebClientId config/COGNITO-CLIENT-ID,
|
||||
:identityPoolId config/IDENTITY-POOL-ID,
|
||||
:oauthDomain config/OAUTH-DOMAIN}))
|
||||
|
||||
(rum/defc user-pane
|
||||
[_sign-out! user]
|
||||
(let [session (:signInUserSession user)
|
||||
username (:username user)]
|
||||
|
||||
(rum/use-effect!
|
||||
(fn []
|
||||
(when session
|
||||
(user/login-callback session)
|
||||
(notification/show! (str "Hi, " username " :)") :success)
|
||||
(state/close-modal!)))
|
||||
[])
|
||||
|
||||
nil))
|
||||
|
||||
(rum/defc page-impl
|
||||
[]
|
||||
(let [[ready?, set-ready?] (rum/use-state false)
|
||||
*ref-el (rum/use-ref nil)]
|
||||
|
||||
(rum/use-effect!
|
||||
(fn [] (setup-configure!)
|
||||
(set-ready? true)
|
||||
(when-let [^js el (rum/deref *ref-el)]
|
||||
(js/setTimeout #(some-> (.querySelector el "input[name=username]")
|
||||
(.focus)) 100))) [])
|
||||
|
||||
[:div.cp__user-login
|
||||
{:ref *ref-el}
|
||||
(when ready?
|
||||
(LSAuthenticator
|
||||
{:termsLink "https://blog.logseq.com/terms/"}
|
||||
(fn [^js op]
|
||||
(let [sign-out! (.-signOut op)
|
||||
^js user-proxy (.-user op)
|
||||
^js user (try (js/JSON.parse (js/JSON.stringify user-proxy))
|
||||
(catch js/Error e
|
||||
(js/console.error "Error: Amplify user payload:" e)))
|
||||
user' (bean/->clj user)]
|
||||
(user-pane sign-out! user')))))]))
|
||||
|
||||
(rum/defcs page <
|
||||
(shortcut/disable-all-shortcuts)
|
||||
[_state]
|
||||
(page-impl))
|
||||
|
||||
(defn open-login-modal!
|
||||
[]
|
||||
(state/set-modal!
|
||||
(fn [_close] (page))
|
||||
{:close-btn? true
|
||||
:label "user-login"
|
||||
:close-backdrop? false
|
||||
:center? true}))
|
|
@ -0,0 +1,135 @@
|
|||
.cp__user-login {
|
||||
[data-amplify-authenticator] [data-amplify-router] {
|
||||
--amplify-components-authenticator-router-background-color: var(--ls-primary-background-color);
|
||||
--amplify-components-field-label-color: var(--ls-primary-text-color);
|
||||
--amplify-components-authenticator-router-border-color: var(--ls-border-color);
|
||||
--amplify-components-tabs-item-color: var(--ls-primary-text-color);
|
||||
--amplify-components-tabs-item-active-color: var(--ls-primary-text-color);
|
||||
--amplify-components-tabs-item-hover-color: var(--ls-primary-text-color);
|
||||
--amplify-components-tabs-item-active-border-color: var(--ls-tertiary-background-color);
|
||||
--amplify-components-tabs-border-width: 0;
|
||||
--amplify-components-authenticator-state-inactive-background-color: var(--ls-tertiary-background-color);
|
||||
--amplify-components-tabs-item-active-background-color: var(--ls-primary-background-color);
|
||||
--amplify-components-button-border-color: var(--ls-border-color);
|
||||
--amplify-components-textfield-border-color: var(--ls-border-color);
|
||||
--amplify-components-button-primary-background-color: var(--color-indigo-600);
|
||||
--amplify-components-text-color: var(--ls-primary-text-color);
|
||||
--amplify-components-button-hover-background-color: var(--ls-primary-background-color);
|
||||
--amplify-components-button-border-width: 0;
|
||||
--amplify-internal-button-loading-background-color: var(--ls-header-button-background);
|
||||
--amplify-components-authenticator-router-border-width: 1px;
|
||||
--amplify-components-button-color: var(--ls-primary-text-color);
|
||||
--amplify-components-divider-label-background-color: var(--ls-primary-background-color);
|
||||
--amplify-components-divider-label-color: var(--ls-primary-text-color);
|
||||
--amplify-components-heading-color: var(--ls-primary-text-color);
|
||||
--amplify-components-button-link-hover-background-color: transparent;
|
||||
--amplify-components-button-link-active-background-color: transparent;
|
||||
--amplify-components-textfield-color: var(--ls-primary-text-color);
|
||||
--amplify-components-checkbox-icon-background-color: var(--color-indigo-600);
|
||||
}
|
||||
|
||||
[data-amplify-authenticator] [data-amplify-router] {
|
||||
@apply overflow-hidden rounded-[6px] shadow-2xl;
|
||||
}
|
||||
|
||||
[data-amplify-authenticator] [data-amplify-container] {
|
||||
place-self: unset;
|
||||
}
|
||||
|
||||
[data-amplify-authenticator] [data-amplify-form] {
|
||||
@apply px-4 py-2;
|
||||
|
||||
@screen sm {
|
||||
@apply px-6 py-4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ui__modal[label=user-login] {
|
||||
@apply flex items-center top-0;
|
||||
|
||||
.ui__modal-panel {
|
||||
transition: transform .3s;
|
||||
transform: translateY(-50px);
|
||||
}
|
||||
|
||||
.panel-content {
|
||||
@apply p-0 min-w-fit relative max-w-[600px] sm:max-w-[90vw] w-auto;
|
||||
}
|
||||
|
||||
.ui__modal-close-wrap {
|
||||
@apply z-10 top-[4px];
|
||||
}
|
||||
}
|
||||
|
||||
.cp__user {
|
||||
&-login {
|
||||
::placeholder {
|
||||
color: var(--ls-primary-text-color);
|
||||
opacity: .3;
|
||||
}
|
||||
|
||||
[data-indicator-position=top] > .amplify-tabs-item {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.amplify-tabs-item {
|
||||
transition: none;
|
||||
|
||||
&:focus {
|
||||
color: var(--ls-primary-text-color);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
opacity: .9;
|
||||
}
|
||||
}
|
||||
|
||||
.amplify-field-group {
|
||||
@apply relative;
|
||||
|
||||
.amplify-button {
|
||||
color: var(--ls-primary-text-color);
|
||||
|
||||
&:active, &:hover, &:focus {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.amplify-field-group__outer-end {
|
||||
@apply absolute right-0 top-0 bottom-0;
|
||||
}
|
||||
|
||||
.amplify-input {
|
||||
border-radius: 4px !important;
|
||||
}
|
||||
|
||||
.amplify-checkboxfield {
|
||||
@apply text-sm;
|
||||
|
||||
.amplify-field__error-message {
|
||||
color: var(--ls-primary-text-color);
|
||||
opacity: .4;
|
||||
}
|
||||
}
|
||||
|
||||
.amplify-text--error {
|
||||
color: var(--ls-error-text-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
html {
|
||||
&.is-mobile .ui__modal[label=user-login] .panel-content {
|
||||
@apply pt-0;
|
||||
}
|
||||
|
||||
&.has-mobile-keyboard .ui__modal[label=user-login] {
|
||||
transform: translateY(calc(-50px - 6%));
|
||||
}
|
||||
}
|
||||
|
||||
.federated-sign-in-container {
|
||||
display: none;
|
||||
}
|
|
@ -32,14 +32,24 @@
|
|||
"https://logseq-prod.auth.us-east-1.amazoncognito.com/login?client_id=3c7np6bjtb4r1k1bi9i049ops5&response_type=code&scope=email+openid+phone&redirect_uri=logseq%3A%2F%2Fauth-callback")
|
||||
(def API-DOMAIN "api.logseq.com")
|
||||
(def WS-URL "wss://ws.logseq.com/file-sync?graphuuid=%s")
|
||||
(def COGNITO-IDP "https://cognito-idp.us-east-1.amazonaws.com/"))
|
||||
(def COGNITO-IDP "https://cognito-idp.us-east-1.amazonaws.com/")
|
||||
(def COGNITO-CLIENT-ID "69cs1lgme7p8kbgld8n5kseii6")
|
||||
(def REGION "us-east-1")
|
||||
(def USER-POOL-ID "us-east-1_dtagLnju8")
|
||||
(def IDENTITY-POOL-ID "us-east-1:d6d3b034-1631-402b-b838-b44513e93ee0")
|
||||
(def OAUTH-DOMAIN "logseq-prod.auth.us-east-1.amazoncognito.com"))
|
||||
|
||||
(do (def FILE-SYNC-PROD? false)
|
||||
(def LOGIN-URL
|
||||
"https://logseq-test2.auth.us-east-2.amazoncognito.com/login?client_id=3ji1a0059hspovjq5fhed3uil8&response_type=code&scope=email+openid+phone&redirect_uri=logseq%3A%2F%2Fauth-callback")
|
||||
(def API-DOMAIN "api-dev.logseq.com")
|
||||
(def WS-URL "wss://ws-dev.logseq.com/file-sync?graphuuid=%s")
|
||||
(def COGNITO-IDP "https://cognito-idp.us-east-2.amazonaws.com/")))
|
||||
(def COGNITO-IDP "https://cognito-idp.us-east-2.amazonaws.com/")
|
||||
(def COGNITO-CLIENT-ID "1qi1uijg8b6ra70nejvbptis0q")
|
||||
(def REGION "us-east-2")
|
||||
(def USER-POOL-ID "us-east-2_kAqZcxIeM")
|
||||
(def IDENTITY-POOL-ID "us-east-2:cc7d2ad3-84d0-4faf-98fe-628f6b52c0a5")
|
||||
(def OAUTH-DOMAIN "logseq-test2.auth.us-east-2.amazoncognito.com")))
|
||||
|
||||
;; Feature flags
|
||||
;; =============
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
[frontend.components.search :as component-search]
|
||||
[frontend.components.shell :as shell]
|
||||
[frontend.components.whiteboard :as whiteboard]
|
||||
[frontend.components.user.login :as login]
|
||||
[frontend.config :as config]
|
||||
[frontend.context.i18n :refer [t]]
|
||||
[frontend.db :as db]
|
||||
|
@ -121,7 +122,13 @@
|
|||
(defmethod handle :user/logout [[_]]
|
||||
(file-sync-handler/reset-session-graphs)
|
||||
(sync/remove-all-pwd!)
|
||||
(file-sync-handler/reset-user-state!))
|
||||
(file-sync-handler/reset-user-state!)
|
||||
(login/sign-out!))
|
||||
|
||||
(defmethod handle :user/login [[_ host-ui?]]
|
||||
(if (or host-ui? (not util/electron?))
|
||||
(js/window.open config/LOGIN-URL)
|
||||
(login/open-login-modal!)))
|
||||
|
||||
(defmethod handle :graph/added [[_ repo {:keys [empty-graph?]}]]
|
||||
(db/set-key-value repo :ast/version db-schema/ast-version)
|
||||
|
@ -468,7 +475,8 @@
|
|||
(reset! util/keyboard-height keyboard-height)
|
||||
(set! (.. main-node -style -marginBottom) (str keyboard-height "px"))
|
||||
(when-let [^js html (js/document.querySelector ":root")]
|
||||
(.setProperty (.-style html) "--ls-native-kb-height" (str keyboard-height "px")))
|
||||
(.setProperty (.-style html) "--ls-native-kb-height" (str keyboard-height "px"))
|
||||
(.add (.-classList html) "has-mobile-keyboard"))
|
||||
(when-let [left-sidebar-node (gdom/getElement "left-sidebar")]
|
||||
(set! (.. left-sidebar-node -style -bottom) (str keyboard-height "px")))
|
||||
(when-let [right-sidebar-node (gdom/getElementByClass "sidebar-item-list")]
|
||||
|
@ -490,7 +498,8 @@
|
|||
(state/set-state! :mobile/show-recording-bar? false))
|
||||
(when (mobile-util/native-ios?)
|
||||
(when-let [^js html (js/document.querySelector ":root")]
|
||||
(.removeProperty (.-style html) "--ls-native-kb-height"))
|
||||
(.removeProperty (.-style html) "--ls-native-kb-height")
|
||||
(.remove (.-classList html) "has-mobile-keyboard"))
|
||||
(when-let [card-preview-el (js/document.querySelector ".cards-review")]
|
||||
(set! (.. card-preview-el -style -marginBottom) "0px"))
|
||||
(when-let [card-preview-el (js/document.querySelector ".encryption-password")]
|
||||
|
|
|
@ -107,14 +107,20 @@
|
|||
(state/set-auth-refresh-token refresh-token)
|
||||
(set-token-to-localstorage! id-token access-token refresh-token)))
|
||||
|
||||
(defn- <refresh-tokens
|
||||
"return refreshed id-token, access-token"
|
||||
[refresh-token]
|
||||
(http/post (str "https://" config/OAUTH-DOMAIN "/oauth2/token")
|
||||
{:form-params {:grant_type "refresh_token"
|
||||
:client_id config/COGNITO-CLIENT-ID
|
||||
:refresh_token refresh-token}}))
|
||||
|
||||
(defn <refresh-id-token&access-token
|
||||
"Refresh id-token and access-token"
|
||||
[]
|
||||
(go
|
||||
(when-let [refresh-token (state/get-auth-refresh-token)]
|
||||
(let [resp (<! (http/get (str "https://" config/API-DOMAIN "/auth_refresh_token?refresh_token=" refresh-token)
|
||||
{:with-credentials? false}))]
|
||||
(let [resp (<! (<refresh-tokens refresh-token))]
|
||||
(cond
|
||||
(and (<= 400 (:status resp))
|
||||
(> 500 (:status resp)))
|
||||
|
@ -146,17 +152,13 @@
|
|||
;; refresh remote graph list by pub login event
|
||||
(when (user-uuid) (state/pub-event! [:user/fetch-info-and-graphs]))))))
|
||||
|
||||
(defn ^:export login-callback [code]
|
||||
(state/set-state! [:ui/loading? :login] true)
|
||||
(go
|
||||
(let [resp (<! (http/get (str "https://" config/API-DOMAIN "/auth_callback?code=" code)
|
||||
{:with-credentials? false}))]
|
||||
(if (= 200 (:status resp))
|
||||
(-> resp
|
||||
:body
|
||||
(as-> $ (set-tokens! (:id_token $) (:access_token $) (:refresh_token $)))
|
||||
(#(state/pub-event! [:user/fetch-info-and-graphs])))
|
||||
(debug/pprint "login-callback" resp)))))
|
||||
(defn login-callback
|
||||
[session]
|
||||
(set-tokens!
|
||||
(:jwtToken (:idToken session))
|
||||
(:jwtToken (:accessToken session))
|
||||
(:token (:refreshToken session)))
|
||||
(state/pub-event! [:user/fetch-info-and-graphs]))
|
||||
|
||||
(defn ^:export login-with-username-password-e2e
|
||||
[username password client-id client-secret]
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
[frontend.handler.editor :as editor-handler]
|
||||
[frontend.handler.notification :as notification]
|
||||
[frontend.handler.route :as route-handler]
|
||||
[frontend.handler.user :as user-handler]
|
||||
[frontend.mobile.intent :as intent]
|
||||
[frontend.state :as state]
|
||||
[frontend.util.text :as text-util]))
|
||||
|
@ -30,10 +29,6 @@
|
|||
(map :url))
|
||||
repo-names (map #(get-graph-name-fn %) repos)]
|
||||
(cond
|
||||
(= hostname "auth-callback")
|
||||
(when-let [code (.get search-params "code")]
|
||||
(user-handler/login-callback code))
|
||||
|
||||
(= hostname "graph")
|
||||
(let [graph-name (some-> pathname
|
||||
(string/replace "/" "")
|
||||
|
|
|
@ -12,7 +12,8 @@
|
|||
[frontend.components.shortcut :as shortcut]
|
||||
[frontend.components.whiteboard :as whiteboard]
|
||||
[frontend.extensions.zotero :as zotero]
|
||||
[frontend.components.bug-report :as bug-report]))
|
||||
[frontend.components.bug-report :as bug-report]
|
||||
[frontend.components.user.login :as login]))
|
||||
|
||||
;; http://localhost:3000/#?anchor=fn.1
|
||||
(def routes
|
||||
|
@ -94,4 +95,8 @@
|
|||
|
||||
["/plugins"
|
||||
{:name :plugins
|
||||
:view plugins/plugins-page}]])
|
||||
:view plugins/plugins-page}]
|
||||
|
||||
["/login"
|
||||
{:name :user-login
|
||||
:view login/page}]])
|
||||
|
|
|
@ -563,9 +563,9 @@
|
|||
"entered" "ease-out duration-300 opacity-100 translate-y-0 sm:scale-100"
|
||||
"exiting" "ease-in duration-200 opacity-100 translate-y-0 sm:scale-100"
|
||||
"exited" "ease-in duration-200 opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95")}
|
||||
[:div.absolute.top-0.right-0.pt-2.pr-2
|
||||
[:div.ui__modal-close-wrap
|
||||
(when-not (false? close-btn?)
|
||||
[:a.ui__modal-close.opacity-60.hover:opacity-100
|
||||
[:a.ui__modal-close
|
||||
{:aria-label "Close"
|
||||
:type "button"
|
||||
:on-click close-fn}
|
||||
|
|
|
@ -146,7 +146,12 @@
|
|||
&-close {
|
||||
@apply text-gray-400 hover:text-gray-500
|
||||
focus:outline-none focus:text-gray-500
|
||||
transition ease-in-out duration-150;
|
||||
transition ease-in-out duration-150 opacity-60
|
||||
hover:opacity-100;
|
||||
|
||||
&-wrap {
|
||||
@apply absolute top-0 right-0 pt-2 pr-2;
|
||||
}
|
||||
}
|
||||
|
||||
&[label="ls-modal-align-center"] {
|
||||
|
@ -200,8 +205,7 @@
|
|||
|
||||
html.is-native-android,
|
||||
html.is-native-iphone,
|
||||
html.is-native-iphone-without-notch
|
||||
{
|
||||
html.is-native-iphone-without-notch {
|
||||
.references {
|
||||
.blocks-container {
|
||||
transform: translateX(-8px);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
@import "resources/css/shepherd.css";
|
||||
@import "resources/css/fonts.css";
|
||||
@import "resources/css/excalidraw.min.css";
|
||||
@import "resources/css/amplify.css";
|
||||
@import "tldraw/apps/tldraw-logseq/src/styles.css";
|
||||
@import "resources/css/katex.min.css";
|
||||
@import "resources/css/codemirror.min.css";
|
||||
|
|
Loading…
Reference in New Issue