refac: migration crash, real-database tests, site deleted during create, ruels out of the repo, lists
This commit is contained in:
1 parent
680b9a1308
commit
9d284e65a9
62 files changed
+1858
-987
No files matched your search
@@ -1,10 +1,10 @@
|
||||
# Articles
|
||||
|
||||
Route: `/article`, `/articles?page=2&size=50`. API: GET /v1/article/ · PATCH …/publish · PATCH …/unpublish · DELETE /v1/article/{id} · GET /v1/article/?page=&size=&q=&status= (page, size; total in the X-Total-Count header; invalid values are normalised in the URL, never shown as an error).
|
||||
Route: `/article`, `/articles?page=2&size=50`. API: GET /v1/article/ · PATCH …/publish · PATCH …/unpublish · DELETE /v1/article/{id} · GET /v1/article/?page=&size=&q=&status=&site=&seo= returns { items, total, page, size, counts } (invalid values are normalised in the URL, never shown as an error).
|
||||
|
||||
Rows update when the server responds, not optimistically. Search, tab and sort are stored in the query string.
|
||||
|
||||
Visual reference: `RenewCMS Screens Back-office.dc.html`, groups "Articles", "Articles: pagination". Frames: `AppFrame.dc.html` (shell, sidebar, topbar, drawer) plus the screen frame where listed in components.md.
|
||||
Visual reference and pixel gate: `RenewCMS Screens Localization.dc.html`, group L7s (single-language site) and L7 (several languages), drawn by LocaleFrame with the shipped AppPaginator. The Back-office groups "Articles" and "Articles: pagination" are superseded for the list layout; they stay as the copy reference for states the new groups do not repeat. Frames: `AppFrame.dc.html` (shell, sidebar, topbar, drawer) plus the screen frame where listed in components.md.
|
||||
|
||||
## Copy per state (generated from the board source, pass 2)
|
||||
|
||||
@@ -47,12 +47,12 @@ Rows update when the server responds, not optimistically. Search, tab and sort a
|
||||
| 10 | Row vanished (404) | Any row action gets a 404. | "That article no longer exists" / "It was deleted somewhere else, so we removed it from the list." |
|
||||
| 11 | Delete: confirm | Delete… from the row menu. | |
|
||||
| 12 | Delete: in progress | DELETE in flight. The dialog can't be dismissed. | |
|
||||
| 13 | Delete: failed | 500, a partial failure where the article is kept. The error shows inside the dialog. | "Couldn't delete the article, so it's still there. Try again in a moment." |
|
||||
| 13 | Delete: failed | 500 or network failure. Deleting is atomic, so nothing is removed and every version is still there. The error shows inside the dialog. | "Couldn't delete the article." / "Nothing was deleted. Every version is still there. Try again in a moment." |
|
||||
| 14 | Deleted | 204: the row is removed and focus moves to the next row. This is also where a delete from the editor ends up. | "Article deleted" / ""Winter checklist for timber windows" and its images are gone." |
|
||||
|
||||
### Articles: pagination (group "Articles: pagination", 11 states)
|
||||
|
||||
Route: `/articles?page=2&size=50`. API: GET /v1/article/?page=&size=&q=&status= (page, size; total in the X-Total-Count header; invalid values are normalised in the URL, never shown as an error).
|
||||
Route: `/articles?page=2&size=50`. API: GET /v1/article/?page=&size=&q=&status=&site=&seo= returns { items, total, page, size, counts } (invalid values are normalised in the URL, never shown as an error).
|
||||
|
||||
Page and page size live in the URL as page and size. Defaults (page 1, size 25) are omitted. Allowed sizes 5, 25, 50, 100. Search, tab or sort changes reset to page 1. Rows equal the page size; the frames draw at most 10 rows. The paginator hides when everything fits on one page; the summary stays. Mobile shows Previous, "Page N of M" and Next. Keyboard: Tab reaches page size, first, previous, each page, next, last; Enter or Space activates; the current page has aria-current="page"; ArrowDown opens the page-size list, Enter selects, Esc closes.
|
||||
|
||||
@@ -99,3 +99,6 @@ A quiet indicator in the Status cell on desktop and under the title on mobile ca
|
||||
| 3 | Needs attention: none | Nothing to show with the toggle on. | Nothing needs attention · Every article has a clean check. Suggestions are optional, so this is just a bonus. · Show all articles |
|
||||
|
||||
Filter: "Needs attention" sets `?seo=suggestions` and resets `page` to 1. Tab counts do not change. Single-site installs behave the same; the Site filter stays hidden.
|
||||
|
||||
## Localization
|
||||
Localization: modes All languages (stories), Language selected (versions), Missing language (stories); mobile filter sheet, scrollable tabs, pager; state in URL. See routes.md.
|
||||
@@ -175,3 +175,6 @@ A read-only dialog (desktop, 720 px) or bottom sheet (mobile) with the resolved
|
||||
| 4 | Draft article | Drafts answer 404 to anonymous callers. | This article is a draft. The API returns this data only to signed-in callers until it is published. |
|
||||
| 5 | Loading | Copy is disabled. | – |
|
||||
| 6 | Error | GET failed. Nothing in the article changes. | Couldn't load the SEO data · GET /v1/article/12/seo failed. Your article is unchanged. Try again in a moment. · Try again |
|
||||
|
||||
## Localization
|
||||
Localization: actions render from per-version capabilities (read, edit, publish, delete, create-translation, review); title is an inline input; slug changes only via Edit slug. See Localization board.
|
||||
@@ -9,9 +9,9 @@ The conflict dialog gives four choices. Keep my changes is the only filled butto
|
||||
|
||||
| ID | State | Trigger | Selector | Sizes | Fixture |
|
||||
|---|---|---|---|---|---|
|
||||
| loc.l11.session | Session expired | Draft kept locally | LocaleFrame{s:{v:"pm",x:"session"}} | 1440, 390 | Journal |
|
||||
| loc.l11.session | Session expired | Draft kept in this browser; editor behind shows the unsaved changes | LocaleFrame{s:{v:"pm",x:"session"}} | 1440, 390 | Journal |
|
||||
| loc.l11.restored | Restored after login | Editor shows "Restored unsaved changes from 14:18" | LocaleFrame{s:{v:"pm",x:"restored"}} | 1440, 390 | Journal |
|
||||
| loc.conflict | Concurrent update | Four choices, local work kept | LocaleFrame{s:{v:"pm",x:"conflict"}} | 1440, 390 | Journal |
|
||||
| loc.conflict | Concurrent update | Four choices, local work kept; Save over theirs outlined in error colour with a warning icon | LocaleFrame{s:{v:"pm",x:"conflict"}} | 1440, 390 | Journal |
|
||||
| loc.l11.conflictRestored | Concurrent update after session expiry | Restored changes notice above the choices | LocaleFrame{s:{v:"pm",x:"conflictRestored"}} | 1440, 390 | Journal |
|
||||
| loc.l11.reloadConfirm | Reload theirs: confirm | "This discards your unsaved changes." | LocaleFrame{s:{v:"pm",x:"reloadConfirm"}} | 1440, 390 | Journal |
|
||||
| loc.l11.conflict2 | Second conflict | Save over theirs failed again; nothing overwritten | LocaleFrame{s:{v:"pm",x:"conflict2"}} | 1440, 390 | Journal |
|
||||
@@ -31,5 +31,6 @@ Entry point is the site select in the editor details. Articles move as a whole,
|
||||
| loc.l11b.moveBusy | In progress | Dialog locked | LocaleFrame{s:{v:"pm",x:"moveBusy"}} | 1440, 390 | Journal |
|
||||
| loc.l11b.moveDone | Moved | Toast | LocaleFrame{s:{v:"pm",x:"moveDone"}} | 1440, 390 | Journal |
|
||||
| loc.l11b.move | Language missing in destination | Notes enables English only | LocaleFrame{s:{v:"pm",x:"move"}} | 1440, 390 | Journal, Notes |
|
||||
| loc.l11b.moveSlug | Address conflict | Names the conflicting readable version only | LocaleFrame{s:{v:"pm",x:"moveSlug"}} | 1440, 390 | Journal, Atelier |
|
||||
| loc.l11b.moveSlug | Address conflict | Names the conflicting readable version and its address; unreadable ones are never named | LocaleFrame{s:{v:"pm",x:"moveSlug"}} | 1440, 390 | Journal, Atelier |
|
||||
| loc.l11b.movePerm | No permission | Neutral | LocaleFrame{s:{v:"pm",x:"movePerm"}} | 1440, 390 | Journal |
|
||||
| loc.l11b.moveFail | Move failed | Server error, nothing moved | LocaleFrame{s:{v:"pm",x:"moveFail"}} | 1440, 390 | Journal |
|
||||
@@ -34,6 +34,7 @@ Header priority and the action matrix are in the tables below. One filled primar
|
||||
| loc.l5.titleLong | Title: too long | Over 200 characters | LocaleFrame{s:{v:"ed",x:"titleLong"}} | 1440, 390 | Journal |
|
||||
| loc.l5.titleSaving | Title: saving | Save in flight | LocaleFrame{s:{v:"ed",x:"titleSaving"}} | 1440, 390 | Journal |
|
||||
| loc.l5.failed | Title: save failed | Text kept, still unsaved, Try again | LocaleFrame{s:{v:"ed",x:"failed"}} | 1440, 390 | Journal |
|
||||
| loc.l5.menuDisabled | Language menu with a disabled language | Spanish is disabled: Disabled tag, version stays readable | LocaleFrame{s:{v:"ed",x:"menuDisabled"}} | 1440, 390 | Journal |
|
||||
|
||||
## L5b Permission states (per version)
|
||||
Route: /article/{id}/edit
|
||||
@@ -64,13 +65,16 @@ Every action names its language. No bulk publish. With unsaved edits the primary
|
||||
| loc.l8.publish | Publish French | Confirm, English untouched | LocaleFrame{s:{v:"pd",x:"publish"}} | 1440, 390 | Journal |
|
||||
| loc.lang.publishDisabled | Publishing blocked: language disabled | French disabled on the site | LocaleFrame{s:{v:"pd",x:"publishDisabled"}} | 1440, 390 | Journal |
|
||||
| loc.l8.saveAndPublish | Save and publish French | Unsaved edits: saves first, then publishes | LocaleFrame{s:{v:"pd",x:"saveAndPublish"}} | 1440, 390 | Journal |
|
||||
| loc.l8.saveFailPublish | Save failed, nothing published | Toast; edits kept and retryable | LocaleFrame{s:{v:"pd",x:"saveFailPublish"}} | 1440, 390 | Journal |
|
||||
| loc.l8.saveFailPublish | Save failed, nothing published | Error banner above the editor and an error toast; Save failed badge, primary Try saving again, edits kept, nothing published | LocaleFrame{s:{v:"pd",x:"saveFailPublish"}} | 1440, 390 | Journal |
|
||||
| loc.l8.unpublish | Unpublish French | Confirm | LocaleFrame{s:{v:"pd",x:"unpublish"}} | 1440, 390 | Journal |
|
||||
| loc.l8.unpublishDirty | Unpublish with unsaved edits | Saved version goes offline; edits kept; nothing saved | LocaleFrame{s:{v:"pd",x:"unpublishDirty"}} | 1440, 390 | Journal |
|
||||
| loc.l8.delete | Delete French version | Confirm | LocaleFrame{s:{v:"pd",x:"delete"}} | 1440, 390 | Journal |
|
||||
| loc.l8.deleteSource | Delete a source version | Warns about review tracking | LocaleFrame{s:{v:"pd",x:"deleteSource"}} | 1440, 390 | Journal |
|
||||
| loc.l8.deleteSource | Delete a source version | Names the readable versions that track the source; warns review tracking pauses | LocaleFrame{s:{v:"pd",x:"deleteSource"}} | 1440, 390 | Journal |
|
||||
| loc.l8.deleteLast | Delete the only version | Deletes the article | LocaleFrame{s:{v:"pd",x:"deleteLast"}} | 1440, 390 | Journal |
|
||||
| loc.l8.deleteStoryOk | Delete article (all readable versions) | Names readable versions only | LocaleFrame{s:{v:"pd",x:"deleteStoryOk"}} | 1440, 390 | Journal |
|
||||
| loc.l8.deleteStory | Delete article blocked | Neutral, no version named | LocaleFrame{s:{v:"pd",x:"deleteStory"}} | 1440, 390 | Journal |
|
||||
| loc.l8.done | Published | Toast | LocaleFrame{s:{v:"pd",x:"done"}} | 1440, 390 | Journal |
|
||||
| loc.l8.done | Published | Toast "French published" and the online banner; badge Published, status Saved | LocaleFrame{s:{v:"pd",x:"done"}} | 1440, 390 | Journal |
|
||||
| loc.l8.fail | Publish failed | Toast | LocaleFrame{s:{v:"pd",x:"fail"}} | 1440, 390 | Journal |
|
||||
| loc.l8.deleteDone | French version deleted | Toast; editor opens English | LocaleFrame{s:{v:"pd",x:"deleteDone"}} | 1440, 390 | Journal |
|
||||
| loc.l8.deleteStoryFail | Delete article failed | Dialog error; nothing deleted | LocaleFrame{s:{v:"pd",x:"deleteStoryFail"}} | 1440, 390 | Journal |
|
||||
| loc.l8.deleteStoryDone | Article deleted | Toast on the Articles list | LocaleFrame{s:{v:"li",x:"deleteStoryDone"}} | 1440, 390 | Journal |
|
||||
@@ -25,3 +25,19 @@ Journal: 8 articles, 17 versions, page size 5. The list header shows the unit: "
|
||||
| loc.l7.filters | Mobile filter sheet | Journal, French, Draft: 2 results | LocaleFrame{s:{v:"li",x:"filters"}} | 1440, 1024, 390 | Journal |
|
||||
| loc.l7.tabsScroll | Tabs scrolled | Not in French reachable; fade and chevrons | LocaleFrame{s:{v:"li",x:"tabsScroll"}} | 1440, 390 | Journal |
|
||||
| loc.l7.long | Eight languages, long labels, filters | Atelier: chips collapse to +3, +4, +4; Draft and SEO filters | LocaleFrame{s:{v:"li",x:"long"}} | 1440, 1024, 390 | Atelier |
|
||||
|
||||
## L7s Article list, single-language site
|
||||
Route: /articles?site=archive&q&status&page&size
|
||||
API: GET /v1/article/?page=&size=&q=&status=&site= returns { items, total, page, size, counts }
|
||||
|
||||
Replaces the old Articles board frames as the pixel-gate reference for the list. A site with one language has no language filter, no coverage column, no Needs translation or Needs review tabs, and its menu labels name no language. The pager is AppPaginator: summary "Showing 1–5 of 5", rows-per-page select, first, previous, page numbers, next and last (390 px: summary and select, then Previous, "Page N of M", Next). Hidden controls when everything fits on one page; the summary stays.
|
||||
|
||||
| ID | State | Trigger | Selector | Sizes | Fixture |
|
||||
|---|---|---|---|---|---|
|
||||
| loc.l7s.default | Default | Archive: 5 articles on one page, no language filter, coverage column or tabs | LocaleFrame{s:{v:"li",x:"single"}} | 1440, 390 | Archive |
|
||||
| loc.l7s.draft | Draft filter | Status: Draft | LocaleFrame{s:{v:"li",x:"singleDraft"}} | 1440, 390 | Archive |
|
||||
| loc.l7s.noResults | No results | Search "zinc" | LocaleFrame{s:{v:"li",x:"singleNoResults"}} | 1440, 390 | Archive |
|
||||
| loc.l7s.empty | Empty | Gallery: no articles | LocaleFrame{s:{v:"li",x:"singleEmpty"}} | 1440, 390 | Gallery |
|
||||
| loc.l7s.loading | Loading | Counts shown as – | LocaleFrame{s:{v:"li",x:"singleLoading"}} | 1440, 390 | Archive |
|
||||
| loc.l7s.fail | Failed | Filters kept | LocaleFrame{s:{v:"li",x:"singleFail"}} | 1440, 390 | Archive |
|
||||
| loc.l7s.menu | Row menu | Open, Unpublish, Copy API URL, Delete article: no language named | LocaleFrame{s:{v:"li",x:"singleMenu"}} | 1440, 390 | Archive |
|
||||
@@ -9,8 +9,8 @@ Slug is unique per (site, lang). Exact lookup is by site + language + slug and n
|
||||
|
||||
| ID | State | Trigger | Selector | Sizes | Fixture |
|
||||
|---|---|---|---|---|---|
|
||||
| loc.seo.noFallback | Search and sharing: French | Localized slug, canonical, alternates, fallback labels, Edit slug | LocaleFrame{s:{v:"seo",x:""}} | 1440, 390 | Journal |
|
||||
| loc.slug.published | Edit slug | Published version: warning about old links | LocaleFrame{s:{v:"seo",x:"editSlug"}} | 1440, 390 | Journal |
|
||||
| loc.url.unset | Public URL not configured | No pattern, no fabricated URL | LocaleFrame{s:{v:"seo",x:"unset"}} | 1440, 390 | Journal |
|
||||
| loc.l10.noSocial | Social locale not set | fr has no region and none is set: og:locale omitted | LocaleFrame{s:{v:"seo",x:"noSocial"}} | 1440, 390 | Journal |
|
||||
| loc.l10.api | Integration: languages | Exact lookup, resolve by article group, errors | LocaleFrame{s:{v:"api",x:""}} | 1440, 390 | Journal |
|
||||
| loc.seo.noFallback | Search and sharing: French | Search and sharing slide-over on the editor: localized slug, canonical, alternates, fallback labels, Edit slug | LocaleFrame{s:{v:"seo",x:""}} | 1440, 390 | Journal |
|
||||
| loc.slug.published | Edit slug | Edit slug dialog over the Search and sharing slide-over: published version warns about old links | LocaleFrame{s:{v:"seo",x:"editSlug"}} | 1440, 390 | Journal |
|
||||
| loc.url.unset | Public URL not configured | Search and sharing slide-over: no pattern, no fabricated URL | LocaleFrame{s:{v:"seo",x:"unset"}} | 1440, 390 | Journal |
|
||||
| loc.l10.noSocial | Social locale not set | Search and sharing slide-over: fr has no region and none is set, og:locale omitted | LocaleFrame{s:{v:"seo",x:"noSocial"}} | 1440, 390 | Journal |
|
||||
| loc.l10.api | Integration: languages | Integration page: exact lookup, resolve by article group, errors | LocaleFrame{s:{v:"api",x:""}} | 1440, 390 | Journal |
|
||||
@@ -11,7 +11,7 @@ Single-language sites show no language field. Multilingual sites show Language a
|
||||
|---|---|---|---|---|---|
|
||||
| loc.l3.single | Single language | Title and site only | LocaleFrame{s:{v:"na",x:"single"}} | 1440, 390 | Archive |
|
||||
| loc.l3.multi | Multilingual: new article | Language defaults to the site default | LocaleFrame{s:{v:"na",x:"multi"}} | 1440, 390 | Journal |
|
||||
| loc.l3.translation | Translation of an article | Article picker + language | LocaleFrame{s:{v:"na",x:"translation"}} | 1440, 390 | Journal |
|
||||
| loc.l3.translation | Translation of an article | Same fields as Add translation: article, language, source version, title, starting content | LocaleFrame{s:{v:"na",x:"translation"}} | 1440, 390 | Journal |
|
||||
| loc.l3.sitechange | Site changed | Selected language not offered by the new site | LocaleFrame{s:{v:"na",x:"sitechange"}} | 1440, 390 | Journal, Notes |
|
||||
|
||||
## L4 Add a translation
|
||||
@@ -23,12 +23,12 @@ Always creates a draft. Source: the user picks which readable version to copy fr
|
||||
| ID | State | Trigger | Selector | Sizes | Fixture |
|
||||
|---|---|---|---|---|---|
|
||||
| loc.l4.form | Copy from source | Editor → language menu → Add translation | LocaleFrame{s:{v:"at",x:"form"}} | 1440, 390 | Journal |
|
||||
| loc.l4.empty | Start empty | Title only | LocaleFrame{s:{v:"at",x:"empty"}} | 1440, 390 | Journal |
|
||||
| loc.l4.empty | Start empty | Title only; Source version reads No source, Freshness will show No source | LocaleFrame{s:{v:"at",x:"empty"}} | 1440, 390 | Journal |
|
||||
| loc.l4.saving | Creating | Submit in flight | LocaleFrame{s:{v:"at",x:"saving"}} | 1440, 390 | Journal |
|
||||
| loc.dup.readable | Exists, readable | Conflict; Open offered | LocaleFrame{s:{v:"at",x:"dup"}} | 1440, 390 | Journal |
|
||||
| loc.dup.hidden | Exists, not readable | Neutral error, no Open | LocaleFrame{s:{v:"at",x:"dupHidden"}} | 1440, 390 | Journal |
|
||||
| loc.l4.fail | Failed | Server error, entries kept | LocaleFrame{s:{v:"at",x:"fail"}} | 1440, 390 | Journal |
|
||||
| loc.l4.gone | Source deleted | Deleted while the dialog was open | LocaleFrame{s:{v:"at",x:"gone"}} | 1440, 390 | Journal |
|
||||
| loc.l4.unreadable | Source no longer readable | Access lost between opening and submitting | LocaleFrame{s:{v:"at",x:"unreadable"}} | 1440, 390 | Journal |
|
||||
| loc.l4.gone | Source deleted | Deleted while the dialog was open: same neutral message as unreadable, no distinction shown | LocaleFrame{s:{v:"at",x:"gone"}} | 1440, 390 | Journal |
|
||||
| loc.l4.unreadable | Source no longer readable | Access lost between opening and submitting: same neutral message as deleted | LocaleFrame{s:{v:"at",x:"unreadable"}} | 1440, 390 | Journal |
|
||||
| loc.l4.langOff | Language disabled mid-flow | An owner disabled French while the dialog was open | LocaleFrame{s:{v:"at",x:"langOff"}} | 1440, 390 | Journal |
|
||||
| loc.l4.long | Long dialog | Long title, many authors and images; body scrolls, footer stays | LocaleFrame{s:{v:"at",x:"long"}} | 1440, 390 | Journal |
|
||||
@@ -52,6 +52,7 @@ Owner-only. One pattern per site, for example https://example.com/{lang}/{slug}.
|
||||
| loc.l1b.saved | Saved | Toast | LocaleFrame{s:{v:"pu",x:"saved"}} | 1440, 390 | Journal |
|
||||
| loc.l1b.unset | Unset | No pattern; opened from "Public URL not configured" | LocaleFrame{s:{v:"pu",x:"unset"}} | 1440, 390 | Journal |
|
||||
| loc.l1b.viewOnly | Read-only view | Non-owner: pattern readable, no controls | LocaleFrame{s:{v:"pu",x:"viewOnly"}} | 1440, 390 | Journal |
|
||||
| loc.l1b.invalidHost | Invalid host | Pattern with an empty host label | LocaleFrame{s:{v:"pu",x:"invalidHost"}} | 1440, 390 | Journal |
|
||||
|
||||
## L2 First-time setup for existing articles
|
||||
Route: /settings/sites/:key/languages/setup
|
||||
|
||||
@@ -12,8 +12,9 @@ Single-language sites show none of this. Home counts articles, not versions.
|
||||
| loc.l12.home | Home: recent articles | Default-language title; code only when not default | LocaleFrame{s:{v:"sf",x:"home"}} | 1440, 1024, 390 | Journal |
|
||||
| loc.l12.homeFr | Home: reader of French only | Titles in French with code FR | LocaleFrame{s:{v:"sf",x:"homeFr"}} | 1440, 1024, 390 | Journal |
|
||||
| loc.l12.activity | Activity | Events name the language | LocaleFrame{s:{v:"sf",x:"activity"}} | 1440, 1024, 390 | Journal |
|
||||
| loc.l12.media | Media usage | Shared image counted once, versions listed | LocaleFrame{s:{v:"sf",x:"media"}} | 1440, 1024, 390 | Journal |
|
||||
| loc.l12.menu | Article menu labels | Publish and Delete name the language | LocaleFrame{s:{v:"sf",x:"menu"}} | 1440, 390 | Journal |
|
||||
| loc.l12.apiCopy | API URL copy | Copies the version URL with ?lang= | LocaleFrame{s:{v:"sf",x:"apiCopy"}} | 1440, 390 | Journal |
|
||||
| loc.l12.seoPreview | SEO preview | Localized address and canonical | LocaleFrame{s:{v:"sf",x:"seoPreview"}} | 1440, 390 | Journal |
|
||||
| loc.l12.siteFallback | Site text fallback | Used only when its language matches the article | LocaleFrame{s:{v:"sf",x:"siteFallback"}} | 1440, 390 | Journal |
|
||||
| loc.l12.media | Media usage | Media page with the image detail panel: shared image counted once, versions listed, "Used in 2" | LocaleFrame{s:{v:"sf",x:"media"}} | 1440, 1024, 390 | Journal |
|
||||
| loc.l12.mediaElsewhere | Media usage: used elsewhere only | Image used only as an author avatar: badge "Used in 1", "Articles" with "No article shows it.", "Used elsewhere" with Author avatar linking to /authors | LocaleFrame{s:{v:"sf",x:"mediaElsewhere"}} | 1440, 390 | Journal |
|
||||
| loc.l12.menu | Article menu labels | Articles list, French selected: row menu names the language (Publish French, Delete French version). Bottom sheet at 390 | LocaleFrame{s:{v:"li",x:"menuLang"}} | 1440, 390 | Journal |
|
||||
| loc.l12.apiCopy | API URL copy | Articles list: toast after Copy API URL with the ?lang= address. Bottom toast at 390 | LocaleFrame{s:{v:"li",x:"apiCopy"}} | 1440, 390 | Journal |
|
||||
| loc.l12.seoPreview | SEO preview | Search and sharing slide-over: localized address and canonical | LocaleFrame{s:{v:"seo",x:"preview"}} | 1440, 390 | Journal |
|
||||
| loc.l12.siteFallback | Site text fallback | Search and sharing slide-over: site text used only in its own language | LocaleFrame{s:{v:"seo",x:"siteFallback"}} | 1440, 390 | Journal |
|
||||
@@ -23,3 +23,6 @@ Recommendation: a modal. Title is the only field. The body is not asked for here
|
||||
| 3 | Submitting | Request in flight. Fields are disabled and the dialog can't be dismissed. | "Creating…" / "Choosing tiles for a small bathroom" |
|
||||
| 4 | Title rejected (400) | A server 400 that got past the browser checks. The raw error isn't shown. | "Something in the form isn't valid. Check the highlighted fields." / "Choosing tiles for a small bathroom" / "Check this title and try again." |
|
||||
| 5 | Error | 500 or network failure. | "Couldn't create the article. Your text is still here. Try again in a moment." / "Choosing tiles for a small bathroom" |
|
||||
|
||||
## Localization
|
||||
Localization: multilingual sites show Language and New story / Translation of; same rules as POST /v1/article/{id}/translations.
|
||||
Reference in new issue
Block a user