diff --git a/.eslintrc b/.eslintrc
index 657cd2c81..c88737d79 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -1,11 +1,16 @@
{
- "extends": ["eslint:recommended", "semistandard", "prettier"],
- "parser": "babel-eslint",
+ "extends": ["eslint:recommended", "prettier"],
+ "parser": "@typescript-eslint/parser",
+ "parserOptions": {
+ "project": "./app/assets/javascripts/tsconfig.json"
+ },
"rules": {
"standard/no-callback-literal": 0, // Disable this as we have too many callbacks relying on literals
"no-throw-literal": 0,
- // "no-console": "error",
- "semi": 1
+ "no-console": "off",
+ "semi": 1,
+ "camelcase": "warn",
+ "sort-imports": "off"
},
"env": {
"browser": true
diff --git a/app/assets/javascripts/app.ts b/app/assets/javascripts/app.ts
index 69cb4fcab..4051a7883 100644
--- a/app/assets/javascripts/app.ts
+++ b/app/assets/javascripts/app.ts
@@ -59,10 +59,35 @@ import { StartApplication } from './startApplication';
import { Bridge } from './services/bridge';
import { SessionsModalDirective } from './directives/views/sessionsModal';
+
+function reloadHiddenFirefoxTab(): boolean {
+ /**
+ * For Firefox pinned tab issue:
+ * When a new browser session is started, and SN is in a pinned tab,
+ * SN exhibits strange behavior until the tab is reloaded.
+ */
+ if (
+ document.hidden &&
+ navigator.userAgent.toLowerCase().includes('firefox') &&
+ !localStorage.getItem('reloading')
+ ) {
+ localStorage.setItem('reloading', 'true');
+ location.reload();
+ return true;
+ } else {
+ localStorage.removeItem('reloading');
+ return false;
+ }
+}
+
const startApplication: StartApplication = async function startApplication(
defaultSyncServerHost: string,
bridge: Bridge
) {
+ if (reloadHiddenFirefoxTab()) {
+ return;
+ }
+
SNLog.onLog = console.log;
startErrorReporting();
diff --git a/app/assets/javascripts/directives/views/accountMenu.ts b/app/assets/javascripts/directives/views/accountMenu.ts
index 21ed1a884..7d73e82ab 100644
--- a/app/assets/javascripts/directives/views/accountMenu.ts
+++ b/app/assets/javascripts/directives/views/accountMenu.ts
@@ -68,7 +68,6 @@ type AccountMenuState = {
errorReportingEnabled: boolean;
syncInProgress: boolean;
syncError: string;
- syncPercentage: string;
showSessions: boolean;
}
@@ -101,7 +100,7 @@ class AccountMenuCtrl extends PureViewCtrl<{}, AccountMenuState> {
},
mutable: {},
showBetaWarning: false,
- errorReportingEnabled: !storage.get(StorageKey.DisableErrorReporting),
+ errorReportingEnabled: storage.get(StorageKey.DisableErrorReporting) === false,
showSessions: false,
} as AccountMenuState;
}
@@ -143,7 +142,6 @@ class AccountMenuCtrl extends PureViewCtrl<{}, AccountMenuState> {
this.setState({
syncInProgress: sync.inProgress,
syncError: sync.errorMessage,
- syncPercentage: sync.humanReadablePercentage,
});
})
this.removeBetaWarningListener = autorun(() => {
@@ -636,7 +634,7 @@ class AccountMenuCtrl extends PureViewCtrl<{}, AccountMenuState> {
} else {
storage.set(StorageKey.DisableErrorReporting, false);
}
- if (!this.application.getSyncStatus().syncInProgress) {
+ if (!this.state.syncInProgress) {
window.location.reload();
}
}
diff --git a/app/assets/javascripts/directives/views/sessionsModal.tsx b/app/assets/javascripts/directives/views/sessionsModal.tsx
index 57c24a50f..08f3906e3 100644
--- a/app/assets/javascripts/directives/views/sessionsModal.tsx
+++ b/app/assets/javascripts/directives/views/sessionsModal.tsx
@@ -1,6 +1,11 @@
import { AppState } from '@/ui_models/app_state';
import { PureViewCtrl } from '@/views';
-import { SNApplication, RemoteSession, UuidString } from '@standardnotes/snjs';
+import {
+ SNApplication,
+ RemoteSession,
+ SessionStrings,
+ UuidString,
+} from '@standardnotes/snjs';
import { autorun, IAutorunOptions, IReactionPublic } from 'mobx';
import { render, FunctionComponent } from 'preact';
import { useState, useEffect, useRef } from 'preact/hooks';
@@ -16,16 +21,20 @@ function useAutorun(view: (r: IReactionPublic) => any, opts?: IAutorunOptions) {
useEffect(() => autorun(view, opts), []);
}
+type Session = RemoteSession & {
+ revoking?: true;
+};
+
function useSessions(
application: SNApplication
): [
- RemoteSession[],
+ Session[],
() => void,
boolean,
(uuid: UuidString) => Promise,
string
] {
- const [sessions, setSessions] = useState([]);
+ const [sessions, setSessions] = useState([]);
const [lastRefreshDate, setLastRefreshDate] = useState(Date.now());
const [refreshing, setRefreshing] = useState(true);
const [errorMessage, setErrorMessage] = useState('');
@@ -41,7 +50,7 @@ function useSessions(
setErrorMessage('An unknown error occured while loading sessions.');
}
} else {
- const sessions = response as RemoteSession[];
+ const sessions = response as Session[];
setSessions(sessions);
setErrorMessage('');
}
@@ -54,9 +63,21 @@ function useSessions(
}
async function revokeSession(uuid: UuidString) {
+ const responsePromise = application.revokeSession(uuid);
+
let sessionsBeforeRevoke = sessions;
- setSessions(sessions.filter((session) => session.uuid !== uuid));
- const response = await application.revokeSession(uuid);
+
+ const sessionsDuringRevoke = sessions.slice();
+ const toRemoveIndex = sessions.findIndex(
+ (session) => session.uuid === uuid
+ );
+ sessionsDuringRevoke[toRemoveIndex] = {
+ ...sessionsDuringRevoke[toRemoveIndex],
+ revoking: true,
+ };
+ setSessions(sessionsDuringRevoke);
+
+ const response = await responsePromise;
if ('error' in response) {
if (response.error?.message) {
setErrorMessage(response.error?.message);
@@ -64,6 +85,8 @@ function useSessions(
setErrorMessage('An unknown error occured while revoking the session.');
}
setSessions(sessionsBeforeRevoke);
+ } else {
+ setSessions(sessions.filter((session) => session.uuid !== uuid));
}
}
@@ -84,7 +107,7 @@ const SessionsModal: FunctionComponent<{
errorMessage,
] = useSessions(application);
- const [revokingSessionUuid, setRevokingSessionUuid] = useState('');
+ const [confirmRevokingSessionUuid, setRevokingSessionUuid] = useState('');
const closeRevokeSessionAlert = () => setRevokingSessionUuid('');
const cancelRevokeRef = useRef();
@@ -146,6 +169,7 @@ const SessionsModal: FunctionComponent<{