/* ════════════════════════════════════════════════════════════════════════
* FlowDeck — « Convertir en base de tâches »
*
* Modale de linkage : pour les trois rôles requis (Assigné à / Statut /
* Échéance) on choisit soit une colonne existante compatible, soit on en
* crée une nouvelle avec le bon type. Le serveur fait foi
* (`POST /db/{id}/task-db/api`) : il valide les types, refuse le double
* emploi d'une colonne et applique la limite de 10 bases connectées.
* ══════════════════════════════════════════════════════════════════════ */
(function () {
'use strict';
if (window.__fdTaskDbLinkLoaded) return;
window.__fdTaskDbLinkLoaded = true;
var ROLE_LABELS = { assignee: 'Assigné à', status: 'Statut', due: "Date d'échéance" };
var ROLE_HINTS = {
assignee: 'Colonne « personne » utilisée pour filtrer vos tâches.',
status: 'Colonne statut ou sélection (À faire / En cours / Terminée).',
due: 'Colonne de type date, utilisée par les vues et le calendrier.'
};
var DEFAULT_NAMES = { assignee: 'Assigné à', status: 'Statut', due: "Échéance" };
var TYPE_LABELS = {
person: 'personne', status: 'statut', select: 'sélection', date: 'date',
text: 'texte', number: 'nombre', checkbox: 'case à cocher'
};
function esc(s) {
return String(s == null ? '' : s)
.replace(/&/g, '&').replace(//g, '>')
.replace(/"/g, '"').replace(/'/g, ''');
}
function csrf() {
return (typeof window.getCsrf === 'function') ? window.getCsrf() : '';
}
function api(path, opts) {
opts = opts || {};
var headers = { 'X-CSRF-Token': csrf() };
if (opts.body) headers['Content-Type'] = 'application/json';
return fetch(path, {
method: opts.method || 'GET',
credentials: 'same-origin',
headers: headers,
body: opts.body ? JSON.stringify(opts.body) : undefined
}).then(function (r) {
return r.json().catch(function () { return {}; }).then(function (d) {
if (!r.ok) throw new Error(d.detail || ('Erreur ' + r.status));
return d;
});
});
}
/* ── Modale ─────────────────────────────────────────────────────── */
function roleRow(state, role) {
var selected = state.mapping[role];
var current = state.candidates[role] || [];
// La colonne déjà mappée doit rester sélectionnable même si elle est
// de type compatible mais exclue des candidats (déjà affectée).
var all = state.all_properties || [];
if (selected && !current.some(function (p) { return p.id === selected; })) {
var kept = all.filter(function (p) { return p.id === selected; })[0];
if (kept) current = [kept].concat(current);
}
var h = '
';
h += '
';
h += '' + esc(ROLE_HINTS[role]) + '
';
h += '
';
h += '';
h += '';
h += '
';
return h;
}
function openModal(collectionId) {
closeModal();
api('/db/' + collectionId + '/task-db/api').then(function (state) {
if (!state.exists) return;
var roles = ['assignee', 'status', 'due'];
var h = '
';
h += '
' +
(state.is_task ? 'Base de tâches' : 'Convertir en base de tâches') +
'
';
h += '
Pour alimenter My Tasks, ' +
'reliez les trois colonnes ci-dessous. Une colonne absente sera créée ' +
'avec le bon type.
';
h += '
';
roles.forEach(function (r) { h += roleRow(state, r); });
h += '
';
if (state.sources_count >= state.max_sources) {
h += '
⚠ Limite de ' + state.max_sources +
' bases connectées atteinte : déconnectez-en une avant.
';
}
h += '
';
if (state.is_task) {
h += '';
}
h += '';
h += '';
h += '';
h += '
';
document.body.insertAdjacentHTML('beforeend', h);
wire(state, collectionId);
}).catch(function (e) { alert(e.message); });
}
function closeModal() {
var ov = document.getElementById('tdb-overlay');
if (ov) ov.remove();
}
function wire(state, collectionId) {
var overlay = document.getElementById('tdb-overlay');
overlay.addEventListener('click', function (e) {
if (e.target === overlay) closeModal();
});
document.getElementById('tdb-close').onclick = closeModal;
document.getElementById('tdb-cancel').onclick = closeModal;
// Choisir une colonne masque le champ « nouvelle colonne ».
overlay.addEventListener('change', function (e) {
var role = e.target.dataset.tdbRole;
if (!role) return;
var input = overlay.querySelector('[data-tdb-new="' + role + '"]');
if (input) input.style.display = e.target.value ? 'none' : '';
});
var disable = document.getElementById('tdb-disable');
if (disable) {
disable.onclick = function () {
if (!confirm('Disconnecter cette base de My Tasks ?\n\n' +
'Les tâches restent dans la base.')) return;
api('/db/' + collectionId + '/task-db/api', { method: 'DELETE' })
.then(function () { closeModal(); toast('Base déconnectée de My Tasks'); })
.catch(function (e) { alert(e.message); });
};
}
document.getElementById('tdb-save').onclick = function () {
var mapping = {}, create_missing = {};
['assignee', 'status', 'due'].forEach(function (role) {
var sel = overlay.querySelector('[data-tdb-role="' + role + '"]');
var val = sel ? sel.value : '';
if (val) {
mapping[role] = Number(val);
} else {
var input = overlay.querySelector('[data-tdb-new="' + role + '"]');
create_missing[role] = {
name: (input && input.value.trim()) || DEFAULT_NAMES[role]
};
}
});
api('/db/' + collectionId + '/task-db/api',
{ method: 'POST', body: { mapping: mapping, create_missing: create_missing } })
.then(function (d) {
closeModal();
toast(d.configured
? '✅ Base connectée à My Tasks'
: '⚠ Mapping incomplet — des colonnes manquent');
})
.catch(function (e) { alert(e.message); });
};
}
function toast(msg) {
var t = document.createElement('div');
t.textContent = msg;
t.style.cssText = 'position:fixed;bottom:24px;left:50%;transform:translateX(-50%);' +
'z-index:1200;background:var(--bg-modal,#fff);color:var(--text-primary,#333);' +
'border:1px solid var(--border,#e3e3e0);border-radius:8px;padding:9px 16px;' +
'font-size:13px;box-shadow:0 8px 24px rgba(0,0,0,.16)';
document.body.appendChild(t);
setTimeout(function () { t.remove(); }, 3200);
}
/* ── Point d'entrée depuis la barre de la base ──────────────────── */
window.FlowDeckTaskDb = { open: openModal, close: closeModal };
document.addEventListener('click', function (e) {
var trigger = e.target.closest ? e.target.closest('[data-task-db]') : null;
if (!trigger) return;
e.preventDefault();
e.stopPropagation();
var id = trigger.dataset.taskDb;
if (id) openModal(Number(id));
});
})();