parent
2ada968439
commit
4ddf47f3da
|
@ -8,14 +8,17 @@ import { updateCustomEmojiForInstance } from './emoji'
|
||||||
import { database } from '../_database/database'
|
import { database } from '../_database/database'
|
||||||
import { DOMAIN_BLOCKS } from '../_static/blocks'
|
import { DOMAIN_BLOCKS } from '../_static/blocks'
|
||||||
|
|
||||||
const REDIRECT_URI = process.browser && `${location.origin}/settings/instances/add`
|
|
||||||
|
|
||||||
function createKnownError (message) {
|
function createKnownError (message) {
|
||||||
const err = new Error(message)
|
const err = new Error(message)
|
||||||
err.knownError = true
|
err.knownError = true
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getRedirectUri () {
|
||||||
|
const { copyPasteMode } = store.get()
|
||||||
|
return copyPasteMode ? 'urn:ietf:wg:oauth:2.0:oob' : `${location.origin}/settings/instances/add`
|
||||||
|
}
|
||||||
|
|
||||||
async function redirectToOauth () {
|
async function redirectToOauth () {
|
||||||
let { instanceNameInSearch, loggedInInstances } = store.get()
|
let { instanceNameInSearch, loggedInInstances } = store.get()
|
||||||
instanceNameInSearch = instanceNameInSearch.replace(/^https?:\/\//, '').replace(/\/+$/, '').toLowerCase()
|
instanceNameInSearch = instanceNameInSearch.replace(/^https?:\/\//, '').replace(/\/+$/, '').toLowerCase()
|
||||||
|
@ -26,7 +29,8 @@ async function redirectToOauth () {
|
||||||
if (DOMAIN_BLOCKS.some(domain => new RegExp(`(?:\\.|^)${domain}$`, 'i').test(instanceHostname))) {
|
if (DOMAIN_BLOCKS.some(domain => new RegExp(`(?:\\.|^)${domain}$`, 'i').test(instanceHostname))) {
|
||||||
throw createKnownError('This service is blocked')
|
throw createKnownError('This service is blocked')
|
||||||
}
|
}
|
||||||
const registrationPromise = registerApplication(instanceNameInSearch, REDIRECT_URI)
|
const redirectUri = getRedirectUri()
|
||||||
|
const registrationPromise = registerApplication(instanceNameInSearch, redirectUri)
|
||||||
const instanceInfo = await getInstanceInfo(instanceNameInSearch)
|
const instanceInfo = await getInstanceInfo(instanceNameInSearch)
|
||||||
await database.setInstanceInfo(instanceNameInSearch, instanceInfo) // cache for later
|
await database.setInstanceInfo(instanceNameInSearch, instanceInfo) // cache for later
|
||||||
const instanceData = await registrationPromise
|
const instanceData = await registrationPromise
|
||||||
|
@ -38,11 +42,16 @@ async function redirectToOauth () {
|
||||||
const oauthUrl = generateAuthLink(
|
const oauthUrl = generateAuthLink(
|
||||||
instanceNameInSearch,
|
instanceNameInSearch,
|
||||||
instanceData.client_id,
|
instanceData.client_id,
|
||||||
REDIRECT_URI
|
redirectUri
|
||||||
)
|
)
|
||||||
// setTimeout to allow the browser to *actually* save the localStorage data (fixes Safari bug apparently)
|
// setTimeout to allow the browser to *actually* save the localStorage data (fixes Safari bug apparently)
|
||||||
|
const { copyPasteMode } = store.get()
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
if (copyPasteMode) {
|
||||||
|
window.open(oauthUrl, '_blank', 'noopener')
|
||||||
|
} else {
|
||||||
document.location.href = oauthUrl
|
document.location.href = oauthUrl
|
||||||
|
}
|
||||||
}, 200)
|
}, 200)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,12 +81,13 @@ export async function logInToInstance () {
|
||||||
|
|
||||||
async function registerNewInstance (code) {
|
async function registerNewInstance (code) {
|
||||||
const { currentRegisteredInstanceName, currentRegisteredInstance } = store.get()
|
const { currentRegisteredInstanceName, currentRegisteredInstance } = store.get()
|
||||||
|
const redirectUri = getRedirectUri()
|
||||||
const instanceData = await getAccessTokenFromAuthCode(
|
const instanceData = await getAccessTokenFromAuthCode(
|
||||||
currentRegisteredInstanceName,
|
currentRegisteredInstanceName,
|
||||||
currentRegisteredInstance.client_id,
|
currentRegisteredInstance.client_id,
|
||||||
currentRegisteredInstance.client_secret,
|
currentRegisteredInstance.client_secret,
|
||||||
code,
|
code,
|
||||||
REDIRECT_URI
|
redirectUri
|
||||||
)
|
)
|
||||||
const { loggedInInstances, loggedInInstancesInOrder, instanceThemes } = store.get()
|
const { loggedInInstances, loggedInInstancesInOrder, instanceThemes } = store.get()
|
||||||
instanceThemes[currentRegisteredInstanceName] = DEFAULT_THEME
|
instanceThemes[currentRegisteredInstanceName] = DEFAULT_THEME
|
||||||
|
@ -92,7 +102,8 @@ async function registerNewInstance (code) {
|
||||||
loggedInInstances: loggedInInstances,
|
loggedInInstances: loggedInInstances,
|
||||||
currentInstance: currentRegisteredInstanceName,
|
currentInstance: currentRegisteredInstanceName,
|
||||||
loggedInInstancesInOrder: loggedInInstancesInOrder,
|
loggedInInstancesInOrder: loggedInInstancesInOrder,
|
||||||
instanceThemes: instanceThemes
|
instanceThemes: instanceThemes,
|
||||||
|
copyPasteMode: false
|
||||||
})
|
})
|
||||||
store.save()
|
store.save()
|
||||||
const { enableGrayscale } = store.get()
|
const { enableGrayscale } = store.get()
|
||||||
|
@ -113,3 +124,16 @@ export async function handleOauthCode (code) {
|
||||||
store.set({ logInToInstanceLoading: false })
|
store.set({ logInToInstanceLoading: false })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function handleCopyPasteOauthCode (code) {
|
||||||
|
const { currentRegisteredInstanceName, currentRegisteredInstance } = store.get()
|
||||||
|
if (!currentRegisteredInstanceName || !currentRegisteredInstance) {
|
||||||
|
store.set({
|
||||||
|
logInToInstanceError: 'You must log in to an instance first.',
|
||||||
|
logInToInstanceErrorForText: '',
|
||||||
|
instanceNameInSearch: ''
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
await handleOauthCode(code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
40
src/routes/_components/InfoAside.html
Normal file
40
src/routes/_components/InfoAside.html
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
<aside class="info-aside {className}">
|
||||||
|
<SvgIcon href="#fa-info-circle" className="aside-icon" />
|
||||||
|
<span>
|
||||||
|
<slot></slot>
|
||||||
|
</span>
|
||||||
|
</aside>
|
||||||
|
<style>
|
||||||
|
.info-aside {
|
||||||
|
font-size: 1.2em;
|
||||||
|
color: var(--deemphasized-text-color);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
:global(.info-aside a) {
|
||||||
|
text-decoration: underline;
|
||||||
|
color: var(--deemphasized-text-color);
|
||||||
|
}
|
||||||
|
:global(.info-aside span) {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
:global(.aside-icon) {
|
||||||
|
fill: var(--deemphasized-text-color);
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
margin: 0 10px 0 5px;
|
||||||
|
min-width: 18px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
import SvgIcon from './SvgIcon.html'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data: () => ({
|
||||||
|
className: ''
|
||||||
|
}),
|
||||||
|
components: {
|
||||||
|
SvgIcon
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -1,7 +1,8 @@
|
||||||
<SettingsLayout page='settings/instances/add' label="Add instance">
|
<SettingsLayout page='settings/instances/add' label="Add instance">
|
||||||
<h1 id="add-an-instance-h1">Add instance</h1>
|
<h1 id="add-an-instance-h1">Add instance</h1>
|
||||||
|
|
||||||
<form class="add-new-instance" on:submit='onSubmit(event)' aria-labelledby="add-an-instance-h1">
|
<div class="add-new-instance">
|
||||||
|
<form on:submit='onSubmitInstance(event)' aria-labelledby="add-an-instance-h1">
|
||||||
|
|
||||||
{#if !hasIndexedDB || !hasLocalStorage}
|
{#if !hasIndexedDB || !hasLocalStorage}
|
||||||
<div class="form-error form-error-user-error" role="alert">
|
<div class="form-error form-error-user-error" role="alert">
|
||||||
|
@ -23,16 +24,30 @@
|
||||||
</div>
|
</div>
|
||||||
</noscript>
|
</noscript>
|
||||||
|
|
||||||
<label class="add-new-instance-label" for="instanceInput">Instance:</label>
|
<label for="instanceInput">Instance:</label>
|
||||||
<input class="add-new-instance-input" type="text" inputmode="url" id="instanceInput"
|
<input type="text" inputmode="url" id="instanceInput"
|
||||||
bind:value='$instanceNameInSearch' placeholder="Enter instance name" required
|
bind:value='$instanceNameInSearch' placeholder="Enter instance name" required
|
||||||
>
|
>
|
||||||
<button class="primary add-new-instance-button" type="submit" id="submitButton"
|
<button class="primary" type="submit" id="submitButton"
|
||||||
disabled={!$instanceNameInSearch || $logInToInstanceLoading}>
|
disabled={!$instanceNameInSearch || $logInToInstanceLoading}>
|
||||||
Log in
|
Log in
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
{#if $copyPasteMode }
|
||||||
|
<form aria-label="Enter code" on:submit="onSubmitOauth(event)">
|
||||||
|
<label for="oauthCodeInput">Code:</label>
|
||||||
|
<input type="text" id="oauthCodeInput"
|
||||||
|
bind:value='oauthCode' placeholder="Enter code" required
|
||||||
|
>
|
||||||
|
<button class="primary" type="submit" id="submitOauthButton"
|
||||||
|
disabled={!oauthCode}>
|
||||||
|
Submit
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
{#if !$isUserLoggedIn}
|
{#if !$isUserLoggedIn}
|
||||||
<p>
|
<p>
|
||||||
Don't have an
|
Don't have an
|
||||||
|
@ -44,22 +59,25 @@
|
||||||
<ExternalLink href="https://joinmastodon.org">Join Mastodon!</ExternalLink>
|
<ExternalLink href="https://joinmastodon.org">Join Mastodon!</ExternalLink>
|
||||||
</p>
|
</p>
|
||||||
{/if}
|
{/if}
|
||||||
|
<p>
|
||||||
|
{#if $copyPasteMode}
|
||||||
|
Switch back to
|
||||||
|
{:else}
|
||||||
|
Trouble logging in? Switch to
|
||||||
|
{/if}
|
||||||
|
<button on:click="onCopyPasteModeButtonClick()"
|
||||||
|
class="copy-paste-mode-button"
|
||||||
|
aria-pressed={$copyPasteMode}>
|
||||||
|
{$copyPasteMode ? 'regular' : 'basic'} login mode
|
||||||
|
</button>.
|
||||||
|
</p>
|
||||||
|
{#if $copyPasteMode}
|
||||||
|
<InfoAside className="add-new-instance-aside">
|
||||||
|
In basic login mode, click "log in" to open a new window. Then copy the code and paste it above.
|
||||||
|
</InfoAside>
|
||||||
|
{/if}
|
||||||
</SettingsLayout>
|
</SettingsLayout>
|
||||||
<style>
|
<style>
|
||||||
.form-error {
|
|
||||||
border: 2px solid red;
|
|
||||||
border-radius: 2px;
|
|
||||||
padding: 10px;
|
|
||||||
font-size: 1.3em;
|
|
||||||
margin: 5px;
|
|
||||||
background-color: var(--main-bg);
|
|
||||||
}
|
|
||||||
.add-new-instance-input {
|
|
||||||
min-width: 70%;
|
|
||||||
max-width: 100%;
|
|
||||||
background-color: var(--input-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.add-new-instance {
|
.add-new-instance {
|
||||||
background: var(--form-bg);
|
background: var(--form-bg);
|
||||||
padding: 5px 10px 15px;
|
padding: 5px 10px 15px;
|
||||||
|
@ -68,13 +86,41 @@
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.add-new-instance-label, .add-new-instance-input, .add-new-instance-button {
|
.form-error {
|
||||||
|
border: 2px solid red;
|
||||||
|
border-radius: 2px;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 1.3em;
|
||||||
|
margin: 5px;
|
||||||
|
background-color: var(--main-bg);
|
||||||
|
}
|
||||||
|
input {
|
||||||
|
min-width: 70%;
|
||||||
|
max-width: 100%;
|
||||||
|
background-color: var(--input-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
label, input, button, :global(.add-new-instance-aside) {
|
||||||
display: block;
|
display: block;
|
||||||
margin: 20px 5px;
|
margin: 20px 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button.copy-paste-mode-button {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: inline-block;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
font-size: 1em;
|
||||||
|
color: var(--anchor-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
button.copy-paste-mode-button:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 767px) {
|
@media (max-width: 767px) {
|
||||||
.add-new-instance-input {
|
input {
|
||||||
min-width: 95%;
|
min-width: 95%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,10 +129,11 @@
|
||||||
<script>
|
<script>
|
||||||
import SettingsLayout from '../../../_components/settings/SettingsLayout.html'
|
import SettingsLayout from '../../../_components/settings/SettingsLayout.html'
|
||||||
import { store } from '../../../_store/store'
|
import { store } from '../../../_store/store'
|
||||||
import { logInToInstance, handleOauthCode } from '../../../_actions/addInstance'
|
import { logInToInstance, handleOauthCode, handleCopyPasteOauthCode } from '../../../_actions/addInstance'
|
||||||
import ExternalLink from '../../../_components/ExternalLink.html'
|
import ExternalLink from '../../../_components/ExternalLink.html'
|
||||||
import { testHasIndexedDB, testHasLocalStorage } from '../../../_utils/testStorage'
|
import { testHasIndexedDB, testHasLocalStorage } from '../../../_utils/testStorage'
|
||||||
import Tooltip from '../../../_components/Tooltip.html'
|
import Tooltip from '../../../_components/Tooltip.html'
|
||||||
|
import InfoAside from '../../../_components/InfoAside.html'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
async oncreate () {
|
async oncreate () {
|
||||||
|
@ -102,18 +149,30 @@
|
||||||
components: {
|
components: {
|
||||||
SettingsLayout,
|
SettingsLayout,
|
||||||
ExternalLink,
|
ExternalLink,
|
||||||
Tooltip
|
Tooltip,
|
||||||
|
InfoAside
|
||||||
},
|
},
|
||||||
store: () => store,
|
store: () => store,
|
||||||
data: () => ({
|
data: () => ({
|
||||||
hasIndexedDB: true,
|
hasIndexedDB: true,
|
||||||
hasLocalStorage: true
|
hasLocalStorage: true,
|
||||||
|
oauthCode: ''
|
||||||
}),
|
}),
|
||||||
methods: {
|
methods: {
|
||||||
onSubmit (event) {
|
onSubmitInstance (event) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
logInToInstance()
|
logInToInstance()
|
||||||
|
},
|
||||||
|
onSubmitOauth (event) {
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
handleCopyPasteOauthCode(this.get().oauthCode)
|
||||||
|
},
|
||||||
|
onCopyPasteModeButtonClick () {
|
||||||
|
const { copyPasteMode } = this.store.get()
|
||||||
|
console.log('copyPasteMode', copyPasteMode)
|
||||||
|
this.store.set({ copyPasteMode: !copyPasteMode })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,13 +44,10 @@
|
||||||
</label>
|
</label>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<aside>
|
<InfoAside className="wellness-aside">
|
||||||
<SvgIcon href="#fa-info-circle" className="aside-icon" />
|
|
||||||
<span>
|
|
||||||
You can filter or disable notifications in the
|
You can filter or disable notifications in the
|
||||||
<a rel="prefetch" href="/settings/instances{$currentInstance ? '/' + $currentInstance : ''}">instance settings</a>.
|
<a rel="prefetch" href="/settings/instances{$currentInstance ? '/' + $currentInstance : ''}">instance settings</a>.
|
||||||
</span>
|
</InfoAside>
|
||||||
</aside>
|
|
||||||
|
|
||||||
<h2>UI</h2>
|
<h2>UI</h2>
|
||||||
|
|
||||||
|
@ -78,26 +75,8 @@
|
||||||
display: block;
|
display: block;
|
||||||
padding: 5px 0;
|
padding: 5px 0;
|
||||||
}
|
}
|
||||||
aside {
|
:global(.wellness-aside) {
|
||||||
font-size: 1.2em;
|
|
||||||
margin: 20px 10px 0px 10px;
|
margin: 20px 10px 0px 10px;
|
||||||
color: var(--deemphasized-text-color);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
aside a {
|
|
||||||
text-decoration: underline;
|
|
||||||
color: var(--deemphasized-text-color);
|
|
||||||
}
|
|
||||||
aside span {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
:global(.aside-icon) {
|
|
||||||
fill: var(--deemphasized-text-color);
|
|
||||||
width: 18px;
|
|
||||||
height: 18px;
|
|
||||||
margin: 0 10px 0 5px;
|
|
||||||
min-width: 18px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 240px) {
|
@media (max-width: 240px) {
|
||||||
|
@ -110,7 +89,7 @@
|
||||||
import SettingsLayout from '../../_components/settings/SettingsLayout.html'
|
import SettingsLayout from '../../_components/settings/SettingsLayout.html'
|
||||||
import { store } from '../../_store/store'
|
import { store } from '../../_store/store'
|
||||||
import ExternalLink from '../../_components/ExternalLink.html'
|
import ExternalLink from '../../_components/ExternalLink.html'
|
||||||
import SvgIcon from '../../_components/SvgIcon.html'
|
import InfoAside from '../../_components/InfoAside.html'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
oncreate () {
|
oncreate () {
|
||||||
|
@ -119,7 +98,7 @@
|
||||||
components: {
|
components: {
|
||||||
SettingsLayout,
|
SettingsLayout,
|
||||||
ExternalLink,
|
ExternalLink,
|
||||||
SvgIcon
|
InfoAside
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
flushChangesToCheckAll () {
|
flushChangesToCheckAll () {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Selector as $ } from 'testcafe'
|
import { Selector as $ } from 'testcafe'
|
||||||
import {
|
import {
|
||||||
addInstanceButton,
|
addInstanceButton,
|
||||||
authorizeInput, confirmationDialogOKButton,
|
authorizeInput, confirmationDialogOKButton, copyPasteModeButton,
|
||||||
emailInput,
|
emailInput,
|
||||||
formError,
|
formError,
|
||||||
getFirstVisibleStatus, getNthStatus, getOpacity,
|
getFirstVisibleStatus, getNthStatus, getOpacity,
|
||||||
|
@ -9,10 +9,10 @@ import {
|
||||||
homeNavButton,
|
homeNavButton,
|
||||||
instanceInput,
|
instanceInput,
|
||||||
logInToInstanceLink,
|
logInToInstanceLink,
|
||||||
mastodonLogInButton,
|
mastodonLogInButton, oauthCodeInput,
|
||||||
passwordInput, reload,
|
passwordInput, reload,
|
||||||
settingsButton,
|
settingsButton,
|
||||||
sleep
|
sleep, submitOauthButton
|
||||||
} from '../utils'
|
} from '../utils'
|
||||||
import { loginAsFoobar } from '../roles'
|
import { loginAsFoobar } from '../roles'
|
||||||
|
|
||||||
|
@ -96,3 +96,13 @@ test('Logs in, refreshes, then logs out', async t => {
|
||||||
.click(homeNavButton)
|
.click(homeNavButton)
|
||||||
.expect(getOpacity('.hidden-from-ssr')()).eql('1')
|
.expect(getOpacity('.hidden-from-ssr')()).eql('1')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('Shows error when entering only oauth code in basic mode', async t => {
|
||||||
|
await t
|
||||||
|
.click(logInToInstanceLink)
|
||||||
|
.click(copyPasteModeButton)
|
||||||
|
.typeText(oauthCodeInput, 'blahblahblah')
|
||||||
|
.click(submitOauthButton)
|
||||||
|
.expect(formError.exists).ok()
|
||||||
|
.expect(formError.innerText).contains('You must log in to an instance first')
|
||||||
|
})
|
||||||
|
|
|
@ -29,6 +29,8 @@ export const emailInput = $('input#user_email')
|
||||||
export const passwordInput = $('input#user_password')
|
export const passwordInput = $('input#user_password')
|
||||||
export const authorizeInput = $('button[type=submit]:not(.negative)')
|
export const authorizeInput = $('button[type=submit]:not(.negative)')
|
||||||
export const logInToInstanceLink = $('a[href="/settings/instances/add"]')
|
export const logInToInstanceLink = $('a[href="/settings/instances/add"]')
|
||||||
|
export const copyPasteModeButton = $('.copy-paste-mode-button')
|
||||||
|
export const oauthCodeInput = $('#oauthCodeInput')
|
||||||
export const searchInput = $('.search-input')
|
export const searchInput = $('.search-input')
|
||||||
export const postStatusButton = $('.compose-box-button')
|
export const postStatusButton = $('.compose-box-button')
|
||||||
export const showMoreButton = $('.more-items-header button')
|
export const showMoreButton = $('.more-items-header button')
|
||||||
|
@ -39,6 +41,7 @@ export const accountProfileFollowButton = $('.account-profile .account-profile-f
|
||||||
export const goBackButton = $('.dynamic-page-go-back')
|
export const goBackButton = $('.dynamic-page-go-back')
|
||||||
export const accountProfileMoreOptionsButton = $('.account-profile-more-options button')
|
export const accountProfileMoreOptionsButton = $('.account-profile-more-options button')
|
||||||
export const addInstanceButton = $('#submitButton')
|
export const addInstanceButton = $('#submitButton')
|
||||||
|
export const submitOauthButton = $('#submitOauthButton')
|
||||||
export const mastodonLogInButton = $('button[type="submit"]')
|
export const mastodonLogInButton = $('button[type="submit"]')
|
||||||
export const followsButton = $('.account-profile-details > *:nth-child(2)')
|
export const followsButton = $('.account-profile-details > *:nth-child(2)')
|
||||||
export const followersButton = $('.account-profile-details > *:nth-child(3)')
|
export const followersButton = $('.account-profile-details > *:nth-child(3)')
|
||||||
|
|
Loading…
Reference in a new issue