Fix lint and type errors
This commit is contained in:
parent
9147982a83
commit
9a1c9a6b2c
8
package-lock.json
generated
8
package-lock.json
generated
@ -44,6 +44,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playwright/test": "^1.44.1",
|
"@playwright/test": "^1.44.1",
|
||||||
"@sealcode/ansi-html-stream": "^1.0.1",
|
"@sealcode/ansi-html-stream": "^1.0.1",
|
||||||
|
"@types/hotwired__turbo": "^8.0.2",
|
||||||
"@types/koa__router": "^12.0.4",
|
"@types/koa__router": "^12.0.4",
|
||||||
"@types/node": "^20.8.4",
|
"@types/node": "^20.8.4",
|
||||||
"@types/object-path": "^0.11.4",
|
"@types/object-path": "^0.11.4",
|
||||||
@ -1149,6 +1150,13 @@
|
|||||||
"version": "7946.0.14",
|
"version": "7946.0.14",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/hotwired__turbo": {
|
||||||
|
"version": "8.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/hotwired__turbo/-/hotwired__turbo-8.0.2.tgz",
|
||||||
|
"integrity": "sha512-fFWI/JNSTVKTPliSOV4fdeC3Kt3FUTbRYkvtF7QPCkqR51+AJWIiX0T5sJXwUnjL9j43tzfBXPZ2jEsBqw8/Bg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@types/http-assert": {
|
"node_modules/@types/http-assert": {
|
||||||
"version": "1.5.5",
|
"version": "1.5.5",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
|
@ -109,6 +109,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playwright/test": "^1.44.1",
|
"@playwright/test": "^1.44.1",
|
||||||
"@sealcode/ansi-html-stream": "^1.0.1",
|
"@sealcode/ansi-html-stream": "^1.0.1",
|
||||||
|
"@types/hotwired__turbo": "^8.0.2",
|
||||||
"@types/koa__router": "^12.0.4",
|
"@types/koa__router": "^12.0.4",
|
||||||
"@types/node": "^20.8.4",
|
"@types/node": "^20.8.4",
|
||||||
"@types/object-path": "^0.11.4",
|
"@types/object-path": "^0.11.4",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Collection, FieldTypes, Policies } from "sealious";
|
import { Collection, FieldTypes, Policies } from "sealious";
|
||||||
import { CRUDRoles, Roles } from "../policy-types/roles.js";
|
import { CRUDRoles } from "../policy-types/roles.js";
|
||||||
|
|
||||||
export default class Redirects extends Collection {
|
export default class Redirects extends Collection {
|
||||||
fields = {
|
fields = {
|
||||||
|
@ -5,7 +5,7 @@ import { Roles } from "../policy-types/roles.js";
|
|||||||
export default class UserRoles extends Collection {
|
export default class UserRoles extends Collection {
|
||||||
name = "user-roles";
|
name = "user-roles";
|
||||||
fields = {
|
fields = {
|
||||||
role: new FieldTypes.Text(),
|
role: new FieldTypes.Text().setRequired(true),
|
||||||
user: new FieldTypes.SingleReference("users"),
|
user: new FieldTypes.SingleReference("users"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -56,9 +56,11 @@ export default class AutoscrollingImages extends Controller {
|
|||||||
const nextButtonID =
|
const nextButtonID =
|
||||||
radioButtonIdPrefix + "-autoscrolling-images__radio-" + nextIndex;
|
radioButtonIdPrefix + "-autoscrolling-images__radio-" + nextIndex;
|
||||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||||
const nextButton = this.element.querySelector("#" + nextButtonID);
|
const nextButton: HTMLInputElement = this.element.querySelector(
|
||||||
|
"#" + nextButtonID
|
||||||
|
);
|
||||||
if (nextButton) {
|
if (nextButton) {
|
||||||
(nextButton as HTMLInputElement).checked = true;
|
nextButton.checked = true;
|
||||||
this.currentIndex = nextIndex;
|
this.currentIndex = nextIndex;
|
||||||
this.handleRadioChange();
|
this.handleRadioChange();
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,8 @@ function parseCoords(s: string): [number, number] {
|
|||||||
return s.split(", ").map((x) => parseFloat(x)) as [number, number];
|
return s.split(", ").map((x) => parseFloat(x)) as [number, number];
|
||||||
}
|
}
|
||||||
|
|
||||||
function decodeHTMLEntities(text) {
|
function decodeHTMLEntities(text: string) {
|
||||||
var entities = [
|
const entities = [
|
||||||
["amp", "&"],
|
["amp", "&"],
|
||||||
["apos", "'"],
|
["apos", "'"],
|
||||||
["#x27", "'"],
|
["#x27", "'"],
|
||||||
@ -37,7 +37,7 @@ function decodeHTMLEntities(text) {
|
|||||||
["quot", '"'],
|
["quot", '"'],
|
||||||
];
|
];
|
||||||
|
|
||||||
for (var i = 0, max = entities.length; i < max; ++i)
|
for (let i = 0, max = entities.length; i < max; ++i)
|
||||||
text = text.replace(new RegExp("&" + entities[i][0] + ";", "g"), entities[i][1]);
|
text = text.replace(new RegExp("&" + entities[i][0] + ";", "g"), entities[i][1]);
|
||||||
|
|
||||||
return text;
|
return text;
|
||||||
@ -101,9 +101,7 @@ export default class MapWithPins extends Controller {
|
|||||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||||
const pins = JSON.parse(
|
const pins = JSON.parse(
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument
|
||||||
decodeHTMLEntities(
|
decodeHTMLEntities(this.element.getAttribute("data-map-with-pins-pins-value"))
|
||||||
this.element.attributes["data-map-with-pins-pins-value"].value
|
|
||||||
)
|
|
||||||
) as Pin[];
|
) as Pin[];
|
||||||
pins.forEach((pin) => this.addPin(pin));
|
pins.forEach((pin) => this.addPin(pin));
|
||||||
this.initiated = true;
|
this.initiated = true;
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-for-in-array */
|
||||||
|
/* eslint-disable @typescript-eslint/consistent-type-assertions */
|
||||||
import { Controller } from "stimulus";
|
import { Controller } from "stimulus";
|
||||||
|
|
||||||
async function sleep(time: number) {
|
async function sleep(time: number) {
|
||||||
@ -21,7 +23,7 @@ export default class Sortable extends Controller {
|
|||||||
|
|
||||||
setIndex(node: HTMLDivElement, index: number) {
|
setIndex(node: HTMLDivElement, index: number) {
|
||||||
node.setAttribute("data-index", String(index));
|
node.setAttribute("data-index", String(index));
|
||||||
(node as HTMLDivElement).style.setProperty("--index", String(index));
|
node.style.setProperty("--index", String(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
setupHoleListeners(hole: HTMLDivElement) {
|
setupHoleListeners(hole: HTMLDivElement) {
|
||||||
@ -70,7 +72,7 @@ export default class Sortable extends Controller {
|
|||||||
this.setIndex(node as HTMLDivElement, index_of_drop_target);
|
this.setIndex(node as HTMLDivElement, index_of_drop_target);
|
||||||
last_node_of_target_index = node;
|
last_node_of_target_index = node;
|
||||||
}
|
}
|
||||||
let next_to_correct = nodes_of_dropped_element_index[0].previousSibling;
|
const next_to_correct = nodes_of_dropped_element_index[0].previousSibling;
|
||||||
const children = Array.from(next_to_correct.parentNode.childNodes);
|
const children = Array.from(next_to_correct.parentNode.childNodes);
|
||||||
const children_to_correct = children.slice(2);
|
const children_to_correct = children.slice(2);
|
||||||
for (const dom_index in children_to_correct) {
|
for (const dom_index in children_to_correct) {
|
||||||
@ -104,15 +106,18 @@ export default class Sortable extends Controller {
|
|||||||
.querySelectorAll(".edge-detector")
|
.querySelectorAll(".edge-detector")
|
||||||
.forEach((detector: HTMLDivElement) => {
|
.forEach((detector: HTMLDivElement) => {
|
||||||
let is_hovered = false;
|
let is_hovered = false;
|
||||||
detector.addEventListener("dragenter", async (e) => {
|
detector.addEventListener("dragenter", (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const target = e.target as HTMLDivElement;
|
const target = e.target as HTMLDivElement;
|
||||||
const step = parseInt(target.getAttribute("data-step"));
|
const step = parseInt(target.getAttribute("data-step"));
|
||||||
is_hovered = true;
|
is_hovered = true;
|
||||||
while (is_hovered && this.dragged_element) {
|
void (async () => {
|
||||||
window.scrollTo(window.scrollX, window.scrollY + step);
|
while (is_hovered && this.dragged_element) {
|
||||||
await sleep(16);
|
window.scrollTo(window.scrollX, window.scrollY + step);
|
||||||
}
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
await sleep(16);
|
||||||
|
}
|
||||||
|
})();
|
||||||
});
|
});
|
||||||
|
|
||||||
detector.addEventListener("dragover ", (e) => {
|
detector.addEventListener("dragover ", (e) => {
|
||||||
@ -121,7 +126,6 @@ export default class Sortable extends Controller {
|
|||||||
});
|
});
|
||||||
|
|
||||||
detector.addEventListener("dragleave", (e) => {
|
detector.addEventListener("dragleave", (e) => {
|
||||||
const target = e.target as HTMLDivElement;
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
is_hovered = false;
|
is_hovered = false;
|
||||||
});
|
});
|
||||||
|
24
src/back/routes/hello-page.page.tsx
Normal file
24
src/back/routes/hello-page.page.tsx
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import type { Context } from "koa";
|
||||||
|
import { TempstreamJSX } from "tempstream";
|
||||||
|
import { Page } from "@sealcode/sealgen";
|
||||||
|
|
||||||
|
import html from "src/back/html.js";
|
||||||
|
|
||||||
|
export const actionName = "HelloPage";
|
||||||
|
|
||||||
|
export default new (class HelloPagePage extends Page {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
async canAccess(_: Context) {
|
||||||
|
return { canAccess: true, message: "" };
|
||||||
|
}
|
||||||
|
|
||||||
|
async render(ctx: Context) {
|
||||||
|
return html({
|
||||||
|
ctx: ctx,
|
||||||
|
title: "HelloPage",
|
||||||
|
body: <div>Hello world</div>,
|
||||||
|
description: "",
|
||||||
|
css_clumps: ["default", "forms"],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})();
|
40
src/back/routes/hello-page.test.ts
Normal file
40
src/back/routes/hello-page.test.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { withProdApp } from "../test_utils/with-prod-app.js";
|
||||||
|
import { VERY_LONG_TEST_TIMEOUT, webhintURL } from "../test_utils/webhint.js";
|
||||||
|
import { HelloPageURL } from "./urls.js";
|
||||||
|
import { getBrowser } from "../test_utils/browser-creator.js";
|
||||||
|
import type { Browser, BrowserContext, Page } from "@playwright/test";
|
||||||
|
|
||||||
|
describe("HelloPage webhint", () => {
|
||||||
|
it("doesn't crash", async function () {
|
||||||
|
return withProdApp(async ({ base_url, rest_api }) => {
|
||||||
|
await rest_api.get(HelloPageURL);
|
||||||
|
await webhintURL(base_url + HelloPageURL);
|
||||||
|
// alternatively you can use webhintHTML for faster but less precise scans
|
||||||
|
// or for scanning responses of requests that use some form of authorization:
|
||||||
|
// const response = await rest_api.get(HelloPageURL);
|
||||||
|
// await webhintHTML(response);
|
||||||
|
});
|
||||||
|
}).timeout(VERY_LONG_TEST_TIMEOUT);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("HelloPage", () => {
|
||||||
|
let page: Page;
|
||||||
|
let browser: Browser;
|
||||||
|
let context: BrowserContext;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
browser = await getBrowser();
|
||||||
|
context = await browser.newContext();
|
||||||
|
page = await context.newPage();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await context.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("works as expected", async function () {
|
||||||
|
return withProdApp(async ({ base_url }) => {
|
||||||
|
await page.goto(base_url + HelloPageURL);
|
||||||
|
});
|
||||||
|
}).timeout(VERY_LONG_TEST_TIMEOUT);
|
||||||
|
});
|
@ -38,7 +38,6 @@ export default new (class LoginForm extends Form<typeof fields, void> {
|
|||||||
|
|
||||||
async onSubmit(ctx: Context) {
|
async onSubmit(ctx: Context) {
|
||||||
const body = ctx.$body;
|
const body = ctx.$body;
|
||||||
console.log(body);
|
|
||||||
if (
|
if (
|
||||||
!hasShape({ username: predicates.string, password: predicates.string }, body)
|
!hasShape({ username: predicates.string, password: predicates.string }, body)
|
||||||
) {
|
) {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/consistent-type-assertions */
|
||||||
import type { Context } from "koa";
|
import type { Context } from "koa";
|
||||||
import { MeiliSearch } from "meilisearch";
|
import { MeiliSearch } from "meilisearch";
|
||||||
import type { CollectionItem } from "sealious";
|
import type { CollectionItem } from "sealious";
|
||||||
@ -31,10 +32,10 @@ export const createIndex = async (name: string) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const indexes = {} as Record<
|
const indexes: Record<
|
||||||
string,
|
string,
|
||||||
{ getItems: (ctx: Context, ids: string[]) => CollectionItem[] }
|
{ getItems: (ctx: Context, ids: string[]) => Promise<CollectionItem[]> }
|
||||||
>;
|
> = {};
|
||||||
|
|
||||||
export async function search(
|
export async function search(
|
||||||
ctx: Context,
|
ctx: Context,
|
||||||
@ -55,9 +56,9 @@ export async function search(
|
|||||||
const result = Object.fromEntries(
|
const result = Object.fromEntries(
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
use_indexes.map(async (index_name, key) => {
|
use_indexes.map(async (index_name, key) => {
|
||||||
const ids = results[key]!.hits.map((e) => e.id);
|
const ids = results[key]!.hits.map((e) => e.id as string);
|
||||||
const items = await indexes[index_name]?.getItems(ctx, ids);
|
const items = await indexes[index_name]?.getItems(ctx, ids);
|
||||||
return [index_name, items];
|
return <const>[index_name, items];
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
/* eslint-disable @typescript-eslint/consistent-type-assertions */
|
/* eslint-disable @typescript-eslint/consistent-type-assertions */
|
||||||
import type { Context } from "koa";
|
import type { Context } from "koa";
|
||||||
import qs from "qs";
|
import qs from "qs";
|
||||||
import { MEILISEARCH_HOST } from "./config.js";
|
|
||||||
|
|
||||||
export async function sleep(time: number) {
|
export async function sleep(time: number) {
|
||||||
return new Promise((resolve) => setTimeout(resolve, time));
|
return new Promise((resolve) => setTimeout(resolve, time));
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/consistent-type-assertions */
|
||||||
export * from "./controllers.js";
|
export * from "./controllers.js";
|
||||||
|
|
||||||
(function enableScrollPreservation() {
|
(function enableScrollPreservation() {
|
||||||
@ -23,6 +24,7 @@ export * from "./controllers.js";
|
|||||||
addEventListener("turbo:visit", () => {
|
addEventListener("turbo:visit", () => {
|
||||||
/* eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any */
|
/* eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any */
|
||||||
if (shouldPreserveScroll) {
|
if (shouldPreserveScroll) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
|
||||||
(window as any).Turbo.navigator.currentVisit.scrolled = true;
|
(window as any).Turbo.navigator.currentVisit.scrolled = true;
|
||||||
document.documentElement.scrollTop = scrollTop;
|
document.documentElement.scrollTop = scrollTop;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user