Fix the two checks the full run 304 found red
game-maker / gate (push) Successful in 3m42s
game-maker / suite (push) Successful in 14m23s

The full CI run on 4c7861b had two red checks. Neither showed when
only the touched modules ran, because each needs a module before it.

- e2e 40c-iii (#347): a stroke on a tilemap drew the captions
  "Comment" and "Held" again. They are a note and a group that e2e 36
  leaves in a graph. AnnotationView gave its caption a new TextStyle
  on every redraw, and Pixi draws a text again for a new style. The
  graph redraws on every edit of the project. The caption now keeps
  its style while colour and width stay the same.
- e2e 49a: a plain user deleting a shared file got 404 instead of
  403. Since #344 the DELETE route asked whether the file exists
  before whose it is. It now refuses a stranger first, so another
  folder tells them nothing. The wiki's API page says so.

Tests:
- Unit annotation-view (new): 2 green, counter-check 1 red
- e2e 36,39,40,49 (melektaus-atx): both checks green, 49 then hit a
  harness timeout (CDP Network.enable) once
- e2e 49 alone (melektaus-atx): ALL PASSED - 22 checks
- Gate (melektaus-atx): CHECK EXIT 0, 261 files, 4040 tests

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 5.5 committed 2026-10-07 17:26:35 +02:00
1 parent 4c7861b5b8
commit 8154569405
3 files changed
+47 -3

No files matched your search

+4 -3
View File
@@ -532,13 +532,14 @@ function routeFiles(
if ($method === 'DELETE') {
$file = implode('/', array_slice($parts, 1));
if (!$store->exists($file)) {
Response::error("{$noun} not found", 404);
}
// Asked before whether there is one: somebody else's folder tells a stranger nothing.
$folder = HashedFileStore::folderOf($file);
if (!$isAdmin && ($folder === '' || $folder !== $users->folderOf($user))) {
Response::error('Only its owner may delete this file', 403);
}
if (!$store->exists($file)) {
Response::error("{$noun} not found", 404);
}
$uses = (new FileUsage(dirname(__DIR__) . '/data'))->of($file);
if ($uses !== []) {
Response::error(FileUsage::refusal($uses, $user, $isAdmin), 409);
+8
View File
@@ -18,6 +18,8 @@ const PAD = 8;
export class AnnotationView extends Widget {
private readonly box = new Graphics();
private readonly caption: Text;
/** Colour and width of the caption's style, see `redraw`. */
private styleKey = '';
selected = false;
constructor(
@@ -105,7 +107,13 @@ export class AnnotationView extends Widget {
.lineTo(this.w - 2, this.h - RESIZE_HANDLE / 2)
.stroke({ width: 1, color: text, alpha: 0.5 });
// A new style draws the caption again even when nothing changed, and the graph redraws on every
// edit of the project, a stroke on a tilemap included (#347). So only a new colour or width sets one.
const styleKey = `${text}|${this.w}`;
if (styleKey !== this.styleKey) {
this.styleKey = styleKey;
this.caption.style = this.captionStyle(text);
}
this.caption.text =
this.kind === 'group'
? truncate(this.annotation.text, this.caption.style, Math.max(this.w - PAD * 2, 1))
+35
View File
@@ -0,0 +1,35 @@
/**
* A graph draws its groups and comments again on every edit of the project, a stroke on a tilemap
* included. A caption that is given a new style is drawn again as text, so it keeps its style for as
* long as colour and width stay the same (#347).
*/
import type { Text } from 'pixi.js';
import { describe, expect, it } from 'vitest';
import { AnnotationView } from '../../src/editor/graph/AnnotationView';
const note = { id: 'n1', x: 0, y: 0, w: 200, h: 120, text: 'Comment' };
const captionOf = (view: AnnotationView) => view.children[1] as Text;
describe('the caption of a group or comment', () => {
// A comment only: a group's title is cut to its width by measuring it, which needs a canvas. The
// groups are seen in the browser, in e2e 40c-iii.
it('keeps its style through a redraw that changes nothing', () => {
const view = new AnnotationView({ ...note }, 'note');
const style = captionOf(view).style;
view.redraw();
view.sync({ ...note });
expect(captionOf(view).style).toBe(style);
});
it('is given a new style for a new width or colour', () => {
const view = new AnnotationView({ ...note }, 'note');
const style = captionOf(view).style;
view.sync({ ...note, w: 260 });
const wider = captionOf(view).style;
expect(wider).not.toBe(style);
expect(wider.wordWrapWidth).toBe(260 - 16);
view.sync({ ...note, w: 260, color: 0xffffff });
expect(captionOf(view).style).not.toBe(wider);
expect(captionOf(view).style.fill).not.toBe(wider.fill);
});
});