Merge remote-tracking branch 'upstream-next/develop' into feature/i18n-part2

This commit is contained in:
Nriver 2024-08-15 11:04:14 +08:00
commit cc98ae0ea4
15 changed files with 91 additions and 14 deletions

Binary file not shown.

View File

@ -0,0 +1,18 @@
import test, { expect } from "@playwright/test";
test("Renders on desktop", async ({ page, context }) => {
await page.goto('http://localhost:8082');
await expect(page.locator('.tree')).toContainText('Trilium Integration Test');
});
test("Renders on mobile", async ({ page, context }) => {
await context.addCookies([
{
url: "http://localhost:8082",
name: "trilium-device",
value: "mobile"
}
]);
await page.goto('http://localhost:8082');
await expect(page.locator('.tree')).toContainText('Trilium Integration Test');
});

View File

@ -4,6 +4,10 @@
display: none; display: none;
} }
.ck-content li p {
margin: 0 !important;
}
/* /*
* CKEditor 5 (v41.0.0) content styles. * CKEditor 5 (v41.0.0) content styles.
* Generated on Fri, 26 Jan 2024 10:23:49 GMT. * Generated on Fri, 26 Jan 2024 10:23:49 GMT.

View File

@ -31,6 +31,14 @@ export default defineConfig({
trace: 'on-first-retry', trace: 'on-first-retry',
}, },
webServer: {
command: "npm run integration-mem-db",
url: "http://127.0.0.1:8082",
reuseExistingServer: true,
stdout: "ignore",
stderr: "pipe"
},
/* Configure projects for major browsers */ /* Configure projects for major browsers */
projects: [ projects: [
{ {

View File

@ -11,7 +11,6 @@ export async function initLocale() {
.init({ .init({
lng: locale, lng: locale,
fallbackLng: "en", fallbackLng: "en",
debug: true,
backend: { backend: {
loadPath: `/${window.glob.assetPath}/translations/{{lng}}/{{ns}}.json` loadPath: `/${window.glob.assetPath}/translations/{{lng}}/{{ns}}.json`
} }

View File

@ -135,7 +135,11 @@ function ajax(url, method, data, headers, silentNotFound) {
}); });
}, },
error: async jqXhr => { error: async jqXhr => {
if (silentNotFound && jqXhr.status === 404) { if (jqXhr.status === 0) {
// don't report requests that are rejected by the browser, usually when the user is refreshing or going to a different page.
rej("rejected by browser");
return;
} else if (silentNotFound && jqXhr.status === 404) {
// report nothing // report nothing
} else { } else {
await reportError(method, url, jqXhr.status, jqXhr.responseText); await reportError(method, url, jqXhr.status, jqXhr.responseText);

View File

@ -57,7 +57,17 @@ class NoteContextAwareWidget extends BasicWidget {
async refresh() { async refresh() {
if (this.isEnabled()) { if (this.isEnabled()) {
this.toggleInt(true); this.toggleInt(true);
await this.refreshWithNote(this.note);
try {
await this.refreshWithNote(this.note);
} catch (e) {
// Ignore errors when user is refreshing or navigating away.
if (e === "rejected by browser") {
return;
}
throw e;
}
} }
else { else {
this.toggleInt(false); this.toggleInt(false);

View File

@ -199,7 +199,7 @@ export default class SearchDefinitionWidget extends NoteContextAwareWidget {
this.$actionList.append( this.$actionList.append(
$('<a class="dropdown-item" href="#">') $('<a class="dropdown-item" href="#">')
.attr('data-action-add', action.actionName) .attr('data-action-add', action.actionName)
.text(t(`${action.actionTitle}`)) .text(action.actionTitle)
); );
} }
} }

View File

@ -29,6 +29,8 @@ export default class LocalizationOptions extends OptionsWidget {
async optionsLoaded(options) { async optionsLoaded(options) {
const availableLocales = await server.get("options/locales"); const availableLocales = await server.get("options/locales");
this.$localeSelect.empty();
for (const locale of availableLocales) { for (const locale of availableLocales) {
this.$localeSelect.append($("<option>") this.$localeSelect.append($("<option>")
.attr("value", locale.id) .attr("value", locale.id)

View File

@ -623,6 +623,10 @@ div[data-notify="container"] {
background-color: var(--accented-background-color) !important; background-color: var(--accented-background-color) !important;
} }
.ck-content li p {
margin: 0 !important;
}
#options-dialog input[type=number] { #options-dialog input[type=number] {
text-align: right; text-align: right;
} }

View File

@ -7,6 +7,8 @@ import anonymizationService from "../../services/anonymization.js";
import consistencyChecksService from "../../services/consistency_checks.js"; import consistencyChecksService from "../../services/consistency_checks.js";
import { Request } from 'express'; import { Request } from 'express';
import ValidationError from "../../errors/validation_error.js"; import ValidationError from "../../errors/validation_error.js";
import sql_init from "../../services/sql_init.js";
import becca_loader from "../../becca/becca_loader.js";
function getExistingBackups() { function getExistingBackups() {
return backupService.getExistingBackups(); return backupService.getExistingBackups();
@ -28,6 +30,12 @@ function findAndFixConsistencyIssues() {
consistencyChecksService.runOnDemandChecks(true); consistencyChecksService.runOnDemandChecks(true);
} }
async function rebuildIntegrationTestDatabase() {
sql.rebuildIntegrationTestDatabase();
sql_init.initializeDb();
becca_loader.load();
}
function getExistingAnonymizedDatabases() { function getExistingAnonymizedDatabases() {
return anonymizationService.getExistingAnonymizedDatabases(); return anonymizationService.getExistingAnonymizedDatabases();
} }
@ -54,6 +62,7 @@ export default {
backupDatabase, backupDatabase,
vacuumDatabase, vacuumDatabase,
findAndFixConsistencyIssues, findAndFixConsistencyIssues,
rebuildIntegrationTestDatabase,
getExistingAnonymizedDatabases, getExistingAnonymizedDatabases,
anonymize, anonymize,
checkIntegrity checkIntegrity

View File

@ -23,6 +23,11 @@ function index(req: Request, res: Response) {
const csrfToken = req.csrfToken(); const csrfToken = req.csrfToken();
log.info(`Generated CSRF token ${csrfToken} with secret ${res.getHeader('set-cookie')}`); log.info(`Generated CSRF token ${csrfToken} with secret ${res.getHeader('set-cookie')}`);
// We force the page to not be cached since on mobile the CSRF token can be
// broken when closing the browser and coming back in to the page.
// The page is restored from cache, but the API call fail.
res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
res.render(view, { res.render(view, {
csrfToken: csrfToken, csrfToken: csrfToken,
themeCssUrl: getThemeCssUrl(options.theme), themeCssUrl: getThemeCssUrl(options.theme),

View File

@ -299,6 +299,10 @@ function register(app: express.Application) {
route(PST, '/api/database/anonymize/:type', [auth.checkApiAuthOrElectron, csrfMiddleware], databaseRoute.anonymize, apiResultHandler, false); route(PST, '/api/database/anonymize/:type', [auth.checkApiAuthOrElectron, csrfMiddleware], databaseRoute.anonymize, apiResultHandler, false);
apiRoute(GET, '/api/database/anonymized-databases', databaseRoute.getExistingAnonymizedDatabases); apiRoute(GET, '/api/database/anonymized-databases', databaseRoute.getExistingAnonymizedDatabases);
if (process.env.TRILIUM_INTEGRATION_TEST === "memory") {
route(PST, '/api/database/rebuild/', [auth.checkApiAuthOrElectron], databaseRoute.rebuildIntegrationTestDatabase, apiResultHandler, false);
}
// backup requires execution outside of transaction // backup requires execution outside of transaction
route(PST, '/api/database/backup-database', [auth.checkApiAuthOrElectron, csrfMiddleware], databaseRoute.backupDatabase, apiResultHandler, false); route(PST, '/api/database/backup-database', [auth.checkApiAuthOrElectron, csrfMiddleware], databaseRoute.backupDatabase, apiResultHandler, false);
apiRoute(GET, '/api/database/backups', databaseRoute.getExistingBackups); apiRoute(GET, '/api/database/backups', databaseRoute.getExistingBackups);

View File

@ -14,17 +14,28 @@ import ws from "./ws.js";
import becca_loader from "../becca/becca_loader.js"; import becca_loader from "../becca/becca_loader.js";
import entity_changes from "./entity_changes.js"; import entity_changes from "./entity_changes.js";
function buildDatabase(path: string) { let dbConnection: DatabaseType = buildDatabase();
let statementCache: Record<string, Statement> = {};
function buildDatabase() {
if (process.env.TRILIUM_INTEGRATION_TEST === "memory") { if (process.env.TRILIUM_INTEGRATION_TEST === "memory") {
// This allows a database that is read normally but is kept in memory and discards all modifications. return buildIntegrationTestDatabase();
const dbBuffer = fs.readFileSync(path);
return new Database(dbBuffer);
} }
return new Database(dataDir.DOCUMENT_PATH); return new Database(dataDir.DOCUMENT_PATH);
} }
const dbConnection: DatabaseType = buildDatabase(dataDir.DOCUMENT_PATH); function buildIntegrationTestDatabase() {
const dbBuffer = fs.readFileSync(dataDir.DOCUMENT_PATH);
return new Database(dbBuffer);
}
function rebuildIntegrationTestDatabase() {
// This allows a database that is read normally but is kept in memory and discards all modifications.
dbConnection = buildIntegrationTestDatabase();
statementCache = {};
}
if (!process.env.TRILIUM_INTEGRATION_TEST) { if (!process.env.TRILIUM_INTEGRATION_TEST) {
dbConnection.pragma('journal_mode = WAL'); dbConnection.pragma('journal_mode = WAL');
@ -96,8 +107,6 @@ function upsert<T extends {}>(tableName: string, primaryKey: string, rec: T) {
execute(query, rec); execute(query, rec);
} }
const statementCache: Record<string, Statement> = {};
function stmt(sql: string) { function stmt(sql: string) {
if (!(sql in statementCache)) { if (!(sql in statementCache)) {
statementCache[sql] = dbConnection.prepare(sql); statementCache[sql] = dbConnection.prepare(sql);
@ -302,7 +311,7 @@ function fillParamList(paramIds: string[] | Set<string>, truncate = true) {
paramIds = paramIds.slice(0, 30000); paramIds = paramIds.slice(0, 30000);
} }
// doing it manually to avoid this showing up on the sloq query list // doing it manually to avoid this showing up on the slow query list
const s = stmt(`INSERT INTO param_list VALUES ${paramIds.map(paramId => `(?)`).join(',')}`); const s = stmt(`INSERT INTO param_list VALUES ${paramIds.map(paramId => `(?)`).join(',')}`);
s.run(paramIds); s.run(paramIds);
@ -403,5 +412,6 @@ export default {
upsert, upsert,
fillParamList, fillParamList,
copyDatabase, copyDatabase,
disableSlowQueryLogging disableSlowQueryLogging,
rebuildIntegrationTestDatabase
}; };

View File

@ -128,7 +128,7 @@
<script src="<%= assetPath %>/node_modules/dayjs/dayjs.min.js"></script> <script src="<%= assetPath %>/node_modules/dayjs/dayjs.min.js"></script>
<link href="<%= assetPath %>/stylesheets/tree.css" rel="stylesheet"> <link href="<%= assetPath %>/stylesheets/tree.css" rel="stylesheet">
<script src="<%= assetPath %>/libraries/fancytree/jquery.fancytree-all-deps.min.js"></script> <script src="<%= assetPath %>/node_modules/jquery.fancytree/dist/jquery.fancytree-all-deps.min.js"></script>
<link href="<%= assetPath %>/node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet"> <link href="<%= assetPath %>/node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="<%= assetPath %>/node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script> <script src="<%= assetPath %>/node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>