Card Settings: a checkbox per section, always every field, only in Board Settings.

Card Settings is now only Board Settings / Card. The opened card has no
Card Settings button any more: it simply shows every field its board
shows on cards, empty or not.

- On this card, Show empty and Show empty fields are removed, with the
  hamburgers' Select all / Select none rows, their handlers, helpers,
  board methods (setCardFieldAlwaysShown, setShowEmptyCardFields), CSS
  and the three translation keys. The card no longer reads its own
  shownFields / hiddenFields, nor the board's cardFieldsAlwaysShown /
  showEmptyCardFields; the schema keeps them so old documents validate.
- Every section has a checkbox before its title: whether the whole
  section is shown on the chosen side, whatever its rows are ticked.
  Stored per side in cardSettingsHiddenOnCard / cardSettingsHiddenOnMinicard
  (setCardSettingsSectionShown, board admins). The opened card's view
  of the board and a new minicard view read false for every row of a
  hidden section, Scrum fields included; Card Settings itself reads the
  raw board, so the rows keep their ticks.
- A section with one row on the chosen side is one line: one checkbox,
  the name, one hamburger.
- A hamburger is drawn only when it holds something.
- Custom Fields: its items are the board's custom fields, in their sort
  order, reordered by drag and drop within the section, with a + under
  them that creates one. Show on Minicard sets a field's showOnCard,
  Show on Card its alwaysOnCard; its hamburger edits the field. The
  section's checkbox is the board's Custom Fields flag of that side.
- Card actions (Filter: Subtasks, Edit voting, Card kind, ...) live in
  the card's own section hamburgers; Card Settings keeps only board
  actions.

Docs: docs/Features/Cards/Card-Settings.md replaces
Card-Settings-On-Card.md; Card-Fields.md and Board Settings / Card.md
rewritten. New tests cardSettingsSectionShown and
cardSettingsCustomFields; the guards of the removed behaviour say why
they changed; card-add-fields.e2e.js covers section hiding per side, an
empty card showing every field, empty hamburgers, the one-row line, the
Custom Fields items and +, and that the opened card has no Card
Settings.

Thanks to xet7 !
This commit is contained in:
Lauri Ojansivu committed 2026-10-28 22:43:29 +02:00
1 parent 039935dd0b
commit 3e5bc58105
285 files changed
+2243 -2976

No files matched your search

@@ -52,8 +52,14 @@ const boardFor = context => ReactiveCache.getBoard(context?.record?.boardId || S
// `field` (a definition suffix, 'Sprint') draws one field alone: on a card and
// a minicard each Scrum field sits where the board's Board Settings / Card
// order puts it (models/lib/cardFieldOrder.js SCRUM_FIELD_KEYS).
// Read through the board as that side sees it (models/lib/cardShownFields.js
// boardForSide): a Scrum section hidden whole on Show on Card or Show on
// Minicard in Card Settings hides these fields there too. The settings above
// (scrumFieldSettings) read the board itself.
function visibleFields(context) {
const board = boardFor(context);
const { boardForSide } = require('/models/lib/cardShownFields');
const side = context?.kind === 'card' || context?.kind === 'minicard' ? context.kind : null;
const board = side ? boardForSide(boardFor(context), side) : boardFor(context);
return (definitions[context?.kind] || []).filter(([suffix]) => (!context.field || context.field === suffix) &&
board?.scrum?.visibility?.[`${context.kind}${suffix}`] === true);
}
+27 -30
View File
@@ -1,26 +1,6 @@
/* "Card Settings" on the opened card (docs/Features/Cards/Card-Settings-On-Card.md):
it replaces itself, and everything below it, with Card Settings on the card. */
.card-details-add-fields { padding: 4px 0 2px; }
.card-details-add-fields-button { display: inline-flex; align-items: center; gap: 0.3em; padding: 2px 8px; border-radius: 3px; }
.card-details-add-fields-button:hover { background: rgba(0, 0, 0, 0.06); }
/* Card Settings on the card: the title with its X at the end of the line,
/* Card Settings (Board Settings / Card, docs/Features/Cards/Card-Settings.md):
"Show" and its two choices, then the sections drawn like checklists. */
.card-settings-inline { padding: 4px 0 8px; }
.card-settings-inline-head {
display: flex;
align-items: center;
gap: 8px;
}
.card-settings-inline-title { flex: 1 1 auto; margin: 0; }
.card-settings-inline-close {
padding: 2px 8px;
border-radius: 3px;
color: inherit;
text-decoration: none;
}
.card-settings-inline-close:hover,
.card-settings-inline-close:focus-visible { background: rgba(0, 0, 0, 0.06); }
.card-settings-inline-show {
display: flex;
flex-wrap: wrap;
@@ -78,8 +58,33 @@
.card-settings-inline-collapse:focus-visible,
.card-settings-inline-menu:hover,
.card-settings-inline-menu:focus-visible { color: #2980b9; }
/* The section's own checkbox, left of its title: the rows' look. A section
hidden whole on this side keeps its rows' ticks, drawn faded. */
.card-settings-section-side { flex: 0 0 auto; }
.card-settings-section-side > a.flex { margin: 0; }
.card-settings-inline-section.is-section-hidden .card-settings-inline-items { opacity: 0.55; }
/* One row on this side: one line, no caret - its checkbox where the other
sections' checkboxes are. */
.card-settings-inline-section.is-single .card-settings-inline-section-head {
padding-inline-start: calc(0.5em + 8px);
}
/* "+" under Custom Fields' items: a new custom field. */
.card-settings-add-custom-field { padding: 2px 0 0 22px; }
.card-settings-add-custom-field-button {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 28px;
min-height: 28px;
border-radius: 3px;
color: #808080;
text-decoration: none;
}
.card-settings-add-custom-field-button:hover,
.card-settings-add-custom-field-button:focus-visible { background: rgba(0, 0, 0, 0.06); color: #2980b9; }
/* Collapsed: the items hidden, not removed, so their drag stays bound. */
.card-settings-inline-section.is-collapsed .card-settings-inline-items { display: none; }
.card-settings-inline-section.is-collapsed .card-settings-inline-items,
.card-settings-inline-section.is-collapsed .card-settings-add-custom-field { display: none; }
/* An item: the checkbox, the name, and its hamburger at the end
(sidebar.css .card-settings-line is the line itself). */
@@ -100,14 +105,6 @@
.card-settings-item-menu .is-animating .materialCheckBox { transition: 0.2s; }
/* The hamburgers' popups. */
.card-settings-section-menu .card-settings-section-menu-select {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 4px 8px;
padding: 4px 0;
}
.card-settings-item-menu,
.card-settings-section-menu { min-width: 16em; }
/* The hamburgers' checkboxes: a space's width before their label, as on
+11 -97
View File
@@ -1,66 +1,23 @@
import './cardDetails.jade';
import { ReactiveCache } from '/imports/reactiveCache';
import { Utils } from '/client/lib/utils';
import { ReactiveVar } from 'meteor/reactive-var';
// docs/Features/Cards/Card-Fields.md: an opened card shows only the fields it
// has data in - and what its board always shows (by default its description,
// attachments and comments), empty or not - and "+ Add" chooses the rest. The rules are models/lib/cardShownFields.js.
// docs/Features/Cards/Card-Fields.md: an opened card shows every field its
// board shows on cards, empty or not, less the Card Settings sections the
// board hides on Show on Card. The rules are models/lib/cardShownFields.js.
const f = require('/models/lib/cardShownFields');
// What lives in other collections, for "has data".
function countOf(list) {
if (!list) return 0;
if (typeof list.length === 'number') return list.length;
return typeof list.count === 'function' ? list.count() : 0;
}
export function cardFieldCounts(card) {
if (!card || !card._id) return {};
return {
checklists: typeof card.checklists === 'function' ? countOf(card.checklists()) : 0,
subtasks: typeof card.subtasks === 'function' ? countOf(card.subtasks()) : 0,
textNotes: countOf(ReactiveCache.getCardTextNotes({ cardId: card._id })),
// For a board that does not always show these: shown when there are some.
attachments: typeof card.attachments === 'function' ? countOf(card.attachments()) : 0,
comments: typeof card.comments === 'function' ? countOf(card.comments()) : 0,
};
}
// The card's document, with its methods, for a template's data.
function cardOf(data) {
if (!data || !data._id) return null;
return ReactiveCache.getCard(data._id) || data;
}
// What decides which fields `card` shows: its DATA, which a linked card keeps
// on its source card (members, labels, dates, custom fields, checklists ...),
// and its own choices (shownFields / hiddenFields, set on the card opened).
// Reading the linked card's own empty document hid every field its source
// has (the #1946/#6613 browser test). Returns { card, counts }.
export function shownFieldsOf(card) {
if (!card) return { card: null, counts: {} };
const real = typeof card.getRealCard === 'function' ? (card.getRealCard() || card) : card;
if (real === card) return { card, counts: cardFieldCounts(card) };
return {
card: { ...real, shownFields: card.shownFields, hiddenFields: card.hiddenFields },
counts: cardFieldCounts(real),
};
}
// The board as this card sees it (cardShownFields.js boardForCard).
export function cardBoardView(data) {
const board = Utils.getCurrentBoard();
const card = cardOf(data);
if (!board || !card || card.boardId !== board._id) return board;
const view = shownFieldsOf(card);
return f.boardForCard(board, view.card, view.counts);
// The board as its opened cards see it (cardShownFields.js boardForCard): the
// same for every card of the board, empty or not, so `data` (the card) does
// not change it - it is kept so the callers read as before.
export function cardBoardView(data) { // eslint-disable-line no-unused-vars
return f.boardForCard(Utils.getCurrentBoard());
}
// The opened card and each of its section templates read `currentBoard`; this
// template-level helper answers before the global one, so every
// `currentBoard.allowsX` in them asks this card's view - and a template not
// listed here (the minicard, the board) is unchanged.
// `currentBoard.allowsX` in them asks the card's view - and a template not
// listed here (the board, Card Settings itself) is unchanged. The minicard has
// its own (client/components/cards/minicard.js MINICARD_FIELD_TEMPLATES).
export const CARD_FIELD_TEMPLATES = Object.freeze([
'cardDetails', 'cardFieldSectionLabels', 'cardFieldSectionDates', 'cardFieldSectionMembers',
'cardFieldSectionDependencies', 'cardFieldSectionSort', 'cardFieldSectionCustomFields',
@@ -74,46 +31,3 @@ CARD_FIELD_TEMPLATES.forEach(name => {
},
});
});
// Whether this card shows the field `key` - for a section with no board flag
// of its own to read (the Scrum fields, cardDetails.js orderedCardFieldSections).
export function cardShowsField(data, key) {
const card = cardOf(data);
if (!card) return true;
const view = shownFieldsOf(card);
return f.isShown(key, view.card, view.counts, Utils.getCurrentBoard());
}
// "Card Settings" on the opened card: the button and everything below it are
// replaced by Card Settings itself, on the card (cardSettingsInline,
// client/components/sidebar/sidebar.jade) - its sections as checklists, their
// rows as checklist items - until its X closes it. The id of the card it is
// open on; a card opened next has it closed.
const cardSettingsOpenOn = new ReactiveVar(null);
export function isCardSettingsOpen(cardId) {
return Boolean(cardId) && cardSettingsOpenOn.get() === cardId;
}
export function closeCardSettings() {
cardSettingsOpenOn.set(null);
}
Template.cardDetails.helpers({
cardSettingsOpen() {
return isCardSettingsOpen(this && this._id);
},
});
Template.cardDetails.onDestroyed(function () {
if (isCardSettingsOpen(this.data && this.data._id)) closeCardSettings();
});
Template.cardDetails.events({
'click .js-open-card-add-fields'(event) {
event.preventDefault();
const card = cardOf(Template.currentData());
if (!card) return;
cardSettingsOpenOn.set(card._id);
},
});
+147 -161
View File
@@ -159,169 +159,158 @@ template(name="cardDetails")
.card-details-cover
img.card-details-cover-image(alt="" src="{{attachmentPreviewUrl cover}}?dummyReloadAfterSessionEstablished={{sess}}" width="512" height="180" decoding="async")
//- "Card Settings", under the cover: the card shows only the fields it has
data in - and its description, attachments and comments, empty or not -
and Card Settings chooses the rest. Opened, it REPLACES the button and
everything below it with Card Settings itself (cardSettingsInline,
client/components/sidebar/sidebar.jade) until its X closes it
(docs/Features/Cards/Card-Settings-On-Card.md).
if cardSettingsOpen
+cardSettingsInline(card=this)
else
if canModifyCard
.card-details-add-fields
a.card-details-add-fields-button.js-open-card-add-fields(href="#" role="button" aria-expanded="false" title="{{_ 'card-settings'}}" aria-label="{{_ 'card-settings'}}")
i.fa.fa-cog(aria-hidden="true")
| {{_ 'card-settings'}}
//- Every field the board shows on cards, empty or not
(docs/Features/Cards/Card-Fields.md). Which ones is Board Settings / Card
(docs/Features/Cards/Card-Settings.md) - the opened card has no Card
Settings of its own.
.card-details-left
.card-details-left
//- At risk, Show on Card (docs/Features/Cards/At-Risk.md): every reason
that applied, the moves back included.
unless $eq currentBoard.allowsAtRiskOnCard false
with cardAtRisk
.card-details-at-risk.js-card-at-risk
i.fa.fa-exclamation-triangle
| {{_ 'at-risk'}}: {{text}}
//- At risk, Show on Card (docs/Features/Cards/At-Risk.md): every reason
that applied, the moves back included.
unless $eq currentBoard.allowsAtRiskOnCard false
with cardAtRisk
.card-details-at-risk.js-card-at-risk
i.fa.fa-exclamation-triangle
| {{_ 'at-risk'}}: {{text}}
.card-details-items
//- #4448: render the reorderable card-detail sections (Labels, Dates,
Members, Dependencies, Sort, Custom Fields, Vote/Poker, Description)
in the board's stored order, falling back to the historical fixed
order - so a board that never touches the setting renders exactly
what it always has. Board Settings / Card writes the order per
FIELD; each section renders where its first field is, and the
fields inside it (the four dates, the people of Members, ...) in
their own order through the ordered*Fields helpers.
models/lib/cardFieldOrder.js, client/components/sidebar/sidebar.jade
//- `each section in ...`, not `each ...`: the plain form makes the
section NAME ("labels", "dates", ...) the data context, so every
section template - and every popup opened from one, e.g. the Labels
popup - saw a string where it expected the card. Clicking a label
then silently did nothing (`card.toggleLabel` was undefined) and
the card's own labels/stickers/locations lists rendered empty. The
`in` form keeps `this` as the card.
each section in orderedCardFieldSections
if $eq section "labels"
+cardFieldSectionLabels
if $eq section "dates"
+cardFieldSectionDates
if $eq section "members"
+cardFieldSectionMembers
if $eq section "dependencies"
+cardFieldSectionDependencies
if $eq section "sort"
+cardFieldSectionSort
if $eq section "customFields"
+cardFieldSectionCustomFields
if $eq section "voteAndPoker"
+cardFieldSectionVoteAndPoker
if $eq section "description"
+cardFieldSectionDescription
//- Each Scrum field where the board's order puts it ("Scrum settings:
Sprint" ... in Board Settings / Card).
//- The Scrum fields shown on this card are ONE section, "Scrum
settings", headed where the first of them is, with Card kind in its
hamburger (docs/Features/Cards/Card-Fields.md).
if $eq section firstScrumSection
+cardSectionHeader(section="scrum" icon="fa-repeat" label="scrum-settings" menuClass="js-section-card-kind" menuTitle="cardKindPopup-title")
if isSectionOpen "scrum"
if $eq section "scrumSprint"
+cardFieldSectionScrumSprint
if $eq section "scrumPastSprints"
+cardFieldSectionScrumPastSprints
if $eq section "scrumRelease"
+cardFieldSectionScrumRelease
if $eq section "scrumIssueType"
+cardFieldSectionScrumIssueType
if $eq section "scrumAcceptanceCriteria"
+cardFieldSectionScrumAcceptanceCriteria
if $eq section "scrumBacklogRank"
+cardFieldSectionScrumBacklogRank
.card-details-items
//- #4448: render the reorderable card-detail sections (Labels, Dates,
Members, Dependencies, Sort, Custom Fields, Vote/Poker, Description)
in the board's stored order, falling back to the historical fixed
order - so a board that never touches the setting renders exactly
what it always has. Board Settings / Card writes the order per
FIELD; each section renders where its first field is, and the
fields inside it (the four dates, the people of Members, ...) in
their own order through the ordered*Fields helpers.
models/lib/cardFieldOrder.js, client/components/sidebar/sidebar.jade
//- `each section in ...`, not `each ...`: the plain form makes the
section NAME ("labels", "dates", ...) the data context, so every
section template - and every popup opened from one, e.g. the Labels
popup - saw a string where it expected the card. Clicking a label
then silently did nothing (`card.toggleLabel` was undefined) and
the card's own labels/stickers/locations lists rendered empty. The
`in` form keeps `this` as the card.
each section in orderedCardFieldSections
if $eq section "labels"
+cardFieldSectionLabels
if $eq section "dates"
+cardFieldSectionDates
if $eq section "members"
+cardFieldSectionMembers
if $eq section "dependencies"
+cardFieldSectionDependencies
if $eq section "sort"
+cardFieldSectionSort
if $eq section "customFields"
+cardFieldSectionCustomFields
if $eq section "voteAndPoker"
+cardFieldSectionVoteAndPoker
if $eq section "description"
+cardFieldSectionDescription
//- Each Scrum field where the board's order puts it ("Scrum settings:
Sprint" ... in Board Settings / Card).
//- The Scrum fields shown on this card are ONE section, "Scrum
settings", headed where the first of them is, with Card kind in its
hamburger (docs/Features/Cards/Card-Fields.md).
if $eq section firstScrumSection
+cardSectionHeader(section="scrum" icon="fa-repeat" label="scrum-settings" menuClass="js-section-card-kind" menuTitle="cardKindPopup-title")
if isSectionOpen "scrum"
if $eq section "scrumSprint"
+cardFieldSectionScrumSprint
if $eq section "scrumPastSprints"
+cardFieldSectionScrumPastSprints
if $eq section "scrumRelease"
+cardFieldSectionScrumRelease
if $eq section "scrumIssueType"
+cardFieldSectionScrumIssueType
if $eq section "scrumAcceptanceCriteria"
+cardFieldSectionScrumAcceptanceCriteria
if $eq section "scrumBacklogRank"
+cardFieldSectionScrumBacklogRank
.card-checklist-attachmentGalleries
.card-checklist-attachmentGallery.card-checklists
if currentBoard.allowsChecklists
unless $eq currentBoard.allowsChecklistTitle false
+cardSectionHeader(section="checklists" icon="fa-check" label="checklists")
if checklistSectionOpen
//- Total checklist item count (finished/total) shown above all
checklists. The board flag is a cheap boolean, so when it is off
the checklist counting below is never evaluated.
if currentBoard.allowsChecklistCountBadgeOnCard
if checklists.length
h4.card-details-item-subtitle
| {{checklistFinishedCount}}/{{checklistItemCount}}
+checklists(cardId = _id card = this)
if currentBoard.allowsSubtasks
//- #4693: "Subtasks (1/3)", done/total (subtaskDoneCount in subtasks.js).
+cardSectionHeader(section="subtasks" icon="fa-sitemap" label="subtasks"
count=subtaskDoneCount
menuClass="js-open-subtasks-menu" menuTitle="subtasks")
if isSectionOpen "subtasks"
+subtasks(cardId = _id)
if currentBoard.allowsAttachments
+cardSectionHeader(section="attachments" icon="fa-paperclip" label="attachments"
count=attachmentCount)
if isSectionOpen "attachments"
//- #6796: the upload rules (size, types, what an invalid name
does) are read when uploading, so they are in the upload popup
(attachments.jade cardAttachmentsPopup), not above every list.
.card-checklist-attachmentGallery.card-attachmentGallery
+attachmentGallery
.card-checklist-attachmentGalleries
.card-checklist-attachmentGallery.card-checklists
if currentBoard.allowsChecklists
unless $eq currentBoard.allowsChecklistTitle false
+cardSectionHeader(section="checklists" icon="fa-check" label="checklists")
if checklistSectionOpen
//- Total checklist item count (finished/total) shown above all
checklists. The board flag is a cheap boolean, so when it is off
the checklist counting below is never evaluated.
if currentBoard.allowsChecklistCountBadgeOnCard
if checklists.length
h4.card-details-item-subtitle
| {{checklistFinishedCount}}/{{checklistItemCount}}
+checklists(cardId = _id card = this)
if currentBoard.allowsSubtasks
//- #4693: "Subtasks (1/3)", done/total (subtaskDoneCount in subtasks.js).
+cardSectionHeader(section="subtasks" icon="fa-sitemap" label="subtasks"
count=subtaskDoneCount
menuClass="js-open-subtasks-menu" menuTitle="subtasks")
if isSectionOpen "subtasks"
+subtasks(cardId = _id)
if currentBoard.allowsAttachments
+cardSectionHeader(section="attachments" icon="fa-paperclip" label="attachments"
count=attachmentCount)
if isSectionOpen "attachments"
//- #6796: the upload rules (size, types, what an invalid name
does) are read when uploading, so they are in the upload popup
(attachments.jade cardAttachmentsPopup), not above every list.
.card-checklist-attachmentGallery.card-attachmentGallery
+attachmentGallery
//- GitHub issue #595: markdown text notes, a card-level collection of
small editable markdown blocks - separate from the card's single
description - so a card is not limited to cramming everything into
one description field. Edited in a popup reusing the SAME editor/
viewer widget the description above already uses.
if currentBoard.allowsTextNotes
+cardSectionHeader(section="text-notes" icon="fa-file-text-o" label="text-notes")
if isSectionOpen "text-notes"
+cardTextNotes(_id = _id)
//- GitHub issue #595: markdown text notes, a card-level collection of
small editable markdown blocks - separate from the card's single
description - so a card is not limited to cramming everything into
one description field. Edited in a popup reusing the SAME editor/
viewer widget the description above already uses.
if currentBoard.allowsTextNotes
+cardSectionHeader(section="text-notes" icon="fa-file-text-o" label="text-notes")
if isSectionOpen "text-notes"
+cardTextNotes(_id = _id)
//- Similar cards, Show on Card: the cards of this board like this one
(docs/Features/Cards/Similar-Cards.md). Asked when the card opens, and
the section is there only when there are some
(docs/Features/Cards/Card-Fields.md).
unless $eq currentBoard.allowsSimilarCardsOnCard false
+cardSimilarCardsSection(cardId=_id)
//- Similar cards, Show on Card: the cards of this board like this one
(docs/Features/Cards/Similar-Cards.md). Asked when the card opens, and
the section is there only when there are some
(docs/Features/Cards/Card-Fields.md).
unless $eq currentBoard.allowsSimilarCardsOnCard false
+cardSimilarCardsSection(cardId=_id)
//- The comments: in this column, or - on a maximized card - at the top of
the right one (cardCommentsSection below).
unless cardMaximized
+cardCommentsSection
//- The comments: in this column, or - on a maximized card - at the top of
the right one (cardCommentsSection below).
unless cardMaximized
+cardCommentsSection
.card-details-right
.card-details-right
//- A maximized card has its comments here, beside the card's fields.
if cardMaximized
+cardCommentsSection
//- A maximized card has its comments here, beside the card's fields.
if cardMaximized
+cardCommentsSection
//- #6688: `allowsActivities` existed in the schema (default true) but
gated nothing; Board Settings / Card now has its row and this is what
the row hides.
if currentBoard.allowsActivities
if currentUser.isBoardAdmin
//- OUTSIDE .activity-title, which is `display: flex`: a rule inside it
becomes a flex item and renders as a short line beside the heading
instead of a separator above it.
The eye that used to sit here showed and hid exactly what the caret
shows and hides, so there were two controls for one thing and they
could disagree. The caret is the one that stayed, and this section is
the one that starts CLOSED - a card is opened to read the card, not
its history.
+cardSectionHeader(section="activities" icon="fa-history" label="activities")
//- #6688: `allowsActivities` existed in the schema (default true) but
gated nothing; Board Settings / Card now has its row and this is what
the row hides.
if currentBoard.allowsActivities
if currentUser.isBoardAdmin
//- OUTSIDE .activity-title, which is `display: flex`: a rule inside it
becomes a flex item and renders as a short line beside the heading
instead of a separator above it.
The eye that used to sit here showed and hid exactly what the caret
shows and hides, so there were two controls for one thing and they
could disagree. The caret is the one that stayed, and this section is
the one that starts CLOSED - a card is opened to read the card, not
its history.
+cardSectionHeader(section="activities" icon="fa-history" label="activities")
if currentUser.isBoardAdmin
if isSectionOpen "activities"
if isLoaded.get
if isLinkedCard
+activities(card=this mode="linkedcard")
else if isLinkedBoard
+activities(card=this mode="linkedboard")
else
+activities(card=this mode="card")
if currentUser.isBoardAdmin
if isSectionOpen "activities"
if isLoaded.get
if isLinkedCard
+activities(card=this mode="linkedcard")
else if isLinkedBoard
+activities(card=this mode="linkedboard")
else
+activities(card=this mode="card")
template(name="cardFieldSectionLabels")
.card-details-group.card-details-group-labels
@@ -722,14 +711,11 @@ template(name="cardFieldSectionSort")
//.card-details-items
template(name="cardFieldSectionCustomFields")
//- The heading is here for a card that has a custom field value, or that
ticked Custom Fields in "+ Add" (docs/Features/Cards/Card-Fields.md). It
used to be on EVERY card the reader may write to, because the hamburger
at its end is the single place custom fields live - the picker of which
fields are on this card, a pencil each, and "Add custom field" - and a
card with none had no other way to get one. "+ Add" is that way now, so
a card with none no longer carries an empty heading. The FIELDS below
still come from `customFieldsWD`.
//- The heading is on EVERY card the reader may write to whose board shows
Custom Fields on cards (docs/Features/Cards/Card-Fields.md), empty or not:
the hamburger at its end is the single place custom fields live - the
picker of which fields are on this card, a pencil each, and "Add custom
field". The FIELDS below still come from `customFieldsWD`.
if canShowCustomFieldsOnCard
//- ONE header for the whole group, outside the loop: a card with six
custom fields is one Custom Fields section, not six sections that
+30 -25
View File
@@ -754,14 +754,15 @@ Template.registerHelper('cardSwimlaneTitle', function cardSwimlaneTitle() {
return swimlane && swimlane.title;
});
// The Custom Fields section: on a card that has a custom field value, or that
// ticked Custom Fields in "+ Add" (docs/Features/Cards/Card-Fields.md) - not on
// every card, where it was an empty heading. "+ Add" is how a card with none
// gets the section, and its hamburger then adds the fields.
// The Custom Fields section: on every card the reader may change whose board
// shows Custom Fields on cards, empty or not (docs/Features/Cards/Card-Fields.md)
// - its hamburger is where the fields are added. The board as its cards see it,
// so a board that hides the whole Custom Fields section on Show on Card
// (models/lib/cardShownFields.js boardForCard) hides it here too.
Template.registerHelper('canShowCustomFieldsOnCard', function canShowCustomFieldsOnCard() {
const { cardShowsField } = require('/client/components/cards/cardAddFields');
const board = this?.board?.();
return Utils.canModifyCard(this) && board?.allowsCustomFields !== false && cardShowsField(this, 'customFields');
const { boardForCard } = require('/models/lib/cardShownFields');
const board = boardForCard(this?.board?.());
return Utils.canModifyCard(this) && board?.allowsCustomFields !== false;
});
Template.registerHelper('stickers', function stickers() {
@@ -909,13 +910,15 @@ Template.registerHelper('isCurrentListId', function isCurrentListId(listId) {
Template.registerHelper('orderedVoteAndPokerFields', sectionHelper('voteAndPoker'));
}
// The card's sections in the board's order, less the Scrum fields this card
// does not show - a Scrum field is its own section with no board flag in the
// template to read (docs/Features/Cards/Card-Fields.md). The board has to
// allow it first (Board Settings / Scrum): Show empty fields and Show empty
// only show what the board allows, as they do for Members or Vote (#6830).
// The card's sections in the board's order, less the Scrum fields the board
// does not show on cards - a Scrum field is its own section with no board flag
// in the template to read (docs/Features/Cards/Card-Fields.md). Only what the
// board allows (Board Settings / Scrum), as for Members or Vote (#6830); and
// read through the board as its cards see it (cardShownFields.js
// boardForCard), so a Scrum section hidden whole on Show on Card is gone.
function orderedSectionsOf(card) {
const board = card?.board?.();
const { boardAllows, boardForCard } = require('/models/lib/cardShownFields');
const board = boardForCard(card?.board?.());
let sections;
if (board && typeof board.getCardFieldOrder === 'function') {
sections = board.getCardFieldOrder();
@@ -923,10 +926,7 @@ function orderedSectionsOf(card) {
const { applyCardFieldOrder } = require('/models/lib/cardFieldOrder');
sections = applyCardFieldOrder(board?.cardFieldOrder);
}
const { cardShowsField } = require('/client/components/cards/cardAddFields');
const { boardAllows } = require('/models/lib/cardShownFields');
return sections.filter(s => !/^scrum[A-Z]/.test(s) ||
(boardAllows(board, s) && cardShowsField(card, s)));
return sections.filter(s => !/^scrum[A-Z]/.test(s) || boardAllows(board, s));
}
Template.cardFieldSectionSort.helpers({
@@ -939,8 +939,7 @@ Template.cardFieldSectionSort.helpers({
return !!(board && (
board.allowsCardSortingByNumber || board.allowsShowLists ||
board.allowsFlowtime || board.allowsPomodoro ||
// The card's own view already says whether Spent time is shown: with
// hours, or ticked "On this card" to be filled in.
// The card's view already says whether Spent time is shown.
board.allowsSpentTime
));
},
@@ -985,29 +984,35 @@ Template.cardDetails.helpers({
// List title, Show on Card: the card's own choice, unless the
// administrator unticked List title in Admin Panel / Settings / Visibility /
// Features (models/lib/cardFieldVisibility.js). The card keeps its choice.
// Its section (Card) hidden whole on Show on Card hides it as well.
showListOnCard() {
const board = this?.board?.();
return Boolean(this?.showListOnCard) && !isCardFieldHiddenOnBoard(board, 'listTitle');
const { hidesRow } = require('/models/lib/cardShownFields');
return Boolean(this?.showListOnCard) && !isCardFieldHiddenOnBoard(board, 'listTitle')
&& !hidesRow(board, 'card', 'listTitle');
},
// The header's own flags, read through the board as its cards see it
// (cardBoardView), so a Card Settings section hidden whole on Show on Card
// takes them away too.
// Card color, Show on Card: the header's color, on unless turned off.
showCardColorOnCard() {
return Utils.getCurrentBoard()?.allowsCardColorOnCard !== false;
return cardBoardView(this)?.allowsCardColorOnCard !== false;
},
// Collapse, Show on Card: the header's collapse caret, on unless turned off.
allowsCardCollapse() {
return Utils.getCurrentBoard()?.allowsCardCollapse !== false;
return cardBoardView(this)?.allowsCardCollapse !== false;
},
// Labels title, Show on Card: the labels above the title, as on a minicard.
showLabelsAboveTitleOnCard() {
return Utils.getCurrentBoard()?.labelsAboveTitleOnCard === true;
return cardBoardView(this)?.labelsAboveTitleOnCard === true;
},
// ...as long as the board shows labels at all.
labelsShownAboveTitle() {
return Utils.getCurrentBoard()?.allowsLabels !== false;
return cardBoardView(this)?.allowsLabels !== false;
},
cardCollapsed() {
// A board that turned the caret off has no collapsed cards.
if (Utils.getCurrentBoard()?.allowsCardCollapse === false) return false;
if (cardBoardView(this)?.allowsCardCollapse === false) return false;
const user = ReactiveCache.getCurrentUser();
if (user && user.profile) {
return !!user.profile.cardCollapsed;
+65 -34
View File
@@ -33,6 +33,32 @@ const {
} = require('/models/lib/cardFieldOrder');
const { isCardFieldHiddenOnBoard } = require('/models/lib/cardFieldVisibility');
// The board as every minicard of it sees it (models/lib/cardShownFields.js
// boardForMinicard): the rows of a Card Settings section hidden whole on Show
// on Minicard read false. Every helper below that decides whether the minicard
// draws a field reads this, not the board itself; Card Settings reads the
// board, so its checkboxes keep showing each row's own flag.
const { boardForMinicard, hidesRow } = require('/models/lib/cardShownFields');
function minicardBoardOf(data) {
const boardId = (data && (data.boardId || (data.card && data.card.boardId))) || null;
const board = boardId ? ReactiveCache.getBoard(boardId) : Utils.getCurrentBoard();
return boardForMinicard(board || Utils.getCurrentBoard());
}
// The minicard and its sub-templates read `currentBoard.allowsXOnMinicard`;
// this template-level helper answers before the global one, as the opened
// card's CARD_FIELD_TEMPLATES do (client/components/cards/cardAddFields.js).
export const MINICARD_FIELD_TEMPLATES = Object.freeze(['minicard', 'minicardChecklist']);
MINICARD_FIELD_TEMPLATES.forEach(name => {
Template[name].helpers({
currentBoard() {
const tpl = Template.instance();
return minicardBoardOf(tpl && tpl.data);
},
});
});
function getMinicardFlag(board, onMinicardField, legacyField, defaultValue) {
if (!board) return false;
if (board[onMinicardField] !== null && board[onMinicardField] !== undefined) {
@@ -61,14 +87,14 @@ Template.minicard.helpers({
return commentBadgeTitle(this.comments(), count => TAPi18n.__('card-comments-title', count));
},
// #1591: the whole-minicard fold, same shape as a list's collapsed() helper.
showCollapseControl() { return ReactiveCache.getBoard(this.boardId)?.allowsMinicardCollapse !== false; },
showCollapseControl() { return minicardBoardOf(this)?.allowsMinicardCollapse !== false; },
showLabelsAboveTitle() {
const board = ReactiveCache.getBoard(this.boardId);
const board = minicardBoardOf(this);
return board?.labelsAboveTitleOnMinicard === true && (board.allowsMinicardCollapse === false || !Utils.getCardCollapseState(this));
},
labelsAboveTitle() { return ReactiveCache.getBoard(this.boardId)?.labelsAboveTitleOnMinicard === true; },
labelsAboveTitle() { return minicardBoardOf(this)?.labelsAboveTitleOnMinicard === true; },
minicardCollapsed() {
return ReactiveCache.getBoard(this.boardId)?.allowsMinicardCollapse !== false && Utils.getCardCollapseState(this);
return minicardBoardOf(this)?.allowsMinicardCollapse !== false && Utils.getCardCollapseState(this);
},
// The minicard's field order from Board Settings / Card's "Show on
// Minicard" column (board.minicardFieldOrder): the sections top to bottom,
@@ -76,19 +102,19 @@ Template.minicard.helpers({
// `.badges` strip. A board that never set it gets the historical order.
// models/lib/cardFieldOrder.js
orderedMinicardSections() {
const board = this.board();
const board = minicardBoardOf(this);
return orderedMinicardSections(board?.minicardFieldOrder);
},
orderedMinicardDates() {
const board = this.board();
const board = minicardBoardOf(this);
return orderedMinicardFieldsOf(board?.minicardFieldOrder, 'dates');
},
orderedMinicardBadges() {
const board = this.board();
const board = minicardBoardOf(this);
return orderedMinicardFieldsOf(board?.minicardFieldOrder, 'badges');
},
showCustomFieldsOnMinicard() {
const board = this.board();
const board = minicardBoardOf(this);
return board?.allowsCustomFieldsOnMinicard === true;
},
// #3078: highlight the minicard when it has comments the current user has
@@ -118,7 +144,7 @@ Template.minicard.helpers({
const card = this;
if (!card || !card._id) return false;
// Unread comments, Show on Minicard: on unless turned off.
if (Utils.getCurrentBoard()?.allowsUnreadCommentsOnMinicard === false) return false;
if (minicardBoardOf(this)?.allowsUnreadCommentsOnMinicard === false) return false;
const comments = ReactiveCache.getCardComments({ cardId: card._id }) || [];
if (!comments.length) return false;
// #6745: only this card's own last-viewed time, so opening ANOTHER card
@@ -228,7 +254,7 @@ Template.minicard.helpers({
showCreatorOnMinicard() {
// cache "board" to reduce the mini-mongodb access
const board = this.board();
const board = minicardBoardOf(this);
let ret = false;
if (board) {
ret = board.allowsCreatorOnMinicard ?? false;
@@ -240,54 +266,54 @@ Template.minicard.helpers({
},
showMembers() {
const board = this.board();
const board = minicardBoardOf(this);
return getMinicardFlag(board, 'allowsMembersOnMinicard', 'allowsMembers', true);
},
showAssignee() {
const board = this.board();
const board = minicardBoardOf(this);
return getMinicardFlag(board, 'allowsAssigneeOnMinicard', 'allowsAssignee', true);
},
showReceived() {
const board = this.board();
const board = minicardBoardOf(this);
return getMinicardFlag(board, 'allowsReceivedDateOnMinicard', 'allowsReceivedDate', true);
},
showStart() {
const board = this.board();
const board = minicardBoardOf(this);
return getMinicardFlag(board, 'allowsStartDateOnMinicard', 'allowsStartDate', true);
},
showDue() {
const board = this.board();
const board = minicardBoardOf(this);
return getMinicardFlag(board, 'allowsDueDateOnMinicard', 'allowsDueDate', true);
},
showEnd() {
const board = this.board();
const board = minicardBoardOf(this);
return getMinicardFlag(board, 'allowsEndDateOnMinicard', 'allowsEndDate', true);
},
// #2530: accumulated spent-time badge on the minicard. Defaults to true
// (models/boards.js) since it was already shown unconditionally; this only
// lets an admin turn it off via Card Settings.
showSpentTime() {
const board = this.board();
const board = minicardBoardOf(this);
return getMinicardFlag(board, 'allowsSpentTimeOnMinicard', 'allowsSpentTime', true);
},
showLabels() {
const board = this.board();
const board = minicardBoardOf(this);
return getMinicardFlag(board, 'allowsLabelsOnMinicard', 'allowsLabels', true);
},
showCardNumber() {
const board = this.board();
const board = minicardBoardOf(this);
return getMinicardFlag(board, 'allowsCardNumberOnMinicard', 'allowsCardNumber', false);
},
// "Mark as complete" toggle on the minicard. No legacy fallback to the
// card-details setting (allowsDueComplete): hidden by default so it only
// appears when explicitly enabled in Card Settings > Show at Minicard.
showDueComplete() {
const board = this.board();
const board = minicardBoardOf(this);
return getMinicardFlag(board, 'allowsDueCompleteOnMinicard', null, false);
},
showSubtasks() {
const board = this.board();
const board = minicardBoardOf(this);
return getMinicardFlag(board, 'allowsSubtasksOnMinicard', 'allowsSubtasks', true);
},
// #6688: the minicard badges that had no Board Settings / Card toggle.
@@ -296,23 +322,23 @@ Template.minicard.helpers({
// flag is NOT a fallback here - hiding the Dependencies section of the
// opened card is a different decision from hiding its badge.
showDependenciesOnMinicard() {
const board = this.board();
const board = minicardBoardOf(this);
return getMinicardFlag(board, 'allowsDependenciesOnMinicard', null, true);
},
showStickersOnMinicard() {
const board = this.board();
const board = minicardBoardOf(this);
return getMinicardFlag(board, 'allowsStickersOnMinicard', null, true);
},
showCommentCountOnMinicard() {
const board = this.board();
const board = minicardBoardOf(this);
return getMinicardFlag(board, 'allowsCommentCountOnMinicard', null, true);
},
showVoteOnMinicard() {
const board = this.board();
const board = minicardBoardOf(this);
return getMinicardFlag(board, 'allowsVoteOnMinicard', null, true);
},
showPokerOnMinicard() {
const board = this.board();
const board = minicardBoardOf(this);
return getMinicardFlag(board, 'allowsPokerOnMinicard', null, true);
},
// #6431: compact checklist item-count badge (finished/total) on the minicard.
@@ -320,7 +346,7 @@ Template.minicard.helpers({
// counting (checklistFinishedCount/checklistItemCount) is gated behind this in
// the template, so a board with the badge off spends no resources counting.
showChecklistCountBadge() {
const board = this.board();
const board = minicardBoardOf(this);
return !!(board && board.allowsChecklistCountBadgeOnMinicard);
},
// #4285: show a card's comments directly on the minicard. Opt-in and OFF by
@@ -329,7 +355,7 @@ Template.minicard.helpers({
// built (and the comment badge's `comments` helper already runs
// unconditionally for the count badge) when this returns true.
showCommentsOnMinicard() {
const board = this.board();
const board = minicardBoardOf(this);
return !!(board && board.allowsCommentsOnMinicard);
},
// Compact, truncated preview of the most recent comments for the minicard.
@@ -384,10 +410,10 @@ Template.minicard.helpers({
// as it was on every board before it had a row.
// Card color, Show on Minicard: on unless turned off.
showCardColorOnMinicard() {
return Utils.getCurrentBoard()?.allowsCardColorOnMinicard !== false;
return minicardBoardOf(this)?.allowsCardColorOnMinicard !== false;
},
showIssueTypeOnMinicard() {
return Utils.getCurrentBoard()?.allowsIssueTypeOnMinicard !== false;
return minicardBoardOf(this)?.allowsIssueTypeOnMinicard !== false;
},
cover() {
// #5666: for a linked card the cover lives on the real card it points at, so
@@ -429,12 +455,14 @@ Template.minicard.helpers({
// Show list name if either:
// 1. Board-wide setting is enabled, OR
// 2. This specific card has the setting enabled
const currentBoard = this.board();
const currentBoard = minicardBoardOf(this);
if (!currentBoard) return false;
if (currentBoard.allowsShowListsOnMinicard) return true;
// The card's own List title, unless unticked in Admin Panel / Settings /
// Visibility / Features (models/lib/cardFieldVisibility.js).
return !isCardFieldHiddenOnBoard(currentBoard, 'listTitle') && Boolean(this.getRealCard().showListOnMinicard);
// ...and unless its section (Card) is hidden whole on Show on Minicard.
return !isCardFieldHiddenOnBoard(currentBoard, 'listTitle') && !hidesRow(currentBoard, 'minicard', 'listTitle')
&& Boolean(this.getRealCard().showListOnMinicard);
},
// #2426: the swimlane a card belongs to isn't otherwise visible on its
@@ -442,7 +470,7 @@ Template.minicard.helpers({
// swimlane), so this board-wide toggle shows the swimlane's name at the
// bottom of the minicard, the same place/style as the list name above.
shouldShowSwimlaneNameOnMinicard() {
const currentBoard = this.board();
const currentBoard = minicardBoardOf(this);
if (!currentBoard) return false;
return currentBoard.allowsSwimlaneNameOnMinicard === true;
},
@@ -455,8 +483,11 @@ Template.minicard.helpers({
shouldShowChecklistAtMinicard() {
// Return checklists that should be shown on minicard
const currentBoard = this.board();
const currentBoard = minicardBoardOf(this);
if (!currentBoard) return [];
// A checklist's own "Show at minicard" overrides the board's default, so
// the Checklists section hidden whole on Show on Minicard is asked first.
if (hidesRow(currentBoard, 'minicard', 'checklists')) return [];
const checklists = this.checklists();
const visibleChecklists = [];
-11
View File
@@ -184,23 +184,12 @@
.card-settings-side > a.flex {
margin: 0;
}
/* Select all / Select none in a section's hamburger: the Draggable table's
buttons (boardSettingsColumnActions.css). */
.card-settings-select {
margin: 3px 0 0;
font-weight: normal;
}
.card-settings-select button {
white-space: nowrap;
}
.card-field-order-toggle,
.card-field-order-move {
flex-shrink: 0;
}
.card-field-order-move.is-disabled,
.card-field-order-toggle.is-disabled,
.card-always-show.is-disabled,
.card-show-empty-fields.is-disabled,
.card-ask-move-reason.is-disabled {
opacity: 0.3;
cursor: not-allowed;
+110 -98
View File
@@ -269,22 +269,22 @@ template(name="boardInfoOnMyBoardsPopup")
i.fa.fa-arrows-h
| {{_ 'personal-list-width'}}
//- Board Settings / Card - what the opened card and the minicard show, and
in what order. Opened from the board's cog menu (boardMenuPopup above).
Whoever may not change the board sees the board's rows disabled and may
still set their own ("Labels text", "List title"), as on the opened card.
//- Board Settings / Card - Card Settings: what every opened card and every
minicard of the board show, and in what order. Opened from the board's cog
menu (boardMenuPopup above); the opened card has no Card Settings of its
own. Whoever may not change the board sees the board's rows disabled and
may still set their own ("Labels text").
template(name="boardCardSettingsPopup")
//- Board Settings / Card is the SAME template as the opened card's Card
Settings (cardSettingsInline below), with no card: Show, then the sections
as checklists, their rows as the items, the rest in their hamburgers
(docs/Features/Cards/Card-Settings-On-Card.md). The popup's own header is
its title and its close button.
+cardSettingsInline(inPopup=true)
//- Show, then the sections as checklists, their rows as the items, the rest
in their hamburgers (cardSettingsInline below,
docs/Features/Cards/Card-Settings.md). The popup's own header is its title
and its close button.
+cardSettingsInline
//- One side's checkbox of a row of Card Settings: the board's Show on Card or
Show on Minicard, through the handler the row names (cardSettingsRows.js).
The same animated checkbox as On this card; only the one clicked animates.
Only the one clicked animates.
template(name="cardSettingsSideToggle")
span.card-settings-side(class="card-settings-side-{{row.side}}")
a.flex.card-field-order-toggle(class="{{#if row.writable}}{{row.toggle}}{{else}}is-disabled{{/if}} {{#if row.checked}}is-checked{{/if}} {{#if row.animating}}is-animating{{/if}}" title="{{row.title}}" role="checkbox" aria-checked="{{#if row.checked}}true{{else}}false{{/if}}")
@@ -317,130 +317,142 @@ template(name="cardSettingsRowLabel")
|  ({{_ 'label-text-follows-board'}})
//- Card Settings on the opened card (docs/Features/Cards/Card-Settings-On-Card.md).
The card's "Card Settings" button, and everything below it, is replaced by
this until its X closes it: the title, "Show" choosing whether the
//- Card Settings, the body of Board Settings / Card
(docs/Features/Cards/Card-Settings.md): "Show" choosing whether the
checkboxes are Show on Minicard or Show on Card, then the sections as
checklists - a title per section, its rows as the items, the checkbox the
chosen side's board-wide setting. Sections and rows are dragged like
checklists and their items and collapse like them; the rest of what a
section or a row has is in its hamburger (cardSettingsSectionPopup,
cardSettingsItemPopup). The rows, checkboxes and handlers are the popup's
above (client/components/sidebar/sidebar.js sectionRowsOf,
cardSettingsEvents), so the two cannot disagree. Board Settings / Card is
this same template, in a popup (boardCardSettingsPopup above).
checklists - a title per section with its own checkbox (the whole section
shown on the chosen side or not), its rows as the items, the checkbox the
chosen side's board-wide setting; a section with one row is one line.
Sections and rows are dragged like checklists and their items and collapse
like them; the rest of what a section or a row has is in its hamburger
(cardSettingsSectionPopup, cardSettingsItemPopup) - drawn only when it has
something in it. client/components/sidebar/sidebar.js inlineSectionsOf,
cardSettingsEvents.
template(name="cardSettingsInline")
.card-settings-inline.js-card-settings-inline(class="{{settingsSideClass}} {{#if inPopup}}card-settings-in-popup{{/if}}")
//- In Board Settings / Card the popup's header is the title and the X.
unless inPopup
.card-settings-inline-head
h3.card-settings-inline-title {{_ 'card-settings'}}
a.card-settings-inline-close.js-close-card-settings(href="#" role="button" title="{{_ 'close'}}" aria-label="{{_ 'close'}}")
i.fa.fa-times(aria-hidden="true")
//- Its own radio name: the opened card's Card Settings and Board Settings /
Card may be open together, and one name would make them one group.
.card-settings-inline.js-card-settings-inline
//- The popup's header is the title and the X.
.card-settings-inline-show(role="radiogroup" aria-label="{{_ 'card-settings-show'}}")
span.card-settings-inline-show-label {{_ 'card-settings-show'}}
label.card-settings-inline-show-option
input.js-card-settings-show-side(type="radio" name="card-settings-show-side-{{#if inPopup}}popup{{else}}card{{/if}}" value="minicard" checked="{{showsSide 'minicard'}}")
input.js-card-settings-show-side(type="radio" name="card-settings-show-side" value="minicard" checked="{{showsSide 'minicard'}}")
span {{_ 'show-on-minicard'}}
label.card-settings-inline-show-option
input.js-card-settings-show-side(type="radio" name="card-settings-show-side-{{#if inPopup}}popup{{else}}card{{/if}}" value="card" checked="{{showsSide 'card'}}")
input.js-card-settings-show-side(type="radio" name="card-settings-show-side" value="card" checked="{{showsSide 'card'}}")
span {{_ 'show-on-card'}}
.card-settings-inline-sections.js-card-settings-sections-sortable
each section in inlineSections
+cardSettingsInlineSection(section=section card=card side=showSide)
+cardSettingsInlineSection(section=section side=showSide)
//- One section of the opened card's Card Settings, drawn like a checklist: a
title that drags and collapses it, a count of the ticked rows, and its
hamburger; under it the rows, each a checkbox, its name and - when it has
one - its own hamburger. Collapsed, the rows are hidden, not removed, so the
drag bound to the list stays bound.
//- One section of Card Settings, drawn like a checklist: a
title that drags and collapses it, left of it a checkbox - whether the WHOLE
section is shown on the side Card Settings shows - a count of the ticked
rows, and its hamburger when it has anything in it; under it the rows, each
a checkbox, its name and - when it has one - its own hamburger. Collapsed,
the rows are hidden, not removed, so the drag bound to the list stays bound.
A section with ONE row on this side is one line (`section.single`): one
checkbox - the field's own, through its real checkbox kept out of sight -
its name, the section's hamburger. Custom Fields' items are the board's
custom fields, with a "+" under them (cardSettingsCustomFields.js).
template(name="cardSettingsInlineSection")
.card-settings-inline-section.js-card-settings-section(data-section="{{section.id}}" class="{{#if section.collapsed}}is-collapsed{{/if}} {{#if section.draggable}}is-draggable{{/if}}")
.card-settings-inline-section-head
a.card-settings-inline-collapse.js-toggle-card-settings-section(href="#" role="button" aria-expanded="{{#if section.collapsed}}false{{else}}true{{/if}}" title="{{_ 'collapse'}}" aria-label="{{_ 'collapse'}}")
i.fa(class="{{#if section.collapsed}}fa-caret-right{{else}}fa-caret-down{{/if}}" aria-hidden="true")
.card-settings-inline-section.js-card-settings-section(data-section="{{section.id}}" class="{{#if section.collapsed}}is-collapsed{{/if}} {{#if section.draggable}}is-draggable{{/if}} {{#if section.single}}is-single{{/if}} {{#unless section.shown}}is-section-hidden{{/unless}}")
.card-settings-inline-section-head(class="{{#if section.flagRow}}js-card-field-order-row{{/if}}" data-key="{{#if section.flagRow}}{{section.flagRow.key}}{{/if}}" data-side="{{#if section.flagRow}}{{section.flagRow.side}}{{/if}}")
unless section.single
a.card-settings-inline-collapse.js-toggle-card-settings-section(href="#" role="button" aria-expanded="{{#if section.collapsed}}false{{else}}true{{/if}}" title="{{_ 'collapse'}}" aria-label="{{_ 'collapse'}}")
i.fa(class="{{#if section.collapsed}}fa-caret-right{{else}}fa-caret-down{{/if}}" aria-hidden="true")
if section.draggable
if section.showDragHandles
a.card-settings-inline-section-move.js-card-settings-section-handle(href="#" draggable="false" role="button" tabindex="0" title="{{_ 'drag-to-reorder'}}" aria-label="{{_ 'drag-to-reorder'}}")
i.fa.fa-arrows(aria-hidden="true")
//- The section's checkbox: for one line and for Custom Fields the
field's own flag (and the section shown); otherwise whether the whole
section is shown on this side. A board admin's, like the rows.
span.card-settings-side.card-settings-section-side
if section.flagRow
a.flex.card-field-order-toggle.card-settings-section-toggle(class="{{#if section.flagWritable}}js-card-settings-single-toggle{{else}}is-disabled{{/if}} {{#if section.flagChecked}}is-checked{{/if}} {{#if section.flagRow.animating}}is-animating{{/if}}" data-side="{{section.side}}" title="{{section.sideTitle}}" aria-label="{{section.sideTitle}}" role="checkbox" aria-checked="{{#if section.flagChecked}}true{{else}}false{{/if}}")
.materialCheckBox(class="{{#if section.flagChecked}}is-checked{{/if}}")
else
a.flex.card-field-order-toggle.card-settings-section-toggle(class="{{#if section.writable}}js-card-settings-section-shown{{else}}is-disabled{{/if}} {{#if section.shown}}is-checked{{/if}} {{#if section.animatingShown}}is-animating{{/if}}" data-side="{{section.side}}" title="{{section.sideTitle}}" aria-label="{{section.sideTitle}}" role="checkbox" aria-checked="{{#if section.shown}}true{{else}}false{{/if}}")
.materialCheckBox(class="{{#if section.shown}}is-checked{{/if}}")
if section.flagRow
//- The field's real checkbox, out of sight: the line's checkbox
clicks it, so the field is set by its own handler.
span.card-settings-single-real.js-card-settings-single-real(hidden aria-hidden="true")
+cardSettingsSideToggle(row=section.flagRow)
//- Like a row: with drag handles on, only the handle drags the section.
h4.card-settings-inline-section-title(class="{{#if section.draggable}}{{#unless section.showDragHandles}}js-card-settings-section-handle{{/unless}}{{/if}}" tabindex="{{#if section.draggable}}{{#unless section.showDragHandles}}0{{/unless}}{{/if}}" title="{{#if section.draggable}}{{#unless section.showDragHandles}}{{_ 'drag-to-reorder'}}{{/unless}}{{/if}}")
i.fa(class=section.icon aria-hidden="true")
| {{section.title}}
span.card-settings-inline-section-count {{section.checkedCount}}/{{section.rows.length}}
a.card-settings-inline-menu.js-open-card-settings-section-menu(href="#" role="button" title="{{_ 'actions'}}" aria-label="{{_ 'actions'}}")
i.fa.fa-bars(aria-hidden="true")
.card-settings-inline-items.js-card-field-order-sortable(data-side="{{side}}")
each row in section.rows
.card-settings-line.card-settings-inline-item.js-card-field-order-row(class="{{#if row.personal}}card-settings-row-personal{{/if}} {{#if row.positioned}}is-positioned{{/if}}" data-key="{{row.key}}" data-side="{{row.side}}")
+cardSettingsSideToggle(row=row)
+cardSettingsRowLabel(row=row)
if row.hasMenu
a.card-settings-inline-menu.js-open-card-settings-item-menu(href="#" role="button" title="{{_ 'actions'}}" aria-label="{{_ 'actions'}}")
i.fa.fa-bars(aria-hidden="true")
unless section.single
span.card-settings-inline-section-count {{section.checkedCount}}/{{section.total}}
if section.hasMenu
a.card-settings-inline-menu.js-open-card-settings-section-menu(href="#" role="button" title="{{_ 'actions'}}" aria-label="{{_ 'actions'}}")
i.fa.fa-bars(aria-hidden="true")
unless section.single
if section.customFields
.card-settings-inline-items.js-card-settings-custom-fields-sortable(data-side="{{side}}")
each field in section.customFieldItems
.card-settings-line.card-settings-inline-item.card-settings-custom-field.js-card-settings-custom-field(class="{{#if field.draggable}}is-positioned{{/if}}" data-id="{{field.id}}" data-side="{{field.side}}")
span.card-settings-side
a.flex.card-field-order-toggle(class="{{#if field.writable}}js-card-settings-custom-field-toggle{{else}}is-disabled{{/if}} {{#if field.checked}}is-checked{{/if}} {{#if field.animating}}is-animating{{/if}}" title="{{field.sideTitle}}" role="checkbox" aria-checked="{{#if field.checked}}true{{else}}false{{/if}}")
.materialCheckBox(class="{{#if field.checked}}is-checked{{/if}}")
span.card-settings-line-label(class="{{#if field.draggable}}{{#unless field.showDragHandles}}js-card-settings-custom-field-handle card-field-order-drag-label{{/unless}}{{/if}}" tabindex="{{#if field.draggable}}{{#unless field.showDragHandles}}0{{/unless}}{{/if}}" title="{{#if field.draggable}}{{#unless field.showDragHandles}}{{_ 'drag-to-reorder'}}{{/unless}}{{/if}}")
if field.draggable
if field.showDragHandles
a.flex.card-field-order-move.card-field-order-handle.js-card-settings-custom-field-handle(href="#" draggable="false" role="button" tabindex="0" title="{{_ 'drag-to-reorder'}}" aria-label="{{_ 'drag-to-reorder'}}")
i.fa.fa-arrows
i.fa.fa-list-alt(aria-hidden="true")
| {{field.name}}
if field.hasMenu
a.card-settings-inline-menu.js-card-settings-edit-custom-field(href="#" role="button" title="{{_ 'actions'}}" aria-label="{{_ 'actions'}}")
i.fa.fa-bars(aria-hidden="true")
//- Under the items, also when there are none: a new custom field of
the board, which then is the last item.
if section.writable
.card-settings-add-custom-field
a.card-settings-add-custom-field-button.js-card-settings-add-custom-field(href="#" role="button" title="{{_ 'createCustomField'}}" aria-label="{{_ 'createCustomField'}}")
i.fa.fa-plus(aria-hidden="true")
else
.card-settings-inline-items.js-card-field-order-sortable(data-side="{{side}}")
each row in section.rows
.card-settings-line.card-settings-inline-item.js-card-field-order-row(class="{{#if row.personal}}card-settings-row-personal{{/if}} {{#if row.positioned}}is-positioned{{/if}}" data-key="{{row.key}}" data-side="{{row.side}}")
+cardSettingsSideToggle(row=row)
+cardSettingsRowLabel(row=row)
if row.hasMenu
a.card-settings-inline-menu.js-open-card-settings-item-menu(href="#" role="button" title="{{_ 'actions'}}" aria-label="{{_ 'actions'}}")
i.fa.fa-bars(aria-hidden="true")
//- A section's hamburger on the opened card's Card Settings.
//- A section's hamburger in Card Settings: the section's board actions
(Subtask settings); and for Card, what is not a field - asking for a move
reason and the Draggable table. A section with none of them has no
hamburger (sidebar.js sectionHasMenu).
template(name="cardSettingsSectionPopup")
.card-settings-section-menu
if sectionIsGeneral
//- What is not a field: the popup's Card pane has these under its title.
div.check-div.card-settings-board-option.card-settings-show-empty-fields
a.flex.card-show-empty-fields(class="{{#if canModifyBoard}}js-show-empty-card-fields{{else}}is-disabled{{/if}} {{#if isAnimating 'showEmptyCardFields'}}is-animating{{/if}}" role="checkbox" aria-checked="{{#if showEmptyCardFields}}true{{else}}false{{/if}}")
.materialCheckBox(class="{{#if showEmptyCardFields}}is-checked{{/if}}")
span {{_ 'card-settings-show-empty-fields'}}
//- What is not a field.
div.check-div.card-settings-board-option.card-settings-ask-move-reason
a.flex.card-ask-move-reason(class="{{#if canModifyBoard}}js-ask-move-reason{{else}}is-disabled{{/if}} {{#if isAnimating 'askForMoveReason'}}is-animating{{/if}}" role="checkbox" aria-checked="{{#if askForMoveReason}}true{{else}}false{{/if}}")
.materialCheckBox(class="{{#if askForMoveReason}}is-checked{{/if}}")
span {{_ 'ask-move-reason'}}
ul.pop-over-list
if maySelectSide
li.card-settings-section-menu-select
span {{sideTitle}}
span.board-settings-column-actions.card-settings-select
button.js-card-settings-inline-select(type="button" data-column="{{side}}" data-value="all") {{_ 'select-all'}}
button.js-card-settings-inline-select(type="button" data-column="{{side}}" data-value="none") {{_ 'select-none'}}
if maySelectThisCard
li.card-settings-section-menu-select
span {{_ 'card-settings-this-card'}}
span.board-settings-column-actions.card-settings-select
button.js-card-settings-inline-select(type="button" data-column="this" data-value="all") {{_ 'select-all'}}
button.js-card-settings-inline-select(type="button" data-column="this" data-value="none") {{_ 'select-none'}}
if maySelectAlways
li.card-settings-section-menu-select
span {{_ 'card-settings-show-empty'}}
span.board-settings-column-actions.card-settings-select
button.js-card-settings-inline-select(type="button" data-column="always" data-value="all") {{_ 'select-all'}}
button.js-card-settings-inline-select(type="button" data-column="always" data-value="none") {{_ 'select-none'}}
each action in sectionActions
li
a.js-card-settings-action(data-action="{{action.id}}")
i.fa(class=action.icon aria-hidden="true")
| {{action.title}}
if sectionActions.length
ul.pop-over-list
each action in sectionActions
li
a.js-card-settings-action(data-action="{{action.id}}")
i.fa(class=action.icon aria-hidden="true")
| {{action.title}}
if sectionIsGeneral
+boardDragSettings(section="card")
//- A row's hamburger on the opened card's Card Settings: whether THIS card
shows the field, whether every card shows it empty, and Labels text's way
back to the board's default. The cell classes are the popup's, so the
popup's handlers set them.
//- A row's hamburger in Card Settings: Labels text's way
back to the board's default, while the user overrides it - the only thing a
row's hamburger holds, so a row without it has no hamburger. The cell
classes are the popup's, so the popup's handlers set them.
template(name="cardSettingsItemPopup")
with itemRow
.card-settings-item-menu.js-card-field-order-row(data-key="{{key}}" data-side="{{side}}")
if menu.thisCard
div.check-div.card-settings-board-option
a.flex.card-add-field.js-card-add-field(data-key="{{key}}" role="checkbox" aria-checked="{{#if shownOnThisCard}}true{{else}}false{{/if}}" class="{{#if isAnimating key}}is-animating{{/if}}")
.materialCheckBox(class="{{#if shownOnThisCard}}is-checked{{/if}}")
span {{_ 'card-settings-this-card'}}
if menu.always
div.check-div.card-settings-board-option
a.flex.card-always-show.js-card-always-show(data-key="{{key}}" class="{{#if animatingAlways}}is-animating{{/if}}" role="checkbox" aria-checked="{{#if alwaysShown}}true{{else}}false{{/if}}")
.materialCheckBox(class="{{#if alwaysShown}}is-checked{{/if}}")
span {{_ 'card-settings-show-empty'}}
if menu.labelTextReset
div.check-div.card-settings-board-option
a(class=labelTextResetClass) {{_ 'label-text-use-board-default'}}
+216 -240
View File
@@ -23,14 +23,13 @@ const {
const { rowsForSide, CARD_SETTINGS_ROWS } = require('/models/lib/cardSettingsRows');
const { isRowVisible } = require('/models/lib/cardFieldVisibility');
const cardSettingsSections = require('/models/lib/cardSettingsSections');
const cardShownFields = require('/models/lib/cardShownFields');
import { shownFieldsOf, closeCardSettings } from '/client/components/cards/cardAddFields';
import { filterSubtasksOf } from '/client/lib/filterSubtasks';
const cardSettingsCustomFields = require('/models/lib/cardSettingsCustomFields');
import { invalidateScrumNames } from '/client/components/boards/scrum/scrumFields';
import { InfiniteScrolling } from '/client/lib/infiniteScrolling';
import '/client/components/boards/exportScope';
import AccessibilitySettings from '/models/accessibilitySettings';
import Boards from '/models/boards';
import CustomFields from '/models/customFields';
import CustomBoardRoles from '/models/customBoardRoles';
const { normalizeCustomCapabilities } = require('/models/lib/boardRoleCapabilities');
// What a custom role's description lists, in this order (#3022).
@@ -2047,21 +2046,13 @@ function setUpCardSettings() {
});
}
// The card Card Settings is drawn for: the opened card's own Card Settings
// passes it in (cardDetails.jade `+cardSettingsInline(card=this)`), and its
// hamburgers pass it on. Board Settings / Card has none - it is about every
// card of the board - so On this card is only ever on a card.
function settingsCard() {
const passed = (Template.currentData() || {}).card;
return passed && passed._id ? ReactiveCache.getCard(passed._id) : null;
}
// The rows of one column of Board Settings / Card, ready for the template:
// the board's order for that side (models/lib/cardFieldOrder.js) applied to
// the row table (models/lib/cardSettingsRows.js), each row with the checkbox
// state its own helper reports, its icons, its translated label, and whether
// each arrow would do anything. `data` is the popup's data context, so the
// helpers that read it (showsListOnMinicard, settingsSideClass) see what they
// helpers that read it (showsListOnMinicard) see what they
// saw when the rows were written out by hand.
function buildCardSettingsRows(side, data) {
const boardId = Session.get('currentBoard');
@@ -2070,11 +2061,11 @@ function buildCardSettingsRows(side, data) {
const stored = side === 'card' ? currentBoard?.cardFieldOrder : currentBoard?.minicardFieldOrder;
const order = applyLayoutOrder(stored, layout);
return rowsForSide(side, order)
// "List title" is a CARD's setting: only for somebody who may change the
// card, the same gate the hand-written row had (`if canModifyCard`).
// Only when the popup was opened for a card (its own menu passes it in):
// from Board Settings there is no card for the row to change.
.filter(row => !row[side].needsCard || (Boolean(data?.card?._id) && Utils.canModifyCard(data)))
// "List title" is a CARD's own setting (`needsCard`): Card Settings is
// Board Settings / Card, about every card of the board, with no card for
// the row to change - so it is never drawn here; each card sets it in its
// own menu (cardDetails.js js-toggle-show-list-on-minicard).
.filter(row => !row[side].needsCard)
// A field the administrator unticked in Admin Panel / Settings /
// Visibility / Features is not offered on any board; the board keeps its
// own choice for when it is ticked again. models/lib/cardFieldVisibility.js
@@ -2120,8 +2111,6 @@ function sectionRowsOf(id, data, side, animatingKey) {
const section = cardSettingsSections.SECTIONS.find(s => s.id === id);
const keys = new Set(section ? section.keys : []);
const board = ReactiveCache.getBoard(Session.get('currentBoard'));
// A linked card's data is on its source card; its own choices are its own.
const { card: thisCard, counts } = shownFieldsOf(settingsCard());
const writable = Boolean(board && Utils.canModifyBoard && Utils.canModifyBoard());
const showDragHandles = Utils.showDragHandles();
const rowOf = key => CARD_SETTINGS_ROWS.find(r => r.key === key);
@@ -2145,26 +2134,16 @@ function sectionRowsOf(id, data, side, animatingKey) {
labelTextOverride: built.labelTextOverride,
labelTextOverridden: built.labelTextOverridden,
labelTextResetClass: built.labelTextResetClass,
perCard: side === 'card' && Boolean(thisCard) && cardShownFields.FIELD_KEYS.includes(built.key),
shownOnThisCard: side === 'card' && Boolean(thisCard) && cardShownFields.isShown(built.key, thisCard, counts, board),
// #6806: the board shows this field on every card, empty or not.
alwaysShowable: side === 'card' && cardShownFields.FIELD_KEYS.includes(built.key),
alwaysShown: cardShownFields.boardAlwaysShows(board, built.key),
animatingAlways: animatingKey === `${built.key}:always`,
}));
}
// The card actions of section `id`: in the popup's pane when opened from a
// card, and in that section's hamburger on the opened card's Card Settings.
// The board actions of section `id`, in that section's hamburger in Card
// Settings (models/lib/cardSettingsSections.js CARD_ACTIONS): for who may
// change the board.
function sectionCardActionsOf(id) {
const card = settingsCard();
const mayCard = Boolean(card && Utils.canModifyCard(card));
const mayBoard = Boolean(Utils.canModifyBoard && Utils.canModifyBoard());
return cardSettingsSections.cardActionsOf(id)
// A board action for who may change the board; a card action only with
// a card, Filter: Subtasks for any reader of it, the edits for who may
// change it.
.filter(action => (action.board ? mayBoard : (action.id === 'filterSubtasks' ? Boolean(card) : mayCard)))
.filter(action => action.board && mayBoard)
.map(action => ({
...action,
title: action.label.map(k => TAPi18n.__(k)).join(action.labelSeparator || ' '),
@@ -2177,20 +2156,12 @@ const boardCardSettingsHelpers = {
askForMoveReason() { return ReactiveCache.getBoard(Session.get('currentBoard'))?.askForMoveReason === true; },
isAnimating(key) { return Template.instance().animating.get() === key; },
showEmptyCardFields() {
return cardShownFields.boardShowsEmptyFields(ReactiveCache.getBoard(Session.get('currentBoard')));
},
allowsMinicardCollapse() { return ReactiveCache.getBoard(Session.get('currentBoard'))?.allowsMinicardCollapse !== false; },
labelsAboveTitleOnMinicard() { return ReactiveCache.getBoard(Session.get('currentBoard'))?.labelsAboveTitleOnMinicard === true; },
allowsChecklistDueDate() { return ReactiveCache.getBoard(Session.get('currentBoard'))?.allowsChecklistDueDate !== false; },
allowsChecklistTitle() { return ReactiveCache.getBoard(Session.get('currentBoard'))?.allowsChecklistTitle !== false; },
// The work item type badge was on every minicard before it had a row: on unless turned off.
allowsIssueTypeOnMinicard() { return ReactiveCache.getBoard(Session.get('currentBoard'))?.allowsIssueTypeOnMinicard !== false; },
// Show empty fields: every field is shown, so Show empty is set aside -
// hidden from the rows' hamburgers, its ticks kept.
settingsSideClass() {
return cardShownFields.boardShowsEmptyFields(ReactiveCache.getBoard(Session.get('currentBoard'))) ? 'show-empty-fields' : '';
},
// Board-level DEFAULT (#4256, Board Settings): whether this board shows
// label text on its minicards unless a user overrides it. Checked means
@@ -2220,19 +2191,6 @@ const boardCardSettingsHelpers = {
return typeof (currentUser.profile || {}).showLabelTextOverride === 'boolean';
},
// "List title" is the CARD's own setting, not the board's, so the card is
// passed in with the side (showOnMinicardPopup) rather than looked up: a
// minicard's menu is opened from the board, where there is no "current card".
// Re-read from the collection so the checkbox follows its own click.
showsListOnMinicard() {
const card = settingsCard();
return Boolean(card && card.showListOnMinicard);
},
// ...and on the opened card.
showsListOnCard() {
const card = settingsCard();
return Boolean(card && card.showListOnCard);
},
// The labels text of the OPENED card, the user's override included.
showsCardLabelText() {
return resolveShowCardLabelText(ReactiveCache.getBoard(Session.get('currentBoard')));
@@ -2679,67 +2637,11 @@ function moveCardSettingsRow(evt, direction) {
placeInListOrder(list.dataset.side, rowEl.dataset.key, keys);
}
// Select all / Select none of one column of Card Settings: the board's columns
// for a board admin, On this card for who may change the card. `container`
// holds the rows of the side columns (one checklist of Card Settings), each
// set through its own checkbox's
// handler; `keys` are the rows of On this card and Show empty. A personal
// row (Labels text, List title) is the user's or the card's own, not the
// board's: left as it is.
async function selectCardSettingsColumn(tpl, container, column, on, keys) {
const board = ReactiveCache.getBoard(Session.get('currentBoard'));
if (!container || !board) return;
const isOn = el => el.getAttribute('aria-checked') === 'true';
tpl.animating.set(null);
try {
if (column === 'this') {
const card = settingsCard();
if (!card || !Utils.canModifyCard(card)) return;
const { card: view, counts } = shownFieldsOf(card);
let next = { shownFields: card.shownFields || [], hiddenFields: card.hiddenFields || [] };
keys.forEach(key => {
next = cardShownFields.cardFieldsAfter({ ...view, ...next }, key, on, counts, board);
});
await Cards.updateAsync(card._id, { $set: next });
return;
}
if (!(Utils.canModifyBoard && Utils.canModifyBoard())) return;
if (column === 'always') {
await board.setCardFieldAlwaysShown(keys, on);
return;
}
if (column !== 'minicard' && column !== 'card') return;
const cells = [...container.querySelectorAll(`.js-card-field-order-row[data-side="${column}"]`)]
.filter(cell => !cell.classList.contains('card-settings-row-personal'))
.map(cell => cell.querySelector('.card-field-order-toggle'))
.filter(toggle => toggle && !toggle.classList.contains('is-disabled') && isOn(toggle) !== on);
// The Scrum rows are one write of the board's Scrum visibility: one by
// one, each would carry the same revision and all but the first fail.
const scrum = {};
cells.filter(t => t.classList.contains('js-scrum-field-toggle')).forEach(toggle => {
const key = toggle.closest('.js-card-field-order-row').dataset.key;
const spec = CARD_SETTINGS_ROWS.find(r => r.key === key)?.[column];
if (spec?.scrum) scrum[spec.scrum] = on;
});
if (Object.keys(scrum).length) {
await Meteor.callAsync('scrum.configure', board._id, { visibility: scrum }, board.scrumRevision || 0);
invalidateScrumNames();
}
// Every other row through its own checkbox's handler, which knows the
// field it sets and its default.
cells.filter(t => !t.classList.contains('js-scrum-field-toggle')).forEach(toggle => toggle.click());
} catch (error) {
console.error(error);
} finally {
tpl.animating.set(null);
}
}
// The handlers of Card Settings: the popup Board Settings opens, and the same
// handlers on the opened card's own Card Settings (cardSettingsInline) and its
// hamburgers, so a checkbox does the same thing wherever it is drawn.
const cardSettingsEvents = {
// The same animated checkbox as Show empty fields; a board admin's.
// The same animated checkbox as the rows; a board admin's.
async 'click .js-ask-move-reason'(evt, tpl) {
evt.preventDefault();
const board = ReactiveCache.getBoard(Session.get('currentBoard'));
@@ -2754,70 +2656,63 @@ const cardSettingsEvents = {
// A row is dragged by its handle or its name: a click on them does nothing.
'click .js-card-field-order-handle'(evt) { evt.preventDefault(); },
// A card action of the open section, for the card the popup was opened from.
// A board action of the open section (CARD_ACTIONS), for a board admin.
'click .js-card-settings-action'(evt) {
evt.preventDefault();
const card = settingsCard();
const id = evt.currentTarget.dataset.action;
const action = Object.values(cardSettingsSections.CARD_ACTIONS).flat().find(a => a.id === id);
if (!action) return;
if (action.board) {
Popup.open(action.popup)(evt);
return;
}
if (!card) return;
if (id === 'filterSubtasks') {
filterSubtasksOf(card);
return;
}
if (!Utils.canModifyCard(card)) return;
Popup.open(action.popup, { dataContext: card })(evt);
if (!action || !action.board || !(Utils.canModifyBoard && Utils.canModifyBoard())) return;
Popup.open(action.popup)(evt);
},
// Only the checkbox just clicked animates; its own handler does the change.
'click .card-field-order-toggle'(evt, tpl) {
const cell = evt.currentTarget.closest('.js-card-field-order-row');
if (cell) tpl.animating.set(`${cell.dataset.key}:${cell.dataset.side}`);
},
// Opened from a card: whether THIS card shows the field
// (models/lib/cardShownFields.js) - ticked, an empty one is shown to be
// filled in; unticked, one with data is hidden from this card.
async 'click .js-card-add-field'(evt, tpl) {
evt.preventDefault();
const card = settingsCard();
const key = evt.currentTarget.dataset.key;
if (!card || !cardShownFields.FIELD_KEYS.includes(key) || !Utils.canModifyCard(card)) return;
tpl.animating.set(key);
const { card: view, counts } = shownFieldsOf(card);
const board = ReactiveCache.getBoard(card.boardId);
const next = cardShownFields.cardFieldsAfter(view, key, !cardShownFields.isShown(key, view, counts, board), counts, board);
await Cards.updateAsync(card._id, { $set: next });
},
// Card Settings / Card's "Show empty fields": every card shows all its
// fields, the empty ones too. A board admin's, like the rest.
async 'click .js-show-empty-card-fields'(evt, tpl) {
// The checkbox left of a section's title: whether the whole section is
// shown on the side Card Settings shows (models/lib/cardSettingsSections.js
// hiddenSectionsOf). Its rows keep their own ticks. A board admin's.
async 'click .js-card-settings-section-shown'(evt, tpl) {
evt.preventDefault();
const sectionEl = evt.currentTarget.closest('.js-card-settings-section');
const id = sectionEl && sectionEl.dataset.section;
const side = evt.currentTarget.dataset.side;
const board = ReactiveCache.getBoard(Session.get('currentBoard'));
if (!board || !(Utils.canModifyBoard && Utils.canModifyBoard())) return;
tpl.animating.set('showEmptyCardFields');
if (!board || !id || !cardSettingsSections.SIDES.includes(side)) return;
if (!(Utils.canModifyBoard && Utils.canModifyBoard())) return;
tpl.animating.set(`section:${id}:${side}`);
try {
await board.setShowEmptyCardFields(!cardShownFields.boardShowsEmptyFields(board));
await board.setCardSettingsSectionShown(side, id, !cardSettingsSections.sectionShown(board, side, id));
} catch (error) {
console.error(error);
}
},
// #6806: "Show empty" - every card of the board shows the field, empty or
// not (models/lib/cardShownFields.js). A board admin's, like the rest.
async 'click .js-card-always-show'(evt, tpl) {
// A section with one row on this side is one line (inlineSectionsOf
// `single`): its one checkbox is "this field is shown on this side". It sets
// the row's own flag through the row's own handler - the row's real
// checkbox, kept in the line out of sight - and, turning it on, also shows
// the section again if it was hidden whole.
async 'click .js-card-settings-single-toggle'(evt, tpl) {
evt.preventDefault();
const sectionEl = evt.currentTarget.closest('.js-card-settings-section');
const real = sectionEl && sectionEl.querySelector('.js-card-settings-single-real .card-field-order-toggle');
const id = sectionEl && sectionEl.dataset.section;
const side = evt.currentTarget.dataset.side;
const board = ReactiveCache.getBoard(Session.get('currentBoard'));
const key = evt.currentTarget.dataset.key;
if (!board || !cardShownFields.FIELD_KEYS.includes(key)) return;
if (!(Utils.canModifyBoard && Utils.canModifyBoard())) return;
tpl.animating.set(`${key}:always`);
try {
await board.setCardFieldAlwaysShown(key, !cardShownFields.boardAlwaysShows(board, key));
} catch (error) {
console.error(error);
if (!board || !real || real.classList.contains('is-disabled') || !cardSettingsSections.SIDES.includes(side)) return;
const rowOn = real.getAttribute('aria-checked') === 'true';
const shown = cardSettingsSections.sectionShown(board, side, id);
if (rowOn && shown) {
real.click();
return;
}
if (!rowOn) real.click();
if (!shown) {
try {
await board.setCardSettingsSectionShown(side, id, true);
} catch (error) {
console.error(error);
}
}
},
// The keyboard way to drag: Up and Down on a focused handle or name move
@@ -2888,20 +2783,6 @@ const cardSettingsEvents = {
evt.stopPropagation();
resetCardLabelTextOverride();
},
'click .js-toggle-show-list-on-card'(evt) {
evt.preventDefault();
const card = settingsCard();
if (!card) return;
Cards.update(card._id, { $set: { showListOnCard: !card.showListOnCard } });
},
'click .js-toggle-show-list-on-minicard'(evt) {
evt.preventDefault();
const card = settingsCard();
if (!card) return;
Cards.update(card._id, {
$set: { showListOnMinicard: !card.showListOnMinicard },
});
},
'click .js-field-has-receiveddate'(evt, tpl) {
evt.preventDefault();
const newValue = !tpl.currentBoard.allowsReceivedDate;
@@ -3256,16 +3137,14 @@ const cardSettingsEvents = {
},
};
// ── Card Settings on the opened card ────────────────────────────────────────
// docs/Features/Cards/Card-Settings-On-Card.md. The opened card's "Card
// Settings" button is replaced, with everything below it, by this: a title
// with its X, "Show" with Show on Minicard / Show on Card, and the sections
// as checklists - each a title with its rows as items, the checkbox the
// chosen side's board-wide Show on Minicard or Show on Card. Sections and
// ── Card Settings: Board Settings / Card ────────────────────────────────────
// docs/Features/Cards/Card-Settings.md. "Show" with Show on Minicard / Show on
// Card, and the sections as checklists - each a title with its own checkbox
// (the whole section shown on that side) and its rows as items, the checkbox
// the chosen side's board-wide Show on Minicard or Show on Card. Sections and
// rows are dragged like checklists and their items, and collapse like them;
// what else a section or a row has is in its hamburger. The rows, their
// checkboxes and their handlers are the popup's (sectionRowsOf,
// cardSettingsEvents), so the two cannot disagree.
// what else a section or a row has is in its hamburger, drawn only when it has
// something in it. The opened card has no Card Settings of its own.
// Where the collapsed sections are kept: the user's collapsed card sections
// (models/users.js), under the BOARD's id, because Card Settings is the
@@ -3278,54 +3157,138 @@ function inlineSectionCollapsed(id) {
return Boolean(user && boardId && user.getCollapsedCardSection(boardId, inlineCollapseKey(id)) === true);
}
// What a row's hamburger holds: On this card, Show empty, and the way back
// to the board's Labels text. A row with none of them has no hamburger.
// What a row's hamburger holds: only Labels text's way back to the board's
// default, while the user overrides it. A row with nothing in it has no
// hamburger at all - the icon is not drawn.
function inlineRowMenu(row) {
const board = ReactiveCache.getBoard(Session.get('currentBoard'));
const mayBoard = Boolean(Utils.canModifyBoard && Utils.canModifyBoard());
return {
thisCard: Boolean(row.perCard),
always: Boolean(row.alwaysShowable && mayBoard && !cardShownFields.boardShowsEmptyFields(board)),
labelTextReset: Boolean(row.labelTextOverride && row.labelTextOverridden),
};
}
// Whether a section's hamburger has anything in it: Card's always does (Ask
// for a reason when moving cards, the Draggable table); any other section only
// when it has card or board actions for this user here (sectionCardActionsOf).
// Without, the icon is not drawn.
function sectionHasMenu(section) {
if (section && section.general) return true;
return Boolean(section) && sectionCardActionsOf(section.id).length > 0;
}
function inlineSectionsOf(tpl, data) {
const board = ReactiveCache.getBoard(Session.get('currentBoard'));
const side = tpl.showSide.get();
const mayBoard = Boolean(Utils.canModifyBoard && Utils.canModifyBoard());
const showDragHandles = Utils.showDragHandles();
const animating = tpl.animating.get();
return cardSettingsSections.orderedSections(cardSettingsSections.SECTIONS, board && board.cardSettingsSectionOrder)
.map(section => {
const rows = sectionRowsOf(section.id, data, side, tpl.animating.get()).map(row => {
const rows = sectionRowsOf(section.id, data, side, animating).map(row => {
const menu = inlineRowMenu(row);
// Blaze keeps a row's element by _id, so switching Show moves each
// row to its place on the other side rather than relabelling the rows
// where they stand - a click in between would land on another field.
return { ...row, _id: row.key, menu, hasMenu: menu.thisCard || menu.always || menu.labelTextReset };
return { ...row, _id: row.key, menu, hasMenu: menu.labelTextReset };
});
// Whether the WHOLE section is shown on this side - the checkbox left
// of its title; its rows keep their own ticks while it is not.
const shown = cardSettingsSections.sectionShown(board, side, section.id);
// Custom Fields: its items are the board's custom fields, its own
// checkbox the board's Custom Fields flag of this side - the row that
// was its only item (models/lib/cardSettingsCustomFields.js).
const customFields = section.id === cardSettingsCustomFields.CUSTOM_FIELDS_SECTION;
const customFieldItems = customFields ? customFieldItemsOf(side, animating, mayBoard, showDragHandles) : [];
// One row on this side: one line - its checkbox, its name, the
// section's hamburger (cardSettingsSections.js isSingleRowSection).
const single = !customFields && cardSettingsSections.isSingleRowSection(rows);
const flagRow = single ? rows[0]
: customFields ? rows.find(r => r.key === cardSettingsCustomFields.CUSTOM_FIELDS_ROW) || null : null;
const items = customFields ? customFieldItems : rows;
return {
// Blaze keeps a section's element (and the drag bound to it) by _id.
_id: section.id,
// A section turning into one line (or back) is another element.
_id: `${section.id}${single ? ':single' : ''}`,
id: section.id,
icon: section.icon,
title: TAPi18n.__(section.labelKey),
rows,
checkedCount: rows.filter(r => r.checked).length,
side,
sideTitle: TAPi18n.__(side === 'minicard' ? 'show-on-minicard' : 'show-on-card'),
rows: customFields ? [] : rows,
shown,
writable: mayBoard,
animatingShown: animating === `section:${section.id}:${side}`,
single,
customFields,
customFieldItems,
// The checkbox of one line and of Custom Fields: the row's flag, and
// the section not hidden whole - "this field is shown on this side".
flagRow,
flagChecked: Boolean(flagRow) && cardSettingsSections.singleLineChecked(board, side, section.id, flagRow.checked),
flagWritable: Boolean(flagRow && flagRow.writable),
hasMenu: sectionHasMenu(section),
checkedCount: items.filter(r => r.checked).length,
total: items.length,
collapsed: inlineSectionCollapsed(section.id),
draggable: mayBoard,
showDragHandles,
};
})
// A section with no row on this side is left out - except Card, whose
// hamburger holds what is not a field.
.filter(section => section.rows.length || cardSettingsSections.SECTIONS.find(s => s.id === section.id)?.general);
// hamburger holds what is not a field, and Custom Fields while its flag
// row is offered.
.filter(section => section.rows.length || section.flagRow
|| cardSettingsSections.SECTIONS.find(s => s.id === section.id)?.general);
}
// The board's custom fields as Custom Fields' items in Card Settings, in their
// `sort` order (models/lib/cardSettingsCustomFields.js): each a checkbox - its
// Show on Card (alwaysOnCard) or Show on Minicard (showOnCard) - its name, and
// a hamburger opening its edit form, for a board admin.
function boardCustomFieldDefinitions() {
const boardId = Session.get('currentBoard');
if (!boardId) return [];
return cardSettingsCustomFields.orderedDefinitions(
ReactiveCache.getCustomFields({ boardIds: { $in: [boardId] } }, { sort: { sort: 1, name: 1 } }) || []);
}
function customFieldItemsOf(side, animating, mayBoard, showDragHandles) {
const sideTitle = TAPi18n.__(side === 'minicard' ? 'show-on-minicard' : 'show-on-card');
return boardCustomFieldDefinitions().map(definition => ({
// Blaze keeps an item's element by _id, as it keeps the rows'.
_id: `customField:${definition._id}`,
id: definition._id,
name: definition.name,
side,
sideTitle,
checked: cardSettingsCustomFields.definitionChecked(definition, side),
writable: mayBoard,
animating: animating === `customField:${definition._id}:${side}`,
draggable: mayBoard,
showDragHandles,
hasMenu: mayBoard,
}));
}
// Custom Fields' items dropped in a new order, or one moved a step by Up and
// Down: each definition whose place changed gets its new `sort`, through the
// same CustomFields write as the board sidebar's own list.
function placeCustomFieldOrder(ids) {
if (!(Utils.canModifyBoard && Utils.canModifyBoard())) return;
const sorts = cardSettingsCustomFields.sortsAfterDrop(boardCustomFieldDefinitions(), ids);
Object.entries(sorts).forEach(([id, sort]) => CustomFields.update(id, { $set: { sort } }));
}
// "Show": which side the checkboxes are - the opened card's when Card Settings
// opens. A section's or a row's hamburger is a popup opened FROM Card Settings,
// so it takes Card Settings' place and its back arrow draws Card Settings
// again: the side is kept on Card Settings' own entry of the popup stack, so
// coming back shows the side that was chosen, and a fresh open is Show on Card.
const popupEntry = () => (typeof Popup !== 'undefined' && typeof Popup._getTopStack === 'function' ? Popup._getTopStack() : null);
function setUpCardSettingsInline() {
setUpCardSettings.call(this);
// "Show": which side the checkboxes are - the opened card's, by default.
this.showSide = new ReactiveVar('card');
this.popupEntry = popupEntry();
const kept = this.popupEntry && this.popupEntry.cardSettingsSide;
this.showSide = new ReactiveVar(kept === 'minicard' ? 'minicard' : 'card');
}
Template.cardSettingsInline.onCreated(setUpCardSettingsInline);
@@ -3361,6 +3324,16 @@ Template.cardSettingsInline.onRendered(function () {
// the handle with drag handles on, by the icon and name with them off
// (cardSettingsRowLabel).
Template.cardSettingsInlineSection.onRendered(function () {
// Custom Fields' items reorder within Custom Fields only, as rows do.
const fields = this.find('.js-card-settings-custom-fields-sortable');
if (fields) {
reorderOnDrop(this.$(fields), {
ownListOnly: true,
items: '> .js-card-settings-custom-field.is-positioned', handle: '.js-card-settings-custom-field-handle',
keyOf: el => el.dataset.id,
drop: (id, ids) => placeCustomFieldOrder(ids),
});
}
const list = this.find('.js-card-field-order-sortable');
if (!list) return;
reorderOnDrop(this.$(list), {
@@ -3373,13 +3346,11 @@ Template.cardSettingsInlineSection.onRendered(function () {
Template.cardSettingsInline.events({
...cardSettingsEvents,
'click .js-close-card-settings'(evt) {
evt.preventDefault();
closeCardSettings();
},
'change .js-card-settings-show-side'(evt, tpl) {
tpl.animating.set(null);
tpl.showSide.set(evt.currentTarget.value === 'minicard' ? 'minicard' : 'card');
const side = evt.currentTarget.value === 'minicard' ? 'minicard' : 'card';
tpl.showSide.set(side);
if (tpl.popupEntry) tpl.popupEntry.cardSettingsSide = side;
},
async 'click .js-toggle-card-settings-section'(evt) {
evt.preventDefault();
@@ -3411,30 +3382,60 @@ Template.cardSettingsInline.events({
const id = evt.currentTarget.closest('.js-card-settings-section')?.dataset.section;
evt.preventDefault();
if (!cardSettingsSections.SECTIONS.some(s => s.id === id)) return;
const data = { card: settingsCard(), sectionId: id, side: tpl.showSide.get(), inPopup: Boolean(tpl.data && tpl.data.inPopup) };
const data = { sectionId: id, side: tpl.showSide.get() };
Popup.open('cardSettingsSection', { dataContext: data })(evt);
},
// Custom Fields' items: the checkbox is the definition's flag of this side.
'click .js-card-settings-custom-field-toggle'(evt, tpl) {
evt.preventDefault();
const item = evt.currentTarget.closest('.js-card-settings-custom-field');
const id = item && item.dataset.id;
const side = item && item.dataset.side;
if (!id || !(Utils.canModifyBoard && Utils.canModifyBoard())) return;
// From what the checkbox shows: the cached definition can still be the
// one before a click just made, and two quick clicks would both write on.
const definition = ReactiveCache.getCustomField(id);
const set = definition && cardSettingsCustomFields.definitionToggleSet(side,
evt.currentTarget.getAttribute('aria-checked') !== 'true');
if (!set) return;
tpl.animating.set(`customField:${id}:${side}`);
CustomFields.update(id, { $set: set });
},
// Dragged by its handle or its name: a click there does nothing.
'click .js-card-settings-custom-field-handle'(evt) { evt.preventDefault(); },
'keydown .js-card-settings-custom-field-handle'(evt) {
const direction = ARROW_KEYS[evt.key];
const item = evt.currentTarget.closest('.js-card-settings-custom-field');
if (!direction || !item) return;
evt.preventDefault();
placeCustomFieldOrder(cardSettingsCustomFields.idsAfterStep(boardCustomFieldDefinitions(), item.dataset.id, direction));
},
// Its hamburger: the custom field's own edit form, the board sidebar's.
'click .js-card-settings-edit-custom-field'(evt) {
evt.preventDefault();
const item = evt.currentTarget.closest('.js-card-settings-custom-field');
const definition = item && ReactiveCache.getCustomField(item.dataset.id);
if (!definition || !(Utils.canModifyBoard && Utils.canModifyBoard())) return;
Popup.open('editCustomField', { dataContext: definition })(evt);
},
// "+" under the items: a new custom field of the board, the last item.
'click .js-card-settings-add-custom-field'(evt) {
evt.preventDefault();
if (!(Utils.canModifyBoard && Utils.canModifyBoard())) return;
Popup.open('createCustomField', { dataContext: { boardId: Session.get('currentBoard') } })(evt);
},
'click .js-open-card-settings-item-menu'(evt, tpl) {
const row = evt.currentTarget.closest('.js-card-field-order-row');
const sectionEl = evt.currentTarget.closest('.js-card-settings-section');
if (!row || !sectionEl) return;
evt.preventDefault();
const data = { card: settingsCard(), key: row.dataset.key, sectionId: sectionEl.dataset.section, side: tpl.showSide.get() };
const data = { key: row.dataset.key, sectionId: sectionEl.dataset.section, side: tpl.showSide.get() };
Popup.open('cardSettingsItem', { dataContext: data })(evt);
},
});
// A section's hamburger: Select all / Select none of the shown side, of On
// this card and of Show empty; the section's card actions; and, for Card,
// what is not a field - Show empty fields, asking for a move reason and the
// Draggable table.
// The section in the Card Settings this hamburger was opened from: the opened
// card's and Board Settings / Card's may both be open at once.
function inlineSectionEl(id, inPopup) {
const which = inPopup ? '.card-settings-in-popup' : ':not(.card-settings-in-popup)';
return document.querySelector(`.js-card-settings-inline${which} .js-card-settings-section[data-section="${id}"]`);
}
// A section's hamburger: the section's card actions; and, for Card, what is
// not a field - asking for a move reason and the Draggable table.
Template.cardSettingsSectionPopup.onCreated(setUpCardSettings);
Template.cardSettingsSectionPopup.helpers({
...boardCardSettingsHelpers,
@@ -3442,42 +3443,17 @@ Template.cardSettingsSectionPopup.helpers({
return Boolean(cardSettingsSections.SECTIONS.find(s => s.id === this.sectionId)?.general);
},
sectionActions() { return sectionCardActionsOf(this.sectionId); },
sideTitle() { return TAPi18n.__(this.side === 'minicard' ? 'show-on-minicard' : 'show-on-card'); },
maySelectSide() { return Boolean(Utils.canModifyBoard && Utils.canModifyBoard()); },
maySelectThisCard() {
const card = settingsCard();
return this.side === 'card' && Boolean(card && Utils.canModifyCard(card));
},
maySelectAlways() {
const board = ReactiveCache.getBoard(Session.get('currentBoard'));
return this.side === 'card' && Boolean(Utils.canModifyBoard && Utils.canModifyBoard())
&& !cardShownFields.boardShowsEmptyFields(board);
},
});
Template.cardSettingsSectionPopup.events({
...cardSettingsEvents,
async 'click .js-card-settings-inline-select'(evt, tpl) {
evt.preventDefault();
const { column, value } = evt.currentTarget.dataset;
const data = Template.currentData();
const rows = sectionRowsOf(data.sectionId, data, 'card', null);
const keys = column === 'this' ? rows.filter(r => r.perCard).map(r => r.key)
: column === 'always' ? rows.filter(r => r.alwaysShowable).map(r => r.key) : [];
await selectCardSettingsColumn(tpl, inlineSectionEl(data.sectionId, data.inPopup), column, value === 'all', keys);
},
});
Template.cardSettingsSectionPopup.events(cardSettingsEvents);
// A row's hamburger: On this card, Show empty, and Labels text's way back to
// the board's default.
// A row's hamburger: Labels text's way back to the board's default.
Template.cardSettingsItemPopup.onCreated(setUpCardSettings);
Template.cardSettingsItemPopup.helpers({
...boardCardSettingsHelpers,
itemRow() {
const tpl = Template.instance();
const row = sectionRowsOf(this.sectionId, this, this.side, tpl.animating.get()).find(r => r.key === this.key);
// `card` too: inside `with itemRow` the row is the data the shared
// handlers read the card from (settingsCard).
return row ? { ...row, menu: inlineRowMenu(row), card: this.card } : null;
return row ? { ...row, menu: inlineRowMenu(row) } : null;
},
});
Template.cardSettingsItemPopup.events(cardSettingsEvents);
+3 -3
View File
@@ -26,9 +26,9 @@
const MOBILE_POPUP_MAX_WIDTH = 800;
// Board Settings / Card's widest; popup.css says the same
// (`.pop-over[data-popup='boardCardSettingsPopup']`). It is the opened
// card's Card Settings (docs/Features/Cards/Card-Settings-On-Card.md) - one
// column of checklists - so about as wide as an opened card.
// (`.pop-over[data-popup='boardCardSettingsPopup']`). It is Card Settings
// (docs/Features/Cards/Card-Settings.md) - one column of checklists - so
// about as wide as an opened card.
const CARD_SETTINGS_MAX_WIDTH = 600;
function computePopupOffset(params) {
@@ -6,31 +6,27 @@ Description or Custom Fields and wants that section first, right under the
card title, or wants the minicard to lead with its due date rather than its
labels.
**Show on Card** says what the cards of the board CAN show. Each opened card
then shows only the fields it has data in - plus its description, attachments
and comments - and its own **Card Settings** button shows these same
settings on the card itself, as checklists, with **On this card** in each
field's hamburger ([Card Settings on the opened card](../../Cards/Card-Settings-On-Card.md)).
Board Settings / Card is that same Card Settings, drawn by the same
templates, in a popup: **Show** chooses **Show on Minicard** or **Show on
Card**, then the sections (Card, Date, Time, Members, Labels, ... Voting,
Planning Poker, Scrum settings, Comments) are checklists - a section is a
checklist's title, its fields the items. There is no card here, so a row's
hamburger has no **On this card**; everything else is as on the card
([Card Settings on the opened card](../../Cards/Card-Settings-On-Card.md)).
This is [Card Settings](../../Cards/Card-Settings.md) - the only place it is:
the opened card has no Card Settings of its own. **Show on Card** says what
every opened card of the board shows - every field ticked, empty or not -
and **Show on Minicard** what every minicard shows. **Show** chooses which,
then the sections (Card, Date, Time, Members, Labels, ... Voting, Planning
Poker, Scrum settings, Comments) are checklists - a section is a checklist's
title with a checkbox of its own, its fields the items.
## Where to find it
**Board sidebar (hamburger menu) → Board Settings → Card**; on an opened
card, its **Card Settings** button shows the same settings on the card.
**Board sidebar (hamburger menu) → Board Settings → Card**.
| part | what it does |
| --- | --- |
| Show | which side the checkboxes and the order are: the minicard's or the opened card's |
| checkbox | whether that side shows the field at all - the same board toggles as before (`allowsLabels`, `allowsLabelsOnMinicard`, ...) |
| a row's hamburger | **Show empty**: every card shows the field, empty or not - by default the description, attachments and comments ([#6806](https://github.com/wekan/wekan/issues/6806)); on a card also **On this card** |
| a section's hamburger | **Select all** / **Select none** for that section's rows; its actions (Subtask settings, Create Field, ...); for **Card** also Show empty fields, Ask for a reason when moving cards and the Draggable table |
| a row's checkbox | whether that side shows the field at all - the same board toggles as before (`allowsLabels`, `allowsLabelsOnMinicard`, ...) |
| a section's checkbox | whether that side shows the whole section at all (`cardSettingsHiddenOnCard`, `cardSettingsHiddenOnMinicard`); the rows keep their ticks |
| a one-row section | one line: one checkbox - the field's own - its name, its hamburger (Subtasks, Voting, Planning Poker) |
| Custom Fields | its items are the board's custom fields - Show on Card is *add to all cards*, Show on Minicard is *show on minicard* - dragged to reorder, **+** to create one |
| a row's hamburger | only Labels text's way back to the board's default, while overridden; no other row has one |
| a section's hamburger | Card: Ask for a reason when moving cards and the Draggable table; Subtasks: Subtask settings; no other section has one |
| drag and drop | move a field earlier or later **on the chosen side only**, within its section; move a whole section above or below another |
What is dragged follows the member's drag handles setting: with drag handles
@@ -39,20 +35,10 @@ the icon and name. Up and Down on a focused handle or name move it one row. A
field cannot move to another section: dropped there, it goes back where it
was and nothing is saved.
## Show empty fields
In Card's hamburger is **Show empty fields**, a board-wide switch, off by
default, saved to the board (`showEmptyCardFields`):
- **Off** - an opened card shows the fields it has data in, plus the fields
ticked **Show empty**.
- **On** - every opened card shows every field ticked **Show on Card**, empty
or not. **Show empty** then leaves the rows' hamburgers, because it has
nothing left to decide; what was ticked is kept, and comes back into effect
when the switch is turned off.
**Ask for a reason when moving cards** sits under it, as the same animated
checkbox.
Removed on 2026-10-28: the opened card's **Card Settings** button, **On this
card**, **Show empty**, **Show empty fields** and the hamburgers' **Select
all / Select none**. Every opened card shows every field its board shows,
empty or not.
The minicard order and the card order are independent: a field can be third
on the minicard and last on the card.
@@ -60,14 +46,14 @@ on the minicard and last on the card.
## Steps to use it
1. Open a board you are an admin of, click the sidebar's hamburger menu,
then **Board Settings → Card** - or click **Card Settings** on an opened
card, which shows the same settings on the card.
then **Board Settings → Card**.
2. Choose **Show on Card** or **Show on Minicard**.
3. Drag a field within its section to move it on that side, or a section to
move the whole section.
4. The change takes effect immediately on every card of this board; there
is no separate save step.
5. Untick a checkbox to hide the field on that side; tick it to show it.
Untick a section's checkbox to hide the whole section on that side.
A row that cannot move (see below) is not dragged. A dropped row goes right
after the row now above it in the side's whole order (or right before the row
@@ -175,13 +161,14 @@ All are on by default except the minicard's forecast.
`applyMinicardOrder`) and the move (`moveKey`). Pure, tested without
Meteor by `tests/cardFieldOrderLayout.test.cjs` and
`tests/cardFieldOrder.test.cjs`.
- `models/lib/cardShownFields.js` - which fields an opened card shows:
`isShown()` reads the board's `cardFieldsAlwaysShown` (the Show empty
column, written by `board.setCardFieldAlwaysShown()`) and
`showEmptyCardFields` (`board.setShowEmptyCardFields()`). A linked card is
decided from its source card's data. Pinned by
`tests/cardFieldsAlwaysShown6806.test.cjs` and
`tests/linkedCardShownFields.test.cjs`.
- `models/lib/cardShownFields.js` - the board as its opened cards and its
minicards see it (`boardForCard`, `boardForMinicard`): the rows of a
section hidden on that side read false. It does not depend on the card.
`models/lib/cardSettingsSections.js` holds the hidden-section rules
(`hiddenSectionsOf`, `hiddenSectionsAfter`, `rowKeysHiddenBySections`),
written through `board.setCardSettingsSectionShown(side, id, shown)`.
Pinned by `tests/cardSettingsSectionShown.test.cjs` and
`tests/cardShownFields.test.cjs`.
- `models/lib/cardSettingsRows.js` - the rows of the popup: toggle class,
board field, icons and label keys of every setting.
- Stored on the board as `cardFieldOrder` and `minicardFieldOrder`, flat
+84 -163
View File
@@ -1,67 +1,39 @@
# Card fields: only what the card has, and Card Settings
# Card fields: every field the board shows, empty or not
An opened card shows **only the fields it has data in**. A card with a due date
and two labels shows its due date and its labels, and not the empty start date,
received date, members, custom fields and the rest beside them.
An opened card shows **every field its board shows on cards** - Board
Settings / Card's **Show on Card** checkbox of the field's row - **empty or
not**. An empty Due date, an empty Members, an empty Custom Fields section are
drawn on every card of a board that shows them, ready to be filled in. A field
the board does not show is on no card, whatever the card holds.
## What every card shows
Until 2026-10-28 an opened card showed only the fields it had data in, plus
what the board's **Show empty** column, Card's **Show empty fields** and the
card's own **On this card** added. All three are gone, and the opened card has
no **Card Settings** button any more: what the cards of a board show is set in
one place, [Card Settings](Card-Settings.md) - **Board Settings / Card**.
By default three things are always there, empty or not, because they are what
a card is for - and the cover when there is one:
## What decides what a card shows
| Shown | When |
| Decides | Where |
| --- | --- |
| **Cover** | when the card has a cover - on by default in Board Settings / Card; a new drawing becomes the cover |
| **Description** (its title and its text) | always, also when empty |
| **Attachments**, with **Add attachment** | always, also when there are none |
| **Comments** | always, also when there are none |
| Whether a field is shown on the board's cards | its row's checkbox with **Show on Card** chosen |
| Whether a whole section (Date, Members, ...) is shown on them | the section's own checkbox, left of its title |
| Whether the administrator offers the field at all | Admin Panel / Settings / Visibility / Features |
Which fields are always shown is the board's choice: Board Settings / Card's
**Show empty** column (below). Unticked there, the description, the
attachments and the comments are shown when they have something in them, like
any other field.
Two sections still appear only when there is something to show: **Similar
cards**, when the board has cards like this one, and the **cover**, when the
card has one (on by default in Board Settings / Card; a new drawing becomes
the cover). **Custom Fields** is on every card the reader may change whose
board shows it: its hamburger is where the fields are added to the card.
Two sections are shown only when there is something in them: **Similar
cards**, when the board has cards like this one, and **Custom Fields**, when
the card has a custom field value (or Custom Fields is ticked **On this card**
in Card Settings, which is how a card with none gets the section and its menu).
## Card Settings
Every other field is shown when it has data: a date that is set, labels,
members, a checklist, a custom field with a value, a vote question, a Scrum
sprint, and so on. A creator, a card number, the history and the other
fields every card has anyway are shown only when added.
## Card Settings on the card, and Board Settings / Card
Under the cover, above the card's fields, the **Card Settings** button (it was
**+ Add**) replaces itself and everything below it with Card Settings, on the
card: its sections as checklists, their rows as checklist items, Show on
Minicard / Show on Card choosing what the checkboxes are, and On this card and
Show empty in each row's hamburger. That design is
[Card Settings on the opened card](Card-Settings-On-Card.md).
[Board Settings / Card](../Board-Sidebar/Board-Settings/Card.md) is the same
Card Settings, drawn by the same templates, in a popup: **Show**, then the same
sections as checklists, the same rows and the same hamburgers. There is no
card there, so a row's hamburger has no **On this card**, and the popup's
header is the title and the close button.
- A row's **checkbox** is the board-wide Show on Card or Show on Minicard,
whichever **Show** chooses.
- **Show empty**, in a row's hamburger, for every per-card field: ticked,
every card of the board shows the field, empty or not
([#6806](https://github.com/wekan/wekan/issues/6806)). By default the
description, attachments and comments are ticked.
- **On this card**, in a row's hamburger on a card, says whether this card
shows the field (the per-card fields only).
- A section's hamburger has **Select all** and **Select none** of the chosen
side, of On this card and of Show empty, for that section's rows - the
board's for a board admin, On this card for who may change the card. A
personal row (Labels text, List title) is left as it is. Card's hamburger
also holds what is not a field: **Show empty fields**, Ask for a reason when
moving cards and the Draggable table.
- Sections and rows are reordered by **drag and drop**, a row only within its
section (see [Card Settings on the opened card](Card-Settings-On-Card.md)).
[Card Settings](Card-Settings.md) is Board Settings / Card: **Show**, then the
sections as checklists, their rows as checklist items, Show on Minicard / Show
on Card choosing what the checkboxes are. Each section has a checkbox of its
own for the whole section; a section with one row is one line; Custom Fields'
items are the board's custom fields with a **+** under them. A hamburger is
drawn only when it has something in it.
A row's name leaves out what its section already says: under **Scrum settings**
the rows are Sprint, Past sprints, Release, Issue type, Acceptance criteria and
@@ -69,144 +41,93 @@ Backlog rank.
| Section | Rows |
| --- | --- |
| Card | Ask for a reason when moving cards, Draggable; Card number, Collapse, Parent card, Linked card, Dependencies, Card sorting by number, Show lists, List title, Swimlane, Card buttons, Similar cards |
| Card | Ask for a reason when moving cards, Draggable (in its hamburger); Card number, Collapse, Parent card, Linked card, Dependencies, Card sorting by number, Show lists, Swimlane, Card buttons, Similar cards |
| Date | Received, Start, Due, End, Mark as complete, Due date from the title, At risk, Forecast |
| Time | Spent time, Flowtime, Pomodoro |
| Members | Members, Assignee, Creator, Requested by, Assigned by, Suggested members |
| Labels | Labels, Labels above the title, Labels text (the board's and your own), Stickers, Location, Card color |
| Description | Description title, Description text, Description badge |
| Checklists | Checklists, Checklist title, Checklist due date, Checklist count, Checklist from description |
| Subtasks | Subtasks |
| Subtasks | Subtasks (one line) |
| Attachments | Cover image, Attachments, Attachment count, Previews, Details, Text notes, Drawing |
| Custom Fields | Custom Fields |
| Voting | Voting question |
| Planning Poker | Planning Poker |
| Custom Fields | the board's custom fields, and **+** |
| Voting | Voting question (one line) |
| Planning Poker | Planning Poker (one line) |
| Scrum settings | Sprint, Past sprints, Release, Issue type, Acceptance criteria, Backlog rank |
| Comments | Comments, Comment count, Unread comments, Activities, Action items |
**On this card**: ticking an empty field shows it on this card, ready to be
filled in; unticking a field hides it from this card, also when it has data -
the data stays, and ticking it again shows it. The choice is the card's own and
is kept with the card; a field whose tick matches what its data would decide
leaves nothing stored.
**Show empty** chooses what every card of the board shows from the start,
ready to be filled in. A board where nearly every card gets the same fields -
labels, a due date, a checklist - ticks those; a board that does not want an
empty description or comments on every card unticks them, and they are shown
when they have something in them. A card still hides an always-shown field by
unticking **On this card**, and a field turned off in **Show on Card** stays
off. It is the board's setting, for a board admin; with Show on Minicard
chosen it is not in the rows' hamburgers.
**Show empty fields**, in Card's hamburger, is off by default.
Ticked, every card of the board shows all its fields - the empty ones too, as
far as Show on Card allows - and **Show empty** leaves the rows' hamburgers, because
every field is then shown anyway. Their ticks are kept: unticked again, Show
empty fields brings them back as they were. It is saved to the board
(`showEmptyCardFields`), for a board admin.
**Card Settings** on the card is shown to whoever may change the card. Its board-wide checkboxes
and dragging work for a board admin; for anybody else they are shown disabled,
and only **On this card** and their own rows (Labels text, List title) change.
Below the **Card Settings** button there is one separator line, above the first section the card
shows: a section the card does not show draws no line of its own.
**List title** - a card's own choice to show its list's name - is not in Card
Settings (there is no card there); each card sets it in its own menu.
Board Settings / Card moves by its title bar (or the drag handle, when drag
handles are on) and has maximize / minimize beside its close button.
## Card actions in their sections
Five actions that were in the opened card's actions menu are in the section
they act on: in the **hamburger** at the end of that section's heading on the
opened card, and in that section's hamburger in Card Settings.
Actions that were in the opened card's actions menu are in the section they
act on, in the **hamburger** at the end of that section's heading on the
opened card:
| Action | Opened card | Card Settings section |
| --- | --- | --- |
| Filter: Subtasks | Subtasks hamburger (with the subtask settings) | Subtasks |
| Edit voting | Voting hamburger | Voting |
| Edit Planning Poker | Planning Poker hamburger | Planning Poker |
| Change spent time | Spent time hamburger | Time |
| Card kind | Scrum settings hamburger | Scrum settings |
| Subtask settings | Subtasks hamburger | Subtasks - also from Board Settings, for a board admin |
| Edit custom fields | Custom Fields hamburger | Custom Fields |
| Create Field | Custom Fields hamburger, then Create Field | Custom Fields - also from Board Settings, for a board admin |
| Link fields to another card | Custom Fields hamburger, then Link fields | Custom Fields |
| Action | Opened card |
| --- | --- |
| Filter: Subtasks | Subtasks hamburger (with the subtask settings) |
| Edit voting | Voting hamburger |
| Edit Planning Poker | Planning Poker hamburger |
| Change spent time | Spent time hamburger |
| Card kind | Scrum settings hamburger |
| Subtask settings | Subtasks hamburger - also in Card Settings' Subtasks hamburger, for a board admin |
| Edit custom fields | Custom Fields hamburger |
| Create Field | Custom Fields hamburger, then Create Field - also Card Settings' **+** under Custom Fields |
| Link fields to another card | Custom Fields hamburger, then Link fields |
Each opens its own popup, as from the opened card. A card's action is there
only with a card; a board's (Subtask settings, Create Field) is also in Board
Settings / Card, for a board admin.
Each opens its own popup. A card's own actions are on the card; Card Settings,
which is about every card of the board, has only the board's
(`tests/cardSectionActions.test.cjs`). Filter: Subtasks is for every reader;
the editing actions are for whoever may change the card.
Everything in a section's hamburger on the opened card is also in that
section's hamburger in Card Settings (`tests/cardSectionActions.test.cjs` fails
for a hamburger that is not).
## The rows that are not a field of their own
A section is on the opened card when the field is on in Card Settings and the
card has data in it or shows it **On this card**: tick Voting "On this card" to
get the Voting heading, then its hamburger asks the question. The Scrum fields
the card shows are one section, **Scrum settings**, under one heading, each
field by its own name. Filter: Subtasks is for every reader; the editing
actions are for whoever may change the card.
## Board Settings / Card still decides what a card can show
**Show on Card** and Admin Panel / Settings / Visibility / Features decide what
the cards of a board CAN show. A field turned off there is shown on no card,
whatever the card's data or its own choice.
The rows that are not a field of their own - Collapse, Labels text, Labels
above the title, the attachment previews and details, the count badges, Card
color, Parent and Linked card, and the helpers such as Similar cards, At risk,
Forecast and Due date from the title - change how a shown field looks or help
to fill it. They follow Board Settings / Card alone and have no **On this
card**.
Collapse, Labels text, Labels above the title, the attachment previews and
details, the count badges, Card color, Parent and Linked card, and the helpers
such as Similar cards, At risk, Forecast and Due date from the title change how
a shown field looks or help to fill it. They follow Board Settings / Card like
every row.
## How it works
`models/lib/cardShownFields.js` holds the rules: what counts as data for each
field, which fields a card shows, and the card's view of the board.
`models/lib/cardSettingsSections.js` holds the popup's sections. The card stores two lists:
| Field | Holds |
| --- | --- |
| `shownFields` | fields shown although empty |
| `hiddenFields` | fields hidden although they have data |
Only the per-card field keys are accepted (`models/cards.js`).
The board stores **Show empty** as `cardFieldsAlwaysShown`, a list of those
keys (`models/boards.js`, written normalised by `setCardFieldAlwaysShown`). A
board that never set it always shows `descriptionTitle`, `descriptionText`,
`attachments` and `comments`; once set, the list is exactly what is ticked -
an empty list too. A card that has made no choice of its own shows a field
when it has data or the board always shows it.
The opened card's templates read the board's flags (`currentBoard.allowsDueDate`
and so on). The opened card and each of its section templates get their own
`currentBoard` helper (`client/components/cards/cardAddFields.js`): this card's
view of the board, whose flags read false for the fields the card does not
show - the same overlay as Admin Panel / Visibility / Features
(`models/lib/cardFieldVisibility.js`), one level down. The board itself is
never changed, and the minicard and the rest of the board are not affected.
The Scrum fields, which are sections of their own, are left out of the card's
`currentBoard` helper (`client/components/cards/cardAddFields.js`
`CARD_FIELD_TEMPLATES`): the board as its cards see it
(`models/lib/cardShownFields.js` `boardForCard`), whose flags read false for
the rows of a section hidden whole on Show on Card - the same overlay as Admin
Panel / Visibility / Features (`models/lib/cardFieldVisibility.js`), one level
down. It is the same for every card of the board: it does not depend on what
the card holds. The minicard has its own (`boardForMinicard`,
`client/components/cards/minicard.js`). The board itself is never changed. The
Scrum fields, which are sections of their own, are left out of the card's
section order the same way.
The legacy fields - `shownFields` / `hiddenFields` on a card,
`cardFieldsAlwaysShown` / `showEmptyCardFields` on a board - stay in the
schema so documents that have them validate; nothing reads or writes them.
## Related files
| File | What it is |
| --- | --- |
| `models/lib/cardShownFields.js` | "Has data", what a card shows, the card's board view |
| `models/lib/cardSettingsSections.js` | The popup's sections, and the row names within them |
| `client/components/sidebar/sidebar.jade` | Card Settings (`cardSettingsInline`), and Board Settings / Card (`boardCardSettingsPopup`), which is the same template |
| `client/components/sidebar/sidebar.js` | Its sections, the two lists, checkboxes, drag and drop and On this card |
| `models/lib/cardShownFields.js` | The card's and the minicard's board view, `boardAllows` |
| `models/lib/cardSettingsSections.js` | Card Settings' sections, the row names within them, which sections are hidden per side |
| `models/lib/cardSettingsCustomFields.js` | Custom Fields' items in Card Settings |
| `client/components/sidebar/sidebar.jade`, `sidebar.js` | Card Settings (`boardCardSettingsPopup`, `cardSettingsInline`) |
| `client/components/sidebar/sidebar.css`, `client/components/cards/cardAddFields.css` | A row's line; the checklist look |
| `client/components/cards/cardAddFields.js` | Card Settings opened on the card, and the card's own `currentBoard` |
| `client/components/cards/cardDetails.jade` | The Card Settings button under the cover, the section hamburgers |
| `client/components/cards/cardAddFields.js` | The opened card's own `currentBoard` |
| `client/components/cards/cardDetails.jade` | The opened card, its section hamburgers |
| `client/lib/filterSubtasks.js` | Filter: Subtasks |
| `tests/cardSectionActions.test.cjs` | The five actions in their sections, none left in the actions menu |
| `models/cards.js` | `shownFields`, `hiddenFields` |
| `tests/cardShownFields.test.cjs` | The rules, the wiring, and that no card section template is left out |
| `tests/cardFieldsAlwaysShown6806.test.cjs` | Show empty and Show empty fields: the defaults, the rule, its storage, its column, that every caller passes the board |
| `tests/cardShownFields.test.cjs` | The rule, the wiring, and that no card section template is left out |
| `tests/cardFieldsAlwaysShown6806.test.cjs` | #6806 met by the rule; Show empty and Show empty fields gone |
| `tests/cardSettingsSectionShown.test.cjs` | The section checkbox, one-line sections, the views |
| `tests/cardSectionActions.test.cjs` | The actions in their sections, none left in the actions menu |
| `tests/cardSettingsCoverage.test.cjs` | Every row in a section, a checkbox and a handler for each side |
| `tests/playwright/specs/card-add-fields.e2e.js` | An empty card, Card Settings on the card, a field with data, the popup |
| `docs/Features/Cards/Card-Settings-On-Card.md` | Card Settings on the opened card |
| `tests/playwright/specs/card-add-fields.e2e.js` | An empty card, Card Settings, the section checkbox, Custom Fields |
| `docs/Features/Cards/Card-Settings.md` | Card Settings |
@@ -1,110 +0,0 @@
# Card Settings on the opened card
The opened card has a **Card Settings** button under its cover (it used to be
**+ Add**). Clicking it does not open a popup: the button, and everything
below it on the card, is **replaced** by Card Settings itself, right on the
card. The **X** at the end of its title puts the card back.
**Board Settings / Card is the same Card Settings**, drawn by the same
templates, in a popup: Show, then the same sections as checklists with the
same rows and hamburgers. Only two things differ, because there is no card:
the popup's own header is the title and the close button, and a row's
hamburger has no **On this card**.
## Top to bottom
```
Card Settings [X]
Show ( ) Show on Minicard (•) Show on Card
▾ ⠿ Card 7/11 [≡]
[x] Card number
[ ] Collapse
...
▾ ⠿ Date 2/8 [≡]
[x] Due [≡]
[ ] Start [≡]
...
▸ ⠿ Time 1/3 [≡]
...
```
1. **Card Settings** - the title, with the **X** (close) at the right end of
the title's line (the left end in a right-to-left language).
2. **Show** and two radio buttons, **Show on Minicard** and **Show on Card**.
They choose which side the checkboxes below are: what the board's
minicards show, or what its opened cards show. Show on Card is chosen when
Card Settings opens.
3. The **sections** - Card, Date, Time, Members, Labels, Description,
Checklists, Subtasks, Attachments, Custom Fields, Voting, Planning Poker,
Scrum settings and Comments - drawn like the card's **checklists**:
- the section is the **checklist's title**, with how many of its rows are
ticked (`2/8`) and a **hamburger** menu;
- its rows are the **checklist items**: a **checkbox**, the row's name and,
when it has any, its own **hamburger**.
A section with no row on the chosen side is left out, except Card, whose
hamburger holds what is not a field.
## The checkbox
An item's checkbox says whether that field is **visible on the chosen side**,
for every card of the board: with **Show on Card** it is the board's Show on
Card, with **Show on Minicard** the board's Show on Minicard. It is the same
setting Board Settings / Card shows, so the two always agree. It is a board
admin's: for anybody else it is shown disabled, except their own rows (Labels
text, List title).
## Hamburgers
| Hamburger | Holds |
| --- | --- |
| A row's | **On this card** - whether THIS card shows the field ([Card fields](Card-Fields.md)); **Show empty** - whether every card shows it empty ([#6806](https://github.com/wekan/wekan/issues/6806)), while Show empty fields is off; Labels text's way back to the board's default. A row with none of these has no hamburger. |
| A section's | **Select all** / **Select none** of the chosen side, of On this card and of Show empty, for that section's rows; the section's card actions (Filter: Subtasks, Edit voting, Card kind, Edit custom fields, ... - a card's own only on a card, a board's also in Board Settings); and for **Card**: Show empty fields, Ask for a reason when moving cards, and the Draggable table. |
On this card is for whoever may change the card; Show empty and the selects of
the board's columns are a board admin's.
## Drag and drop, collapse
What a section or a row is dragged by follows the member's **drag handles**
setting, as checklists do:
| Drag handles | Dragged by | The rest of the line |
| --- | --- | --- |
| On | the handle only | scrolls the page, as a touch there means to |
| Off | the icon and name (a section: its title) | - |
- A **section** is dragged above or below another, as a checklist is. The
order is the board's (`cardSettingsSectionOrder`), so every member sees the
sections in it; a section added to WeKan later appears in its default place.
- A **row** is dragged within its section, as a checklist item is. That moves
the field on the chosen side: the card's order with Show on Card, the
minicard's with Show on Minicard.
- A row **cannot move to another section**: the sections are unrelated kinds
of fields. Dropped on another section, it goes back where it was, and
nothing is saved.
- The **Up** and **Down** keys on a focused section title or row name move it
one step.
- Only a board admin drags.
- The caret before a section's title **collapses** and expands it, as a
checklist's caret does. Collapsed sections are the user's own, kept per
board.
## How it works
| File | What it is |
| --- | --- |
| `client/components/cards/cardDetails.jade` | The Card Settings button; `if cardSettingsOpen` draws `+cardSettingsInline` in place of the button and everything below it |
| `client/components/cards/cardAddFields.js` | Which card it is open on (`isCardSettingsOpen`, `closeCardSettings`), closed when the card closes |
| `client/components/sidebar/sidebar.jade` | `cardSettingsInline`, `cardSettingsInlineSection`, `cardSettingsSectionPopup`, `cardSettingsItemPopup`; `boardCardSettingsPopup` is `+cardSettingsInline(inPopup=true)` |
| `client/components/sidebar/sidebar.js` | The rows (`sectionRowsOf`), the handlers (`cardSettingsEvents`), Select all (`selectCardSettingsColumn`), the drags (`reorderOnDrop`, `ownListOnly` for a row) |
| `client/components/cards/cardAddFields.css` | The checklist look |
| `models/lib/cardSettingsSections.js` | The sections, and their order: `sectionOrder`, `orderedSections`, `sectionOrderAfterDrop` |
| `models/boards.js` | `cardSettingsSectionOrder`, `setCardSettingsSectionOrder` |
| `tests/cardSettingsOnCard.test.cjs` | The order rules, the layout, the shared handlers, the translations |
| `tests/playwright/specs/card-add-fields.e2e.js` | The button, the replaced card, the checkbox, the hamburgers, the drag and collapse |
The card and Board Settings / Card draw the same templates with the same
handlers, not a copy: a checkbox does the same thing wherever it is drawn, and
a row added to Card Settings is in both.
+183
View File
@@ -0,0 +1,183 @@
# Card Settings
**Card Settings is Board Settings / Card**: a popup opened from the board's
cog menu (**Board Settings → Card**). It decides what **every opened card**
and **every minicard** of the board shows, and in what order. The opened card
has no Card Settings of its own (until 2026-10-28 it had a **Card Settings**
button under its cover that drew the same thing on the card; it is gone, and
so is **On this card**).
An opened card shows **every field its board shows on cards**, empty or not:
an empty Due, an empty Members, an empty Custom Fields section are drawn,
ready to be filled in ([Card fields](Card-Fields.md)).
## Top to bottom
```
Card Settings [□] [X] <- the popup's header
Show ( ) Show on Minicard (•) Show on Card
▾ ⠿ [x] Card 7/11 [≡]
[x] Card number
[ ] Collapse
...
▾ ⠿ [x] Date 2/8
[x] Due
[ ] Start
...
▸ ⠿ [x] Time 1/3
▾ ⠿ [x] Custom Fields 1/2
[x] Priority [≡]
[ ] Estimate [≡]
[+]
⠿ [x] Voting
...
```
1. **Show** and two radio buttons, **Show on Minicard** and **Show on Card**.
They choose which side the checkboxes below are: what the board's
minicards show, or what its opened cards show. Show on Card is chosen when
Card Settings opens.
2. The **sections** - Card, Date, Time, Members, Labels, Description,
Checklists, Subtasks, Attachments, Custom Fields, Voting, Planning Poker,
Scrum settings and Comments - drawn like the card's **checklists**:
- the section is the **checklist's title**: its caret, its drag handle, a
**checkbox** of its own, its name, how many of its rows are ticked
(`2/8`) and - only when it has something in it - a **hamburger**;
- its rows are the **checklist items**: a **checkbox**, the row's name and,
when it has anything in it, its own **hamburger**.
A section with no row on the chosen side is left out, except Card, whose
hamburger holds what is not a field.
## The checkboxes
**A row's checkbox** says whether that field is **visible on the chosen
side**, for every card of the board: with **Show on Card** it is the board's
Show on Card, with **Show on Minicard** the board's Show on Minicard.
**A section's checkbox**, left of its title, says whether the **whole
section** is shown on the chosen side at all:
- Unticked on **Show on Card**, the section is missing from every opened card
of the board, whatever its rows are ticked; unticked on **Show on
Minicard**, from every minicard. The two sides are independent.
- The rows **keep their own ticks** while their section is hidden (drawn
faded), so ticking the section back shows exactly what was shown before.
- The count `n/m` stays.
The board stores the hidden sections of each side, `cardSettingsHiddenOnCard`
and `cardSettingsHiddenOnMinicard` (lists of section ids), written by
`board.setCardSettingsSectionShown(side, sectionId, shown)`.
Every checkbox is a board admin's: for anybody else it is shown disabled,
except their own row (Labels text).
## A section with one row is one line
A section that has exactly **one row** on the chosen side - Subtasks, Voting,
Planning Poker - is drawn as **one line**: one checkbox, its name, and the
section's hamburger when it has one. No caret, no count, no item under it. It
still drags as a section.
Its checkbox reads **this field is shown on this side**: ticked when the
row's own flag is on and the section is not hidden. Clicking it sets the
row's own flag (through the row's own checkbox, kept in the line out of
sight); turning it on also shows the section again if it was hidden whole.
## Custom Fields
Custom Fields' items are the **board's custom fields** themselves, in their
order (`sort`, the order the card and the minicard draw them in):
| Show | An item's checkbox is the custom field's |
| --- | --- |
| Show on Minicard | **Show on minicard** (`showOnCard`, the legacy name of what the minicard reads) |
| Show on Card | **Add to all cards** (`alwaysOnCard`): the opened card draws the custom fields the CARD carries, and this puts the field on every card of the board |
Unticking Show on Card stops the field being added to cards; a card that
already carries it keeps it until it is taken off that card in its own Custom
Fields hamburger, because a card may carry a field it was given on its own.
- An item's **hamburger** opens the custom field's edit form, the board
sidebar's own.
- Items are **dragged** within Custom Fields only - by the handle with drag
handles on, by the icon and name with them off; Up and Down move one step.
That writes each custom field's `sort`, so the card's and the minicard's
order follow.
- Under the items, also when there are none, **+** creates a custom field
(the board's Create Field form); the new one is the last item.
- The **section's checkbox** is the board's Custom Fields flag of the chosen
side (`allowsCustomFields` / `allowsCustomFieldsOnMinicard`, the row that
was its only item) and, as for a one-row section, ticking it also shows the
section again if it was hidden whole. So there is no "Custom Fields >
Custom Fields" line.
The +, the checkboxes and the hamburgers are a board admin's; anybody else
sees no + and disabled checkboxes.
## Hamburgers
A hamburger is drawn **only when it has something in it**.
| Hamburger | Holds |
| --- | --- |
| A row's | Labels text's way back to the board's default, while the user overrides it. Every other row has none. |
| Card's | **Ask for a reason when moving cards**, and the **Draggable** table. |
| Subtasks' | **Subtask settings**, for a board admin. |
| Any other section's | nothing - so no hamburger. |
What a card does with its own fields - Filter: Subtasks, Edit voting, Card
kind, Edit custom fields, Link fields - is in that card's own section
hamburgers on the opened card, not here.
Removed on 2026-10-28: **On this card** and **Show empty** (a row's
hamburger), **Show empty fields** (Card's), and **Select all / Select none**
(every section's). Empty fields are always shown, and a section has its own
checkbox.
## Drag and drop, collapse
What a section or a row is dragged by follows the member's **drag handles**
setting, as checklists do:
| Drag handles | Dragged by | The rest of the line |
| --- | --- | --- |
| On | the handle only | scrolls the page, as a touch there means to |
| Off | the icon and name (a section: its title) | - |
- A **section** is dragged above or below another, as a checklist is. The
order is the board's (`cardSettingsSectionOrder`), so every member sees the
sections in it; a section added to WeKan later appears in its default place.
- A **row** is dragged within its section, as a checklist item is. That moves
the field on the chosen side: the card's order with Show on Card, the
minicard's with Show on Minicard.
- A row **cannot move to another section**: the sections are unrelated kinds
of fields. Dropped on another section, it goes back where it was, and
nothing is saved.
- The **Up** and **Down** keys on a focused section title or row name move it
one step.
- Only a board admin drags.
- The caret before a section's title **collapses** and expands it, as a
checklist's caret does. Collapsed sections are the user's own, kept per
board.
## How it works
| File | What it is |
| --- | --- |
| `client/components/sidebar/sidebar.jade` | `boardCardSettingsPopup` is `+cardSettingsInline`; `cardSettingsInlineSection`, `cardSettingsSectionPopup`, `cardSettingsItemPopup` |
| `client/components/sidebar/sidebar.js` | The sections (`inlineSectionsOf`, `single`, `customFieldItems`), the rows (`sectionRowsOf`), the handlers (`cardSettingsEvents`, `js-card-settings-section-shown`, `js-card-settings-single-toggle`, the custom field ones), the drags (`reorderOnDrop`, `ownListOnly`) |
| `client/components/cards/cardAddFields.css` | The checklist look |
| `models/lib/cardSettingsSections.js` | The sections, their order, and whether one is shown: `hiddenSectionsOf`, `sectionShown`, `hiddenSectionsAfter`, `rowKeysHiddenBySections`, `isSingleRowSection`, `singleLineChecked` |
| `models/lib/cardSettingsCustomFields.js` | Custom Fields' items: their order, their checkbox per side, their new `sort` after a drop |
| `models/lib/cardShownFields.js` | `boardForCard` / `boardForMinicard`: the board as its cards / minicards see it, the rows of hidden sections reading false |
| `client/components/cards/cardAddFields.js` | `cardBoardView`, `CARD_FIELD_TEMPLATES`: the opened card's templates read that view |
| `client/components/cards/minicard.js` | `MINICARD_FIELD_TEMPLATES` and its helpers read the minicard's view |
| `models/boards.js` | `cardSettingsSectionOrder`, `cardSettingsHiddenOnCard`, `cardSettingsHiddenOnMinicard`, `setCardSettingsSectionOrder`, `setCardSettingsSectionShown` |
| `tests/cardSettingsSectionShown.test.cjs`, `tests/cardSettingsCustomFields.test.cjs`, `tests/cardSettingsOnCard.test.cjs` | The rules, the layout, the handlers |
| `tests/playwright/specs/card-add-fields.e2e.js` | The popup, the checkboxes, the hamburgers, Custom Fields, the drag and collapse |
Card Settings itself reads the board as it is - its checkboxes show each
row's own flag even while its section is hidden; only the opened card and the
minicard read the side's view.
+3 -4
View File
@@ -1,10 +1,9 @@
# Cards and minicards
Create a card in a list, then click its minicard to open its details. The
opened card shows only the fields it has data in, plus its description,
attachments and comments; **Card Settings** under the cover adds the rest,
right on the card ([Card fields](Card-Fields.md),
[Card Settings on the opened card](Card-Settings-On-Card.md)). Board-wide field visibility and order are in
opened card shows every field its board shows on cards, empty or not
([Card fields](Card-Fields.md)). Which fields, and in what order, on the
opened card and on the minicard, is [Card Settings](Card-Settings.md) -
[Board Settings / Card](../Board-Sidebar/Board-Settings/Card.md).
| Place or action | Guide |
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Ureueng nyang geubri buet",
"addmore-detail": "Tamah deskripsi nyang leubeh rinci",
"show-on-card": "Peuleumah bak Kad",
"card-settings-this-card": "Bak kad nyoe",
"card-settings-show-empty": "Peuleumah nyang kosong",
"card-settings-show-empty-fields": "Peuleumah ruang nyang kosong",
"show-on-minicard": "Peudeuh bak Minicard",
"default-on-public-board": "Asai bak papan umum",
"show-on-public-board": "Peuleumah bak papan umum",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Gevolmagtigde",
"addmore-detail": "Voeg 'n meer gedetailleerde beskrywing by",
"show-on-card": "Wys op kaart",
"card-settings-this-card": "Op hierdie kaart",
"card-settings-show-empty": "Wys leë",
"card-settings-show-empty-fields": "Wys leë velde",
"show-on-minicard": "Wys op Minicard",
"default-on-public-board": "Verstek op openbare bord",
"show-on-public-board": "Wys op openbare bord",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Gevolmagtigde",
"addmore-detail": "Voeg 'n meer gedetailleerde beskrywing by",
"show-on-card": "Wys op kaart",
"card-settings-this-card": "Op hierdie kaart",
"card-settings-show-empty": "Wys leë",
"card-settings-show-empty-fields": "Wys leë velde",
"show-on-minicard": "Wys op Minicard",
"default-on-public-board": "Verstek op openbare bord",
"show-on-public-board": "Wys op openbare bord",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Nea wɔde adwuma ama no",
"addmore-detail": "Fa nkyerɛkyerɛmu a emu da hɔ kɛse ka ho",
"show-on-card": "Kyerɛ wɔ Kaad",
"card-settings-this-card": "Wɔ Kaad yi so",
"card-settings-show-empty": "Kyerɛ deɛ hwee nni mu",
"card-settings-show-empty-fields": "Kyerɛ afã a hwee nni mu",
"show-on-minicard": "Kyerɛ wɔ Minikaad",
"default-on-public-board": "Nea wɔahyɛ dedaw wɔ baguam bɔɔd so",
"show-on-public-board": "Kyerɛ wɔ baguam bɔɔd so",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "ኃላፊ",
"addmore-detail": "ይበልጥ ዝርዝር መግለጫ ጨምር",
"show-on-card": "በካርድ ላይ አሳይ",
"card-settings-this-card": "በዚህ ካርድ ላይ",
"card-settings-show-empty": "ባዶዎችን አሳይ",
"card-settings-show-empty-fields": "ባዶ መስኮችን አሳይ",
"show-on-minicard": "በትንሽ ካርድ ላይ አሳይ",
"default-on-public-board": "በይፋዊ ሰሌዳ ላይ ነባሪ",
"show-on-public-board": "በይፋዊ ሰሌዳ ላይ አሳይ",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Asignau",
"addmore-detail": "Adhibir una descripción detallada",
"show-on-card": "Mostrar en la tarcheta",
"card-settings-this-card": "En esta tarcheta",
"card-settings-show-empty": "Amostrar vuedos",
"card-settings-show-empty-fields": "Amostrar campos vuedos",
"show-on-minicard": "Amostrar en a minitarcheta",
"default-on-public-board": "Predeterminau en tablero publico",
"show-on-public-board": "Amostrar en tablero publico",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "المكلّف",
"addmore-detail": "إضافة وصف أكثر تفصيلًا",
"show-on-card": "عرض على البطاقة",
"card-settings-this-card": "على هذه البطاقة",
"card-settings-show-empty": "عرض الفارغة",
"card-settings-show-empty-fields": "عرض الحقول الفارغة",
"show-on-minicard": "عرض على البطاقة المصغرة",
"default-on-public-board": "افتراضي على اللوحة العامة",
"show-on-public-board": "إظهار على اللوحة العامة",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "المكلّف",
"addmore-detail": "إضافة وصف أكثر تفصيلًا",
"show-on-card": "عرض على البطاقة",
"card-settings-this-card": "على هذه البطاقة",
"card-settings-show-empty": "عرض الفارغة",
"card-settings-show-empty-fields": "عرض الحقول الفارغة",
"show-on-minicard": "عرض على البطاقة المصغرة",
"default-on-public-board": "افتراضي على اللوحة العامة",
"show-on-public-board": "إظهار على اللوحة العامة",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "المكلّف",
"addmore-detail": "إضافة وصف أكثر تفصيلًا",
"show-on-card": "عرض على البطاقة",
"card-settings-this-card": "على هذه البطاقة",
"card-settings-show-empty": "عرض الفارغة",
"card-settings-show-empty-fields": "عرض الحقول الفارغة",
"show-on-minicard": "عرض على البطاقة المصغرة",
"default-on-public-board": "افتراضي على اللوحة العامة",
"show-on-public-board": "إظهار على اللوحة العامة",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "محول‌شده",
"addmore-detail": "افزودن توضیحات کامل تر",
"show-on-card": "عرض على البطاقة",
"card-settings-this-card": "على هاد البطاقة",
"card-settings-show-empty": "عرض الخاويين",
"card-settings-show-empty-fields": "عرض الخانات الخاوية",
"show-on-minicard": "عرض على البطاقة المصغرة",
"default-on-public-board": "ديفو فاللوحة العامة",
"show-on-public-board": "بيّن فاللوحة العامة",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "দায়িত্বপ্ৰাপ্ত",
"addmore-detail": "অধিক বিশদ বিৱৰণ যোগ কৰক",
"show-on-card": "কাৰ্ডত দেখুৱাওক",
"card-settings-this-card": "এই কাৰ্ডত",
"card-settings-show-empty": "খালী দেখুৱাওক",
"card-settings-show-empty-fields": "খালী ক্ষেত্ৰ দেখুৱাওক",
"show-on-minicard": "মিনিকাৰ্ডত দেখুৱাওক",
"default-on-public-board": "ৰাজহুৱা ব’ৰ্ডত অবিকল্পিত",
"show-on-public-board": "ৰাজহুৱা ব’ৰ্ডত দেখুৱাওক",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Asignado",
"addmore-detail": "Añadir una descripción más detallada",
"show-on-card": "Mostrar en la tarjeta",
"card-settings-this-card": "Nesta tarxeta",
"card-settings-show-empty": "Amosar baleros",
"card-settings-show-empty-fields": "Amosar campos baleros",
"show-on-minicard": "Mostra a la Minicard",
"default-on-public-board": "Predetermináu en tableru públicu",
"show-on-public-board": "Amosar en tableru públicu",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Lurañataki churata",
"addmore-detail": "yapxataña a jukʼampi detailed qhanañchäwi",
"show-on-card": "uñachtʼayaña patana tarjeta",
"card-settings-this-card": "Aka tarjeta patana",
"card-settings-show-empty": "Chʼusanaka uñachtʼayaña",
"card-settings-show-empty-fields": "Chʼusa chiqanaka uñachtʼayaña",
"show-on-minicard": "uñachtʼayaña patana Minicard",
"default-on-public-board": "Taqi jaqinkiri pizarranxa nayrïri",
"show-on-public-board": "Taqi jaqinkiri pizarranxa uñachayaña",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Təyin edilmiş şəxs",
"addmore-detail": "Daha ətraflı təsvir əlavə edin",
"show-on-card": "Kartda göstərin",
"card-settings-this-card": "Bu kartda",
"card-settings-show-empty": "Boşları göstərin",
"card-settings-show-empty-fields": "Boş sahələri göstərin",
"show-on-minicard": "Minikartda göstərin",
"default-on-public-board": "İctimai lövhədə standart",
"show-on-public-board": "İctimai lövhədə göstər",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Təyin edilmiş şəxs",
"addmore-detail": "Daha ətraflı təsvir əlavə edin",
"show-on-card": "Kartda göstərin",
"card-settings-this-card": "Bu kartda",
"card-settings-show-empty": "Boşları göstərin",
"card-settings-show-empty-fields": "Boş sahələri göstərin",
"show-on-minicard": "Minikartda göstərin",
"default-on-public-board": "İctimai lövhədə standart",
"show-on-public-board": "İctimai lövhədə göstər",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Təyin edilmiş şəxs",
"addmore-detail": "Daha ətraflı təsvir əlavə edin",
"show-on-card": "Kartda göstərin",
"card-settings-this-card": "Bu kartda",
"card-settings-show-empty": "Boşları göstərin",
"card-settings-show-empty-fields": "Boş sahələri göstərin",
"show-on-minicard": "Minikartda göstərin",
"default-on-public-board": "İctimai lövhədə standart",
"show-on-public-board": "İctimai lövhədə göstər",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Яуаплы",
"addmore-detail": "Ентеклерәк тасуирлама өҫтәргә",
"show-on-card": "Карточкала күрһәтергә",
"card-settings-this-card": "Был карточкала",
"card-settings-show-empty": "Буштарын күрһәтергә",
"card-settings-show-empty-fields": "Буш яландарҙы күрһәтергә",
"show-on-minicard": "Мини-карточкала күрһәтергә",
"default-on-public-board": "Асыҡ таҡтала ғәҙәттәгесә",
"show-on-public-board": "Асыҡ таҡтала күрһәтергә",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Прызначаны",
"addmore-detail": "Дадаць больш падрабязнае апісанне",
"show-on-card": "Паказваць на картцы",
"card-settings-this-card": "На гэтай картцы",
"card-settings-show-empty": "Паказваць пустыя",
"card-settings-show-empty-fields": "Паказваць пустыя палі",
"show-on-minicard": "Паказваць на мінікартцы",
"default-on-public-board": "Прадвызначана на публічнай дошцы",
"show-on-public-board": "Паказваць на публічнай дошцы",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Изпълнител",
"addmore-detail": "Добавяне на по-подробно описание",
"show-on-card": "Показване на картата",
"card-settings-this-card": "На тази карта",
"card-settings-show-empty": "Показване на празните",
"card-settings-show-empty-fields": "Показване на празните полета",
"show-on-minicard": "Показване на миникартата",
"default-on-public-board": "По подразбиране на публична дъска",
"show-on-public-board": "Показване на публична дъска",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "जिम्मेदार",
"addmore-detail": "अउरी विस्तार वाला विवरण जोड़ीं",
"show-on-card": "कार्ड पर देखाईं",
"card-settings-this-card": "एह कार्ड पर",
"card-settings-show-empty": "खाली देखाईं",
"card-settings-show-empty-fields": "खाली फील्ड देखाईं",
"show-on-minicard": "छोट कार्ड पर देखाईं",
"default-on-public-board": "सार्वजनिक बोर्ड पर डिफ़ॉल्ट",
"show-on-public-board": "सार्वजनिक बोर्ड पर देखाईं",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Man we i gat wok",
"addmore-detail": "Adem wan diskripsen we i gat moa ditel",
"show-on-card": "Soemaot long Kad",
"card-settings-this-card": "Long Kad ia",
"card-settings-show-empty": "Soemaot ol emti",
"card-settings-show-empty-fields": "Soemaot ol emti filed",
"show-on-minicard": "Soemaot long Smol Kad",
"default-on-public-board": "Difol long pablik bod",
"show-on-public-board": "Soemaot long pablik bod",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Baarakɛla",
"addmore-detail": "Ɲɛfɔli dafalen fara a kan",
"show-on-card": "A jira karata kan",
"card-settings-this-card": "Nin karata kan",
"card-settings-show-empty": "A jira lankolonw",
"card-settings-show-empty-fields": "A jira yɔrɔ lankolonw",
"show-on-minicard": "A jira minikarata kan",
"default-on-public-board": "Dabali ka tabulo bɛɛ ta la",
"show-on-public-board": "A jira tabulo bɛɛ ta la",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "দায়িত্বপ্রাপ্ত",
"addmore-detail": "আরও বিস্তারিত বিবরণ যোগ করুন",
"show-on-card": "কার্ডে দেখান",
"card-settings-this-card": "এই কার্ডে",
"card-settings-show-empty": "খালি দেখান",
"card-settings-show-empty-fields": "খালি ক্ষেত্রগুলি দেখান",
"show-on-minicard": "মিনিকার্ডে দেখান",
"default-on-public-board": "সর্বজনীন বোর্ডে ডিফল্ট",
"show-on-public-board": "সর্বজনীন বোর্ডে দেখান",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "འགན་འཁུར་བ།",
"addmore-detail": "ཞིབ་ཕྲའི་འགྲེལ་བཤད་ཁ་སྣོན།",
"show-on-card": "བྱང་བུའི་སྟེང་སྟོན།",
"card-settings-this-card": "བྱང་བུ་འདིའི་སྟེང་།",
"card-settings-show-empty": "སྟོང་པ་སྟོན།",
"card-settings-show-empty-fields": "ས་སྒོ་སྟོང་པ་སྟོན།",
"show-on-minicard": "བྱང་བུ་ཆུང་ངུའི་སྟེང་སྟོན།",
"default-on-public-board": "སྤྱི་པའི་པང་ལེབ་སྟེང་སྔོན་སྒྲིག",
"show-on-public-board": "སྤྱི་པའི་པང་ལེབ་སྟེང་སྟོན།",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Personne assignée",
"addmore-detail": "Ouzhpennañ un deskrivadur munutoc’h",
"show-on-card": "Diskwel war ar gartenn",
"card-settings-this-card": "War ar gartenn-mañ",
"card-settings-show-empty": "Diskwel ar re c'houllo",
"card-settings-show-empty-fields": "Diskwel ar maeziennoù goullo",
"show-on-minicard": "Diskouez war ar gartennig",
"default-on-public-board": "Dre ziouer war an daolenn foran",
"show-on-public-board": "Diskouez war an daolenn foran",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Zaduženi",
"addmore-detail": "Dodaj detaljniji opis",
"show-on-card": "Prikaži na kartici",
"card-settings-this-card": "Na ovoj kartici",
"card-settings-show-empty": "Prikaži prazna",
"card-settings-show-empty-fields": "Prikaži prazna polja",
"show-on-minicard": "Prikaži na mini kartici",
"default-on-public-board": "Zadano na javnoj tabli",
"show-on-public-board": "Prikaži na javnoj tabli",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Харюусалгата",
"addmore-detail": "Үлүү дэлгэрэнгы тайлбари нэмэхэ",
"show-on-card": "Картада харуулха",
"card-settings-this-card": "Энэ картада",
"card-settings-show-empty": "Хооһониие харуулха",
"card-settings-show-empty-fields": "Хооһон талбаринуудые харуулха",
"show-on-minicard": "Бишыхан картада харуулха",
"default-on-public-board": "Нээлттэ самбар дээрэ анханай",
"show-on-public-board": "Нээлттэ самбар дээрэ харуулха",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Assignat",
"addmore-detail": "Afegiu una descripció més detallada",
"show-on-card": "Mostra a la fitxa",
"card-settings-this-card": "En aquesta fitxa",
"card-settings-show-empty": "Mostra els buits",
"card-settings-show-empty-fields": "Mostra els camps buits",
"show-on-minicard": "Mostra a la Minicard",
"default-on-public-board": "Per defecte al tauler públic",
"show-on-public-board": "Mostra al tauler públic",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Assignat",
"addmore-detail": "Afegiu una descripció més detallada",
"show-on-card": "Mostra a la fitxa",
"card-settings-this-card": "En esta fitxa",
"card-settings-show-empty": "Mostra els buits",
"card-settings-show-empty-fields": "Mostra els camps buits",
"show-on-minicard": "Mostra a la Minicard",
"default-on-public-board": "Per defecte al tauler públic",
"show-on-public-board": "Mostra al tauler públic",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Assignat",
"addmore-detail": "Afegiu una descripció més detallada",
"show-on-card": "Mostra a la fitxa",
"card-settings-this-card": "En aquesta fitxa",
"card-settings-show-empty": "Mostra els buits",
"card-settings-show-empty-fields": "Mostra els camps buits",
"show-on-minicard": "Mostra a la Minicard",
"default-on-public-board": "Per defecte al tauler públic",
"show-on-public-board": "Mostra al tauler públic",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "ᎠᏥᏁᏤᎸ",
"addmore-detail": "ᎤᏟ ᎦᏅᏖᏗ ᎧᏃᎮᏓ ᎧᏁᏉᏗ",
"show-on-card": "ᎪᏪᎵ ᎤᏍᏗ ᎠᏂ ᎠᏄᎪᏫᏍᏗ",
"card-settings-this-card": "ᎯᎠ ᎪᏪᎵ ᎤᏍᏗ ᎠᏂ",
"card-settings-show-empty": "ᎤᏰᎸᏒ ᎠᏄᎪᏫᏍᏗ",
"card-settings-show-empty-fields": "ᎤᏰᎸᏒ ᏗᏟᎶᏍᏗ ᎠᏄᎪᏫᏍᏗ",
"show-on-minicard": "ᎪᏪᎵ ᎤᏍᏗ ᎦᏴᎵ ᎠᏄᎪᏫᏍᏗ",
"default-on-public-board": "ᏂᎦᏓ ᎤᎾᏙᏢᏒ ᎠᏂᏙᏢᏗ ᎾᎥ ᎢᏳᎵᏍᏙᏗ",
"show-on-public-board": "ᏂᎦᏓ ᎤᎾᏙᏢᏒ ᎠᏂᏙᏢᏗ ᎾᎥ ᎬᏂᎨᏒ",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "بەرپرس",
"addmore-detail": "وەسفێکی وردتر زیاد بکە",
"show-on-card": "لە کارت پیشان بدە",
"card-settings-this-card": "لەم کارتە",
"card-settings-show-empty": "بەتاڵەکان پیشان بدە",
"card-settings-show-empty-fields": "خانە بەتاڵەکان پیشان بدە",
"show-on-minicard": "لە کارتی بچووک پیشان بدە",
"default-on-public-board": "بنەڕەت لەسەر تەختەی گشتی",
"show-on-public-board": "پیشاندان لەسەر تەختەی گشتی",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "受让人",
"addmore-detail": "添加更详细的描述",
"show-on-card": "显示在卡上",
"card-settings-this-card": "在此卡上",
"card-settings-show-empty": "显示空项",
"card-settings-show-empty-fields": "显示空字段",
"show-on-minicard": "显示在迷你卡上",
"default-on-public-board": "公开看板的默认视图",
"show-on-public-board": "在公开看板上显示",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Assignatu",
"addmore-detail": "Aghjunghje una descrizzione più dettagliata",
"show-on-card": "Mustrà nantu à a carta",
"card-settings-this-card": "Nantu à sta carta",
"card-settings-show-empty": "Mustrà i vioti",
"card-settings-show-empty-fields": "Mustrà i campi vioti",
"show-on-minicard": "Mustrà nant’à a minicarta",
"default-on-public-board": "Predefinitu nantu à u tavulone publicu",
"show-on-public-board": "Affissà nantu à u tavulone publicu",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Řešitel",
"addmore-detail": "Přidat detailnější popis",
"show-on-card": "Zobrazit na kartě",
"card-settings-this-card": "Na této kartě",
"card-settings-show-empty": "Zobrazit prázdné",
"card-settings-show-empty-fields": "Zobrazit prázdná pole",
"show-on-minicard": "Zobrazit na minikartě",
"default-on-public-board": "Výchozí na veřejné tabuli",
"show-on-public-board": "Zobrazit na veřejné tabuli",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Řešitel",
"addmore-detail": "Přidat detailnější popis",
"show-on-card": "Zobrazit na kartě",
"card-settings-this-card": "Na této kartě",
"card-settings-show-empty": "Zobrazit prázdné",
"card-settings-show-empty-fields": "Zobrazit prázdná pole",
"show-on-minicard": "Zobrazit na minikartě",
"default-on-public-board": "Výchozí na veřejné tabuli",
"show-on-public-board": "Zobrazit na veřejné tabuli",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Òdpòwiedzalny",
"addmore-detail": "Dodôj bardziej szczegòłowi òpisënk",
"show-on-card": "Pòkôżë na kôrce",
"card-settings-this-card": "Na ti kôrce",
"card-settings-show-empty": "Pòkôżë pùsté",
"card-settings-show-empty-fields": "Pòkôżë pùsté pòla",
"show-on-minicard": "Wyświetl na miniaturze kôrtë",
"default-on-public-board": "Domëslno na pùbliczny tôflë",
"show-on-public-board": "Pòkôżë na pùbliczny tôflë",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Яваплӑ",
"addmore-detail": "Туллин ӑнлантару хушас",
"show-on-card": "Карточка ҫинче кӑтартас",
"card-settings-this-card": "Ҫак карточка ҫинче",
"card-settings-show-empty": "Пушӑсене кӑтартас",
"card-settings-show-empty-fields": "Пушӑ уйсене кӑтартас",
"show-on-minicard": "Кӗске карточка ҫинче кӑтартас",
"default-on-public-board": "Уҫӑ хӑма ҫинче тӗп",
"show-on-public-board": "Уҫӑ хӑма ҫинче кӑтарт",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Aseinai",
"addmore-detail": "Ychwanegu disgrifiad manylach",
"show-on-card": "Dangos ar Gerdyn",
"card-settings-this-card": "Ar y Cerdyn hwn",
"card-settings-show-empty": "Dangos rhai gwag",
"card-settings-show-empty-fields": "Dangos meysydd gwag",
"show-on-minicard": "Dangoswch ar Gerdyn Mini",
"default-on-public-board": "Rhagosodiad ar fwrdd cyhoeddus",
"show-on-public-board": "Dangos ar fwrdd cyhoeddus",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Aseinai",
"addmore-detail": "Ychwanegu disgrifiad manylach",
"show-on-card": "Dangos ar Gerdyn",
"card-settings-this-card": "Ar y Cerdyn hwn",
"card-settings-show-empty": "Dangos rhai gwag",
"card-settings-show-empty-fields": "Dangos meysydd gwag",
"show-on-minicard": "Dangoswch ar Gerdyn Mini",
"default-on-public-board": "Rhagosodiad ar fwrdd cyhoeddus",
"show-on-public-board": "Dangos ar fwrdd cyhoeddus",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Tildelt til",
"addmore-detail": "Tilføj en mere detaljeret beskrivelse",
"show-on-card": "Vis på kort",
"card-settings-this-card": "På dette kort",
"card-settings-show-empty": "Vis tomme",
"card-settings-show-empty-fields": "Vis tomme felter",
"show-on-minicard": "Vis på minikort",
"default-on-public-board": "Standard på offentlig tavle",
"show-on-public-board": "Vis på offentlig tavle",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Zugewiesen",
"addmore-detail": "Eine detailliertere Beschreibung hinzufügen",
"show-on-card": "Zeige auf Karte",
"card-settings-this-card": "Auf dieser Karte",
"card-settings-show-empty": "Zeige leere",
"card-settings-show-empty-fields": "Zeige leere Felder",
"show-on-minicard": "Zeige auf Minikarte",
"default-on-public-board": "Standard auf öffentlicher Arbeitstafel",
"show-on-public-board": "Zeige auf öffentlicher Arbeitstafel",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Zugewiesen",
"addmore-detail": "Eine detailliertere Beschreibung hinzufügen",
"show-on-card": "Zeige auf Karte",
"card-settings-this-card": "Auf dieser Karte",
"card-settings-show-empty": "Zeige leere",
"card-settings-show-empty-fields": "Zeige leere Felder",
"show-on-minicard": "Anzeigen auf Minikarte",
"default-on-public-board": "Standard auf öffentlicher Arbeitstafel",
"show-on-public-board": "Zeige auf öffentlicher Arbeitstafel",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Zugewiesen",
"addmore-detail": "Eine detailliertere Beschreibung hinzufügen",
"show-on-card": "Zeige auf Karte",
"card-settings-this-card": "Auf dieser Karte",
"card-settings-show-empty": "Zeige leere",
"card-settings-show-empty-fields": "Zeige leere Felder",
"show-on-minicard": "Zeige auf Minikarte",
"default-on-public-board": "Standard auf öffentlicher Arbeitstafel",
"show-on-public-board": "Zeige auf öffentlicher Arbeitstafel",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Zugewiesen",
"addmore-detail": "Eine detailliertere Beschreibung hinzufügen",
"show-on-card": "Zeige auf Karte",
"card-settings-this-card": "Auf dieser Karte",
"card-settings-show-empty": "Zeige leere",
"card-settings-show-empty-fields": "Zeige leere Felder",
"show-on-minicard": "Zeige auf Minikarte",
"default-on-public-board": "Standard auf öffentlicher Arbeitstafel",
"show-on-public-board": "Zeige auf öffentlicher Arbeitstafel",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "འགན་འབག་མི།",
"addmore-detail": "ཞིབ་ཕྲ་བའི་འགྲེལ་བཤད་ཁ་སྣོན།",
"show-on-card": "ཤོག་བྱང་ཐོག་སྟོན།",
"card-settings-this-card": "ཤོག་བྱང་འདི་གི་ཐོག་ལུ།",
"card-settings-show-empty": "སྟོངམ་སྟོན།",
"card-settings-show-empty-fields": "ས་སྒོ་སྟོངམ་སྟོན།",
"show-on-minicard": "ཤོག་བྱང་ཆུང་བར་སྟོན།",
"default-on-public-board": "མི་མང་པང་ལེབ་གུ་སྔོན་སྒྲིག",
"show-on-public-board": "མི་མང་པང་ལེབ་གུ་སྟོན།",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Ame si wotsɔ dɔ na",
"addmore-detail": "Tsɔ numeɖeɖe le nyatakaka geɖe me kpe ɖe eŋu",
"show-on-card": "Fia le kaɖi dzi",
"card-settings-this-card": "Le kaɖi sia dzi",
"card-settings-show-empty": "Fia nusiwo me naneke mele o",
"card-settings-show-empty-fields": "Fia teƒe siwo me naneke mele o",
"show-on-minicard": "Fia le kaɖivi dzi",
"default-on-public-board": "Ɖoɖo le dutoƒo ʋuɖoɖo dzi",
"show-on-public-board": "Fia le dutoƒo ʋuɖoɖo dzi",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Υπεύθυνος",
"addmore-detail": "Προσθέστε πιο αναλυτική περιγραφή",
"show-on-card": "Εμφάνιση στην κάρτα",
"card-settings-this-card": "Σε αυτή την κάρτα",
"card-settings-show-empty": "Εμφάνιση κενών",
"card-settings-show-empty-fields": "Εμφάνιση κενών πεδίων",
"show-on-minicard": "Εμφάνιση στη μίνι κάρτα",
"default-on-public-board": "Προεπιλογή σε δημόσιο πίνακα",
"show-on-public-board": "Εμφάνιση σε δημόσιο πίνακα",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Υπεύθυνος",
"addmore-detail": "Προσθέστε πιο αναλυτική περιγραφή",
"show-on-card": "Εμφάνιση στην κάρτα",
"card-settings-this-card": "Σε αυτή την κάρτα",
"card-settings-show-empty": "Εμφάνιση κενών",
"card-settings-show-empty-fields": "Εμφάνιση κενών πεδίων",
"show-on-minicard": "Εμφάνιση στη μίνι κάρτα",
"default-on-public-board": "Προεπιλογή σε δημόσιο πίνακα",
"show-on-public-board": "Εμφάνιση σε δημόσιο πίνακα",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Assignee",
"addmore-detail": "Add a more detailed description",
"show-on-card": "Show on Card",
"card-settings-this-card": "On this card",
"card-settings-show-empty": "Show empty",
"card-settings-show-empty-fields": "Show empty fields",
"show-on-minicard": "Show on Minicard",
"default-on-public-board": "Default on Public Board",
"show-on-public-board": "Show on Public Board",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Assignee",
"addmore-detail": "Add a more detailed description",
"show-on-card": "Show on Card",
"card-settings-this-card": "On this card",
"card-settings-show-empty": "Show empty",
"card-settings-show-empty-fields": "Show empty fields",
"show-on-minicard": "Show on Minicard",
"default-on-public-board": "Default on Public Board",
"show-on-public-board": "Show on Public Board",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Assignee",
"addmore-detail": "Add a more detailed description",
"show-on-card": "Show on Card",
"card-settings-this-card": "On this card",
"card-settings-show-empty": "Show empty",
"card-settings-show-empty-fields": "Show empty fields",
"show-on-minicard": "Show on Minicard",
"default-on-public-board": "Default on Public Board",
"show-on-public-board": "Show on Public Board",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Assignee",
"addmore-detail": "Add a more detailed description",
"show-on-card": "Show on Card",
"card-settings-this-card": "On this card",
"card-settings-show-empty": "Show empty",
"card-settings-show-empty-fields": "Show empty fields",
"show-on-minicard": "Show on Minicard",
"default-on-public-board": "Default on Public Board",
"show-on-public-board": "Show on Public Board",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Assignee",
"addmore-detail": "Add a more detailed description",
"show-on-card": "Show on Card",
"card-settings-this-card": "On this card",
"card-settings-show-empty": "Show empty",
"card-settings-show-empty-fields": "Show empty fields",
"show-on-minicard": "Show on Minicard",
"default-on-public-board": "Default on Public Board",
"show-on-public-board": "Show on Public Board",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Assignee",
"addmore-detail": "Add a more detailed description",
"show-on-card": "Show on Card",
"card-settings-this-card": "On this card",
"card-settings-show-empty": "Show empty",
"card-settings-show-empty-fields": "Show empty fields",
"show-on-minicard": "Show on Minicard",
"default-on-public-board": "Default on Public Board",
"show-on-public-board": "Show on Public Board",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Assignee",
"addmore-detail": "Add a more detailed description",
"show-on-card": "Show on Card",
"card-settings-this-card": "On this card",
"card-settings-show-empty": "Show empty",
"card-settings-show-empty-fields": "Show empty fields",
"show-on-minicard": "Show on Minicard",
"default-on-public-board": "Default on Public Board",
"show-on-public-board": "Show on Public Board",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Assignee",
"addmore-detail": "Add a more detailed description",
"show-on-card": "Show on Card",
"card-settings-this-card": "On this card",
"card-settings-show-empty": "Show empty",
"card-settings-show-empty-fields": "Show empty fields",
"show-on-minicard": "Show on Minicard",
"default-on-public-board": "Default on Public Board",
"show-on-public-board": "Show on Public Board",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Assignee",
"addmore-detail": "Add a more detailed description",
"show-on-card": "Show on Card",
"card-settings-this-card": "On this card",
"card-settings-show-empty": "Show empty",
"card-settings-show-empty-fields": "Show empty fields",
"show-on-minicard": "Show on Minicard",
"default-on-public-board": "Default on Public Board",
"show-on-public-board": "Show on Public Board",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Assignee",
"addmore-detail": "Add a more detailed description",
"show-on-card": "Show on Card",
"card-settings-this-card": "On this card",
"card-settings-show-empty": "Show empty",
"card-settings-show-empty-fields": "Show empty fields",
"show-on-minicard": "Show on Minicard",
"default-on-public-board": "Default on Public Board",
"show-on-public-board": "Show on Public Board",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Assignee",
"addmore-detail": "Add a more detailed description",
"show-on-card": "Show on Card",
"card-settings-this-card": "On this card",
"card-settings-show-empty": "Show empty",
"card-settings-show-empty-fields": "Show empty fields",
"show-on-minicard": "Show on Minicard",
"default-on-public-board": "Default on Public Board",
"show-on-public-board": "Show on Public Board",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Assignee",
"addmore-detail": "Add a more detailed description",
"show-on-card": "Show on Card",
"card-settings-this-card": "On this card",
"card-settings-show-empty": "Show empty",
"card-settings-show-empty-fields": "Show empty fields",
"show-on-minicard": "Show on Minicard",
"default-on-public-board": "Default on Public Board",
"show-on-public-board": "Show on Public Board",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Asignito",
"addmore-detail": "Aldoni pli detalan priskribon",
"show-on-card": "Montri sur karto",
"card-settings-this-card": "Sur ĉi tiu karto",
"card-settings-show-empty": "Montri malplenajn",
"card-settings-show-empty-fields": "Montri malplenajn kampojn",
"show-on-minicard": "Montri sur minikarto",
"default-on-public-board": "Defaŭlta sur publika tabulo",
"show-on-public-board": "Montri sur publika tabulo",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Asignado",
"addmore-detail": "Añadir una descripción detallada",
"show-on-card": "Mostrar en la tarjeta",
"card-settings-this-card": "En esta tarjeta",
"card-settings-show-empty": "Mostrar vacíos",
"card-settings-show-empty-fields": "Mostrar campos vacíos",
"show-on-minicard": "Mostrar en la minitarjeta",
"default-on-public-board": "Predeterminado en tablero público",
"show-on-public-board": "Mostrar en tablero público",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Asignado",
"addmore-detail": "Añadir una descripción detallada",
"show-on-card": "Mostrar en la tarjeta",
"card-settings-this-card": "En esta tarjeta",
"card-settings-show-empty": "Mostrar vacíos",
"card-settings-show-empty-fields": "Mostrar campos vacíos",
"show-on-minicard": "Mostrar en la minitarjeta",
"default-on-public-board": "Predeterminado en tablero público",
"show-on-public-board": "Mostrar en tablero público",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Asignado",
"addmore-detail": "Añadir una descripción detallada",
"show-on-card": "Mostrar en la tarjeta",
"card-settings-this-card": "En esta tarjeta",
"card-settings-show-empty": "Mostrar vacíos",
"card-settings-show-empty-fields": "Mostrar campos vacíos",
"show-on-minicard": "Mostrar en la minitarjeta",
"default-on-public-board": "Predeterminado en tablero público",
"show-on-public-board": "Mostrar en tablero público",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Asignado",
"addmore-detail": "Añadir una descripción detallada",
"show-on-card": "Mostrar en la tarjeta",
"card-settings-this-card": "En esta tarjeta",
"card-settings-show-empty": "Mostrar vacíos",
"card-settings-show-empty-fields": "Mostrar campos vacíos",
"show-on-minicard": "Mostrar en la minitarjeta",
"default-on-public-board": "Predeterminado en tablero público",
"show-on-public-board": "Mostrar en tablero público",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Asignado",
"addmore-detail": "Añadir una descripción detallada",
"show-on-card": "Mostrar en la tarjeta",
"card-settings-this-card": "En esta tarjeta",
"card-settings-show-empty": "Mostrar vacíos",
"card-settings-show-empty-fields": "Mostrar campos vacíos",
"show-on-minicard": "Mostrar en la minitarjeta",
"default-on-public-board": "Predeterminado en tablero público",
"show-on-public-board": "Mostrar en tablero público",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Asignado",
"addmore-detail": "Agregar una descripción detallada",
"show-on-card": "Mostrar en la tarjeta",
"card-settings-this-card": "En esta tarjeta",
"card-settings-show-empty": "Mostrar vacíos",
"card-settings-show-empty-fields": "Mostrar campos vacíos",
"show-on-minicard": "Mostrar en la minitarjeta",
"default-on-public-board": "Predeterminado en tablero público",
"show-on-public-board": "Mostrar en tablero público",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Asignado",
"addmore-detail": "Añadir una descripción detallada",
"show-on-card": "Mostrar en la tarjeta",
"card-settings-this-card": "En esta tarjeta",
"card-settings-show-empty": "Mostrar vacíos",
"card-settings-show-empty-fields": "Mostrar campos vacíos",
"show-on-minicard": "Mostrar en la minitarjeta",
"default-on-public-board": "Predeterminado en tablero público",
"show-on-public-board": "Mostrar en tablero público",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Asignado",
"addmore-detail": "Añadir una descripción detallada",
"show-on-card": "Mostrar en la tarjeta",
"card-settings-this-card": "En esta tarjeta",
"card-settings-show-empty": "Mostrar vacíos",
"card-settings-show-empty-fields": "Mostrar campos vacíos",
"show-on-minicard": "Mostrar en la minitarjeta",
"default-on-public-board": "Predeterminado en tablero público",
"show-on-public-board": "Mostrar en tablero público",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Asignado",
"addmore-detail": "Añadir una descripción detallada",
"show-on-card": "Mostrar en la tarjeta",
"card-settings-this-card": "En esta tarjeta",
"card-settings-show-empty": "Mostrar vacíos",
"card-settings-show-empty-fields": "Mostrar campos vacíos",
"show-on-minicard": "Mostrar en la minitarjeta",
"default-on-public-board": "Predeterminado en tablero público",
"show-on-public-board": "Mostrar en tablero público",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Vastuvõtja",
"addmore-detail": "Lisage üksikasjalikum kirjeldus",
"show-on-card": "Näita kaardil",
"card-settings-this-card": "Sellel kaardil",
"card-settings-show-empty": "Näita tühje",
"card-settings-show-empty-fields": "Näita tühje välju",
"show-on-minicard": "Näita minikaardil",
"default-on-public-board": "Vaikimisi avalikul tahvlil",
"show-on-public-board": "Näita avalikul tahvlil",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Esleitua",
"addmore-detail": "Gehitu deskripzio zehatzagoa",
"show-on-card": "Erakutsi txartelan",
"card-settings-this-card": "Txartel honetan",
"card-settings-show-empty": "Erakutsi hutsak",
"card-settings-show-empty-fields": "Erakutsi eremu hutsak",
"show-on-minicard": "Erakutsi minitxartelean",
"default-on-public-board": "Lehenetsia taula publikoan",
"show-on-public-board": "Erakutsi taula publikoan",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "محول‌شده",
"addmore-detail": "افزودن توضیحات کامل تر",
"show-on-card": "نمایش در کارت",
"card-settings-this-card": "در این کارت",
"card-settings-show-empty": "نمایش خالی‌ها",
"card-settings-show-empty-fields": "نمایش فیلدهای خالی",
"show-on-minicard": "نمایش روی کارت کوچک",
"default-on-public-board": "پیش‌فرض در برد عمومی",
"show-on-public-board": "نمایش در برد عمومی",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "محول‌شده",
"addmore-detail": "افزودن توضیحات کامل تر",
"show-on-card": "نمایش در کارت",
"card-settings-this-card": "در این کارت",
"card-settings-show-empty": "نمایش خالی‌ها",
"card-settings-show-empty-fields": "نمایش فیلدهای خالی",
"show-on-minicard": "نمایش روی کارت کوچک",
"default-on-public-board": "پیش‌فرض در برد عمومی",
"show-on-public-board": "نمایش در برد عمومی",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Halfinaaɗo",
"addmore-detail": "ƈeydu cifagol ɓurɗol carɗude",
"show-on-card": "Hollu e kartal",
"card-settings-this-card": "E ndee kartal",
"card-settings-show-empty": "Hollu ko woni meho",
"card-settings-show-empty-fields": "Hollu nokkuuji meho",
"show-on-minicard": "Hollu e kartal pamarel",
"default-on-public-board": "Fuɗɗorde e tabal kuuɓal",
"show-on-public-board": "Hollu e tabal kuuɓal",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Käsittelijä",
"addmore-detail": "Lisää tarkempi kuvaus",
"show-on-card": "Näytä kortilla",
"card-settings-this-card": "Tällä kortilla",
"card-settings-show-empty": "Näytä tyhjät",
"card-settings-show-empty-fields": "Näytä tyhjät kentät",
"show-on-minicard": "Näytä minikortilla",
"default-on-public-board": "Oletus julkisella taululla",
"show-on-public-board": "Näytä julkisella taululla",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "E lesi kina",
"addmore-detail": "Kuria e dua na ivakamacala matailalai cake",
"show-on-card": "Vakaraitaka ena Kadi",
"card-settings-this-card": "Ena Kadi oqo",
"card-settings-show-empty": "Vakaraitaka na lala",
"card-settings-show-empty-fields": "Vakaraitaka na vanua lala",
"show-on-minicard": "Vakaraitaka ena Kadi Lailai",
"default-on-public-board": "Vakarautaki ena papa raraba",
"show-on-public-board": "Vakaraitaka ena papa raraba",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Ábyrgdari",
"addmore-detail": "Legg eina nágreiniligari lýsing afturat",
"show-on-card": "Vís á korti",
"card-settings-this-card": "Á hesum korti",
"card-settings-show-empty": "Vís tóm",
"card-settings-show-empty-fields": "Vís tóm teigar",
"show-on-minicard": "Vís á smákorti",
"default-on-public-board": "Standard á almennari talvu",
"show-on-public-board": "Vís á almennari talvu",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Intervenant",
"addmore-detail": "Ajouter une description plus détaillée",
"show-on-card": "Afficher sur la carte",
"card-settings-this-card": "Sur cette carte",
"card-settings-show-empty": "Afficher les vides",
"card-settings-show-empty-fields": "Afficher les champs vides",
"show-on-minicard": "Afficher sur la mini-carte",
"default-on-public-board": "Par défaut sur tableau public",
"show-on-public-board": "Afficher sur tableau public",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Intervenant",
"addmore-detail": "Ajouter une description plus détaillée",
"show-on-card": "Afficher sur la carte",
"card-settings-this-card": "Sur cette carte",
"card-settings-show-empty": "Afficher les vides",
"card-settings-show-empty-fields": "Afficher les champs vides",
"show-on-minicard": "Afficher sur la mini-carte",
"default-on-public-board": "Par défaut sur tableau public",
"show-on-public-board": "Afficher sur tableau public",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Intervenant",
"addmore-detail": "Ajouter une description plus détaillée",
"show-on-card": "Afficher sur la carte",
"card-settings-this-card": "Sur cette carte",
"card-settings-show-empty": "Afficher les vides",
"card-settings-show-empty-fields": "Afficher les champs vides",
"show-on-minicard": "Afficher sur la mini-carte",
"default-on-public-board": "Par défaut sur tableau public",
"show-on-public-board": "Afficher sur tableau public",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Personne assignée",
"addmore-detail": "Ajouter une description plus détaillée",
"show-on-card": "Afficher sur la carte",
"card-settings-this-card": "Sur cette carte",
"card-settings-show-empty": "Afficher les vides",
"card-settings-show-empty-fields": "Afficher les champs vides",
"show-on-minicard": "Afficher sur la minicarte",
"default-on-public-board": "Par défaut sur tableau public",
"show-on-public-board": "Afficher sur tableau public",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Intervenant",
"addmore-detail": "Ajouter une description plus détaillée",
"show-on-card": "Afficher sur la carte",
"card-settings-this-card": "Sur cette carte",
"card-settings-show-empty": "Afficher les vides",
"card-settings-show-empty-fields": "Afficher les champs vides",
"show-on-minicard": "Afficher sur la mini-carte",
"default-on-public-board": "Par défaut sur tableau public",
"show-on-public-board": "Afficher sur tableau public",
-3
View File
@@ -2000,9 +2000,6 @@
"cardAssigneesPopup-title": "Assegnât",
"addmore-detail": "Zonte una descrizion più dettagliata",
"show-on-card": "Mostre sulla cjarte",
"card-settings-this-card": "Su cheste cjarte",
"card-settings-show-empty": "Mostre i vueits",
"card-settings-show-empty-fields": "Mostre i cjamps vueits",
"show-on-minicard": "Mostre sulla minicjarte",
"default-on-public-board": "Predefinît su la lavagne publiche",
"show-on-public-board": "Mostre su la lavagne publiche",
Loaded 100 of 285 files, more files were not shown because too many files have changed in this diff. Show more