PCO Plan 1.7.0: a Teams tile — who is scheduled, with photos #23
@@ -411,21 +411,35 @@
|
|||||||
"h": 2
|
"h": 2
|
||||||
},
|
},
|
||||||
"instanceSchema": {
|
"instanceSchema": {
|
||||||
|
"columns": {
|
||||||
|
"type": "select",
|
||||||
|
"label": "Columns",
|
||||||
|
"default": "auto",
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"value": "auto",
|
||||||
|
"label": "Fit the tile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "1",
|
||||||
|
"label": "One"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "2",
|
||||||
|
"label": "Two"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "3",
|
||||||
|
"label": "Three"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"teams": {
|
"teams": {
|
||||||
"type": "multiselect",
|
"type": "multiselect",
|
||||||
"label": "Teams",
|
"label": "Teams",
|
||||||
"group": "Teams",
|
|
||||||
"optionsRoute": "/teams",
|
|
||||||
"columns": 1,
|
|
||||||
"allByDefault": true
|
|
||||||
},
|
|
||||||
"positions": {
|
|
||||||
"type": "multiselect",
|
|
||||||
"label": "Positions",
|
|
||||||
"group": "Positions",
|
|
||||||
"optionsRoute": "/positions",
|
|
||||||
"columns": 2,
|
"columns": 2,
|
||||||
"allByDefault": true
|
"allByDefault": true,
|
||||||
|
"optionsRoute": "/teams"
|
||||||
},
|
},
|
||||||
"headerTemplate": {
|
"headerTemplate": {
|
||||||
"type": "template",
|
"type": "template",
|
||||||
@@ -484,12 +498,6 @@
|
|||||||
"default": false,
|
"default": false,
|
||||||
"group": "Colors"
|
"group": "Colors"
|
||||||
},
|
},
|
||||||
"headerGradient": {
|
|
||||||
"type": "boolean",
|
|
||||||
"label": "Header fade",
|
|
||||||
"default": true,
|
|
||||||
"group": "Colors"
|
|
||||||
},
|
|
||||||
"tintRows": {
|
"tintRows": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"label": "Tint rows too",
|
"label": "Tint rows too",
|
||||||
@@ -497,23 +505,29 @@
|
|||||||
"group": "Colors",
|
"group": "Colors",
|
||||||
"showWhen": "tintTeams"
|
"showWhen": "tintTeams"
|
||||||
},
|
},
|
||||||
|
"headerGradient": {
|
||||||
|
"type": "boolean",
|
||||||
|
"label": "Header fade",
|
||||||
|
"default": true,
|
||||||
|
"group": "Colors"
|
||||||
|
},
|
||||||
"confirmedColor": {
|
"confirmedColor": {
|
||||||
"type": "color",
|
"type": "color",
|
||||||
"label": "Confirmed",
|
"label": "Confirmed",
|
||||||
"default": "#2ee59a",
|
"default": "#2ee59a",
|
||||||
"group": "Status colors"
|
"group": "Colors"
|
||||||
},
|
},
|
||||||
"unconfirmedColor": {
|
"unconfirmedColor": {
|
||||||
"type": "color",
|
"type": "color",
|
||||||
"label": "Unconfirmed",
|
"label": "Unconfirmed",
|
||||||
"default": "#f0b429",
|
"default": "#f0b429",
|
||||||
"group": "Status colors"
|
"group": "Colors"
|
||||||
},
|
},
|
||||||
"declinedColor": {
|
"declinedColor": {
|
||||||
"type": "color",
|
"type": "color",
|
||||||
"label": "Declined",
|
"label": "Declined",
|
||||||
"default": "#f4433c",
|
"default": "#f4433c",
|
||||||
"group": "Status colors"
|
"group": "Colors"
|
||||||
},
|
},
|
||||||
"showTopBar": {
|
"showTopBar": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
@@ -580,52 +594,16 @@
|
|||||||
"label": "Teams with nobody",
|
"label": "Teams with nobody",
|
||||||
"default": false,
|
"default": false,
|
||||||
"group": "Show"
|
"group": "Show"
|
||||||
},
|
|
||||||
"columns": {
|
|
||||||
"type": "select",
|
|
||||||
"label": "Columns",
|
|
||||||
"default": "auto",
|
|
||||||
"group": "Show",
|
|
||||||
"options": [
|
|
||||||
{
|
|
||||||
"value": "auto",
|
|
||||||
"label": "Fit the tile"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"value": "1",
|
|
||||||
"label": "One"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"value": "2",
|
|
||||||
"label": "Two"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"value": "3",
|
|
||||||
"label": "Three"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"instanceGroups": {
|
"instanceGroups": {
|
||||||
"Top bar": {
|
"Top bar": {
|
||||||
"collapsed": false
|
"collapsed": false
|
||||||
},
|
},
|
||||||
"Teams": {
|
|
||||||
"collapsed": true,
|
|
||||||
"help": "Untick a team to leave it out of this tile."
|
|
||||||
},
|
|
||||||
"Positions": {
|
|
||||||
"collapsed": true,
|
|
||||||
"help": "Untick a position to leave it out. Positions follow the teams above."
|
|
||||||
},
|
|
||||||
"Colors": {
|
"Colors": {
|
||||||
"collapsed": false,
|
"collapsed": false,
|
||||||
"columns": 2
|
"columns": 2
|
||||||
},
|
},
|
||||||
"Status colors": {
|
|
||||||
"collapsed": true,
|
|
||||||
"columns": 3
|
|
||||||
},
|
|
||||||
"Show": {
|
"Show": {
|
||||||
"collapsed": true,
|
"collapsed": true,
|
||||||
"columns": 2
|
"columns": 2
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
* GET /note-categories → { options } for a tile's "Item notes" categories:
|
* GET /note-categories → { options } for a tile's "Item notes" categories:
|
||||||
* the service type's item note categories, by name
|
* the service type's item note categories, by name
|
||||||
* GET /teams → { options } for a Teams tile's "Teams" switches
|
* GET /teams → { options } for a Teams tile's "Teams" switches
|
||||||
* GET /positions → { options } for a Teams tile's "Positions" switches
|
|
||||||
* GET /team-avatar/<planPersonId> → that person's photo, proxied + cached
|
* GET /team-avatar/<planPersonId> → that person's photo, proxied + cached
|
||||||
* GET /timers → snapshot for the Timers module (guide: "Offering
|
* GET /timers → snapshot for the Timers module (guide: "Offering
|
||||||
* GET /timers/stream → SSE, `timers` events timers to the Timers module")
|
* GET /timers/stream → SSE, `timers` events timers to the Timers module")
|
||||||
@@ -821,24 +820,6 @@ module.exports = {
|
|||||||
return { options: state.teams.map((t) => ({ value: t.id, label: t.name })) };
|
return { options: state.teams.map((t) => ({ value: t.id, label: t.name })) };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Options for a Teams tile's "Positions" switches. Positions are named,
|
|
||||||
* not numbered, in Planning Center, so the name is the value; the team
|
|
||||||
* name groups them so two "Leader" positions stay apart in the list.
|
|
||||||
*/
|
|
||||||
function positionOptions() {
|
|
||||||
const seen = new Set();
|
|
||||||
const options = [];
|
|
||||||
for (const team of state.teams) {
|
|
||||||
for (const m of team.members) {
|
|
||||||
const value = m.position || '(no position)';
|
|
||||||
if (seen.has(value)) continue;
|
|
||||||
seen.add(value);
|
|
||||||
options.push({ value, label: value, group: team.name });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return { options };
|
|
||||||
}
|
|
||||||
|
|
||||||
async function readPlan() {
|
async function readPlan() {
|
||||||
if (!pco.configured || !serviceTypeId) return;
|
if (!pco.configured || !serviceTypeId) return;
|
||||||
@@ -1589,7 +1570,6 @@ module.exports = {
|
|||||||
documentOptions,
|
documentOptions,
|
||||||
noteCategoryOptions,
|
noteCategoryOptions,
|
||||||
teamOptions,
|
teamOptions,
|
||||||
positionOptions,
|
|
||||||
avatarUrlFor: (id) => teamPhotos.get(String(id)) || "",
|
avatarUrlFor: (id) => teamPhotos.get(String(id)) || "",
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1684,19 +1664,15 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Options for a Teams tile's "Teams" and "Positions" switches. Like the
|
* Options for a Teams tile's "Teams" switches. Like the note
|
||||||
* note categories, always a 200 with a list: an empty one simply means
|
* categories, always a 200 with a list: an empty one simply means there
|
||||||
* there is nothing scheduled to choose from yet, which the gear window
|
* is nothing scheduled to choose from yet, which the gear window says
|
||||||
* says plainly.
|
* plainly.
|
||||||
*/
|
*/
|
||||||
'GET /teams': (req, res) => {
|
'GET /teams': (req, res) => {
|
||||||
json(res, 200, current ? current.teamOptions() : { options: [] });
|
json(res, 200, current ? current.teamOptions() : { options: [] });
|
||||||
},
|
},
|
||||||
|
|
||||||
'GET /positions': (req, res) => {
|
|
||||||
json(res, 200, current ? current.positionOptions() : { options: [] });
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A scheduled person's photo, proxied from Planning Center and cached.
|
* A scheduled person's photo, proxied from Planning Center and cached.
|
||||||
* The tile asks by plan-person id and never sees the CDN URL; an id the
|
* The tile asks by plan-person id and never sees the CDN URL; an id the
|
||||||
|
|||||||
@@ -94,12 +94,10 @@ export default function createTeams({ root, moduleApi }) {
|
|||||||
function visibleTeams() {
|
function visibleTeams() {
|
||||||
const teams = Array.isArray(state?.teams) ? state.teams : [];
|
const teams = Array.isArray(state?.teams) ? state.teams : [];
|
||||||
const wantTeams = chosen('teams');
|
const wantTeams = chosen('teams');
|
||||||
const wantPositions = chosen('positions');
|
|
||||||
const out = [];
|
const out = [];
|
||||||
for (const team of teams) {
|
for (const team of teams) {
|
||||||
if (wantTeams && !wantTeams.includes(team.id)) continue;
|
if (wantTeams && !wantTeams.includes(team.id)) continue;
|
||||||
const members = team.members.filter((m) => {
|
const members = team.members.filter((m) => {
|
||||||
if (wantPositions && !wantPositions.includes(m.position || '(no position)')) return false;
|
|
||||||
if (m.status === 'declined' && !on('showDeclined')) return false;
|
if (m.status === 'declined' && !on('showDeclined')) return false;
|
||||||
if (m.status === 'unconfirmed' && !on('showUnconfirmed')) return false;
|
if (m.status === 'unconfirmed' && !on('showUnconfirmed')) return false;
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
Reference in New Issue
Block a user