fraim-hub 2.0.262 → 2.0.263
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/public/ai-hub/index.html +33 -0
- package/public/ai-hub/script.js +71 -92
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fraim-hub",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.263",
|
|
4
4
|
"description": "FRAIM Hub local companion package.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"fraim-hub": "bin/fraim-hub.js",
|
|
@@ -163,7 +163,7 @@
|
|
|
163
163
|
"electron": "^41.2.2",
|
|
164
164
|
"electron-updater": "^6.8.9",
|
|
165
165
|
"express": "^5.2.1",
|
|
166
|
-
"fraim": "2.0.
|
|
166
|
+
"fraim": "2.0.263",
|
|
167
167
|
"mongodb": "^7.0.0",
|
|
168
168
|
"node-cron": "4.2.1",
|
|
169
169
|
"node-edge-tts": "^1.2.10",
|
package/public/ai-hub/index.html
CHANGED
|
@@ -1132,6 +1132,39 @@
|
|
|
1132
1132
|
</div>
|
|
1133
1133
|
|
|
1134
1134
|
<!-- Issue #834: Sharing-backend chooser modal -->
|
|
1135
|
+
<!-- Share destination modal: shown when the user clicks "Share with others" -->
|
|
1136
|
+
<div class="modal-backdrop" id="share-dest-modal" role="dialog" aria-modal="true" aria-labelledby="share-dest-title" hidden>
|
|
1137
|
+
<div class="modal">
|
|
1138
|
+
<div class="modal-header">
|
|
1139
|
+
<h2 id="share-dest-title">Share learnings</h2>
|
|
1140
|
+
<p id="share-dest-sub">Choose where to share these learnings.</p>
|
|
1141
|
+
</div>
|
|
1142
|
+
<div class="modal-body">
|
|
1143
|
+
<div class="lp-pp-dest-row" id="share-dest-row">
|
|
1144
|
+
<button class="lp-pp-dest-btn" type="button" data-dest="org" id="share-dest-org">
|
|
1145
|
+
<span class="lp-pp-dest-name">Company</span>
|
|
1146
|
+
<span class="lp-pp-dest-sub">Everyone in the organization</span>
|
|
1147
|
+
</button>
|
|
1148
|
+
<button class="lp-pp-dest-btn" type="button" data-dest="project" id="share-dest-proj">
|
|
1149
|
+
<span class="lp-pp-dest-name">This project</span>
|
|
1150
|
+
<span class="lp-pp-dest-sub">Visible on a specific project</span>
|
|
1151
|
+
</button>
|
|
1152
|
+
</div>
|
|
1153
|
+
<div class="lp-pp-project-section" id="share-dest-proj-section" hidden>
|
|
1154
|
+
<label class="lp-pp-label" for="share-dest-proj-sel">Which project?</label>
|
|
1155
|
+
<select class="lp-pp-sel" id="share-dest-proj-sel"></select>
|
|
1156
|
+
</div>
|
|
1157
|
+
</div>
|
|
1158
|
+
<div class="modal-footer">
|
|
1159
|
+
<span class="left" id="share-dest-hint"></span>
|
|
1160
|
+
<div class="right">
|
|
1161
|
+
<button class="ghost" type="button" id="share-dest-cancel">Cancel</button>
|
|
1162
|
+
<button class="send-button" type="button" id="share-dest-go" disabled>Start</button>
|
|
1163
|
+
</div>
|
|
1164
|
+
</div>
|
|
1165
|
+
</div>
|
|
1166
|
+
</div>
|
|
1167
|
+
|
|
1135
1168
|
<div class="modal-backdrop" id="sharing-chooser-modal" role="dialog" aria-modal="true" aria-labelledby="sharing-chooser-title" hidden>
|
|
1136
1169
|
<div class="modal">
|
|
1137
1170
|
<div class="modal-header">
|
package/public/ai-hub/script.js
CHANGED
|
@@ -13157,114 +13157,93 @@ async function tfRunShareWithOthers(scope, level, selectedTitles) {
|
|
|
13157
13157
|
const job = templates.find((t) => t.id === slug)
|
|
13158
13158
|
|| jobs.find((j) => j.id === slug)
|
|
13159
13159
|
|| { id: slug, title: 'Share with others', intent: 'Move artifacts to the right scope level.' };
|
|
13160
|
-
|
|
13161
|
-
if (typeof showStatus === 'function') showStatus('Pick a project folder first, then share learnings.', true);
|
|
13162
|
-
return;
|
|
13163
|
-
}
|
|
13164
|
-
// Always show the destination picker when sharing from the Manager tab —
|
|
13165
|
-
// the manager must choose Company vs. This project regardless of how many
|
|
13166
|
-
// projects are loaded.
|
|
13167
|
-
const hostId = scope === 'manager' && level === 'machine' ? 'manager-learnings' : 'project-learnings';
|
|
13168
|
-
tfShareDestinationPicker(hostId, scope, level, selectedTitles, job);
|
|
13160
|
+
tfShareDestinationPicker(scope, level, selectedTitles, job);
|
|
13169
13161
|
}
|
|
13170
13162
|
|
|
13171
|
-
// Destination picker:
|
|
13172
|
-
// optionally
|
|
13173
|
-
function tfShareDestinationPicker(
|
|
13174
|
-
const
|
|
13175
|
-
if (!
|
|
13176
|
-
// Remove any existing picker before showing a fresh one.
|
|
13177
|
-
host.querySelectorAll('.lp-project-picker').forEach((el) => el.remove());
|
|
13178
|
-
|
|
13179
|
-
const picker = document.createElement('div');
|
|
13180
|
-
picker.className = 'lp-project-picker';
|
|
13181
|
-
|
|
13182
|
-
// ── Step 1: destination scope ──────────────────────────────────────────
|
|
13183
|
-
const destLabel = document.createElement('div');
|
|
13184
|
-
destLabel.className = 'lp-pp-label';
|
|
13185
|
-
destLabel.textContent = 'Share to:';
|
|
13186
|
-
picker.appendChild(destLabel);
|
|
13187
|
-
|
|
13188
|
-
const destRow = document.createElement('div');
|
|
13189
|
-
destRow.className = 'lp-pp-dest-row';
|
|
13190
|
-
|
|
13191
|
-
const makeDestBtn = (value, text, desc) => {
|
|
13192
|
-
const btn = document.createElement('button');
|
|
13193
|
-
btn.type = 'button';
|
|
13194
|
-
btn.className = 'lp-pp-dest-btn';
|
|
13195
|
-
btn.dataset.dest = value;
|
|
13196
|
-
const name = document.createElement('span'); name.className = 'lp-pp-dest-name'; name.textContent = text;
|
|
13197
|
-
const sub = document.createElement('span'); sub.className = 'lp-pp-dest-sub'; sub.textContent = desc;
|
|
13198
|
-
btn.appendChild(name); btn.appendChild(sub);
|
|
13199
|
-
return btn;
|
|
13200
|
-
};
|
|
13201
|
-
|
|
13202
|
-
const companyBtn = makeDestBtn('org', 'Company', 'Everyone in the organization');
|
|
13203
|
-
const projectBtn = makeDestBtn('project', 'This project', 'Visible on a specific project');
|
|
13204
|
-
destRow.appendChild(companyBtn);
|
|
13205
|
-
destRow.appendChild(projectBtn);
|
|
13206
|
-
picker.appendChild(destRow);
|
|
13207
|
-
|
|
13208
|
-
// ── Step 2: project picker (hidden until "This project" chosen) ────────
|
|
13209
|
-
const projectSection = document.createElement('div');
|
|
13210
|
-
projectSection.className = 'lp-pp-project-section';
|
|
13211
|
-
projectSection.hidden = true;
|
|
13163
|
+
// Destination picker: modal overlay. Company vs. This project, then (for project)
|
|
13164
|
+
// optionally which project when more than one is loaded.
|
|
13165
|
+
function tfShareDestinationPicker(scope, level, selectedTitles, job) {
|
|
13166
|
+
const modal = document.getElementById('share-dest-modal');
|
|
13167
|
+
if (!modal) return;
|
|
13212
13168
|
|
|
13169
|
+
const orgBtn = document.getElementById('share-dest-org');
|
|
13170
|
+
const projBtn = document.getElementById('share-dest-proj');
|
|
13171
|
+
const projSection = document.getElementById('share-dest-proj-section');
|
|
13172
|
+
const projSel = document.getElementById('share-dest-proj-sel');
|
|
13173
|
+
const goBtn = document.getElementById('share-dest-go');
|
|
13174
|
+
const cancelBtn = document.getElementById('share-dest-cancel');
|
|
13175
|
+
const hintEl = document.getElementById('share-dest-hint');
|
|
13176
|
+
|
|
13177
|
+
if (!orgBtn || !projBtn || !projSection || !projSel || !goBtn || !cancelBtn) return;
|
|
13178
|
+
|
|
13179
|
+
// Reset visual state.
|
|
13180
|
+
orgBtn.classList.remove('lp-pp-dest-selected');
|
|
13181
|
+
projBtn.classList.remove('lp-pp-dest-selected');
|
|
13182
|
+
projSection.hidden = true;
|
|
13183
|
+
goBtn.disabled = true;
|
|
13184
|
+
if (hintEl) hintEl.textContent = selectedTitles && selectedTitles.length > 0
|
|
13185
|
+
? `${selectedTitles.length} learning${selectedTitles.length === 1 ? '' : 's'} selected`
|
|
13186
|
+
: 'All learnings will be shared';
|
|
13187
|
+
|
|
13188
|
+
// Populate project dropdown.
|
|
13189
|
+
projSel.innerHTML = '';
|
|
13213
13190
|
const projects = (typeof tf !== 'undefined' && tf.projects) || [];
|
|
13214
|
-
if (projects.length >
|
|
13215
|
-
const projLabel = document.createElement('label');
|
|
13216
|
-
projLabel.className = 'lp-pp-label';
|
|
13217
|
-
const projLabelId = 'lp-pp-proj-' + Math.random().toString(36).slice(2, 8);
|
|
13218
|
-
projLabel.id = projLabelId;
|
|
13219
|
-
projLabel.textContent = 'Which project?';
|
|
13220
|
-
const projSel = document.createElement('select');
|
|
13221
|
-
projSel.className = 'lp-pp-sel';
|
|
13222
|
-
projSel.setAttribute('aria-labelledby', projLabelId);
|
|
13191
|
+
if (projects.length > 0) {
|
|
13223
13192
|
for (const p of projects) {
|
|
13224
|
-
const o = document.createElement('option');
|
|
13193
|
+
const o = document.createElement('option');
|
|
13194
|
+
o.value = p.id;
|
|
13225
13195
|
o.textContent = p.name || p.id;
|
|
13226
|
-
if (p.id === tf.activeProjectId) o.selected = true;
|
|
13196
|
+
if (p.id === (typeof tf !== 'undefined' && tf.activeProjectId)) o.selected = true;
|
|
13227
13197
|
projSel.appendChild(o);
|
|
13228
13198
|
}
|
|
13229
|
-
|
|
13230
|
-
|
|
13231
|
-
|
|
13199
|
+
} else if (state.projectPath) {
|
|
13200
|
+
const o = document.createElement('option');
|
|
13201
|
+
o.value = state.projectPath;
|
|
13202
|
+
o.textContent = state.projectPath.split(/[\\/]/).pop() || state.projectPath;
|
|
13203
|
+
projSel.appendChild(o);
|
|
13232
13204
|
}
|
|
13233
|
-
picker.appendChild(projectSection);
|
|
13234
|
-
|
|
13235
|
-
// ── Action row ─────────────────────────────────────────────────────────
|
|
13236
|
-
const bar = document.createElement('div'); bar.className = 'lp-pp-bar';
|
|
13237
|
-
const go = document.createElement('button');
|
|
13238
|
-
go.type = 'button'; go.className = 'rb-approve'; go.textContent = 'Start'; go.disabled = true;
|
|
13239
|
-
const cancel = document.createElement('button');
|
|
13240
|
-
cancel.type = 'button'; cancel.className = 'rb-secondary'; cancel.textContent = 'Cancel';
|
|
13241
|
-
bar.appendChild(go); bar.appendChild(cancel);
|
|
13242
|
-
picker.appendChild(bar);
|
|
13243
|
-
host.appendChild(picker);
|
|
13244
13205
|
|
|
13245
13206
|
let chosenDest = null;
|
|
13246
13207
|
|
|
13247
|
-
|
|
13248
|
-
|
|
13249
|
-
|
|
13250
|
-
|
|
13251
|
-
|
|
13252
|
-
|
|
13208
|
+
// Use AbortController so listeners are torn down atomically when the modal closes.
|
|
13209
|
+
const ac = new AbortController();
|
|
13210
|
+
const sig = { signal: ac.signal };
|
|
13211
|
+
|
|
13212
|
+
const selectDest = (dest) => {
|
|
13213
|
+
orgBtn.classList.toggle('lp-pp-dest-selected', dest === 'org');
|
|
13214
|
+
projBtn.classList.toggle('lp-pp-dest-selected', dest === 'project');
|
|
13215
|
+
chosenDest = dest;
|
|
13216
|
+
projSection.hidden = dest !== 'project';
|
|
13217
|
+
goBtn.disabled = false;
|
|
13218
|
+
};
|
|
13219
|
+
|
|
13220
|
+
orgBtn.addEventListener('click', () => selectDest('org'), sig);
|
|
13221
|
+
projBtn.addEventListener('click', () => selectDest('project'), sig);
|
|
13222
|
+
|
|
13223
|
+
const close = () => {
|
|
13224
|
+
ac.abort();
|
|
13225
|
+
modal.hidden = true;
|
|
13226
|
+
modal.classList.remove('open');
|
|
13253
13227
|
};
|
|
13254
13228
|
|
|
13255
|
-
|
|
13256
|
-
projectBtn.addEventListener('click', () => selectDest(projectBtn));
|
|
13229
|
+
cancelBtn.addEventListener('click', close, sig);
|
|
13257
13230
|
|
|
13258
|
-
|
|
13231
|
+
goBtn.addEventListener('click', async () => {
|
|
13232
|
+
const dest = chosenDest || 'project';
|
|
13233
|
+
close();
|
|
13234
|
+
const projectId = dest === 'project'
|
|
13235
|
+
? (projSel.value || ((typeof tf !== 'undefined' && tf.activeProjectId) || state.projectPath))
|
|
13236
|
+
: ((typeof tf !== 'undefined' && tf.activeProjectId) || state.projectPath);
|
|
13237
|
+
await tfLaunchShareWithOthers(scope, level, selectedTitles, job, projectId, dest);
|
|
13238
|
+
}, sig);
|
|
13259
13239
|
|
|
13260
|
-
|
|
13261
|
-
|
|
13262
|
-
|
|
13263
|
-
|
|
13264
|
-
|
|
13265
|
-
|
|
13266
|
-
|
|
13267
|
-
});
|
|
13240
|
+
// Dismiss on backdrop click.
|
|
13241
|
+
modal.addEventListener('click', (e) => { if (e.target === modal) close(); }, sig);
|
|
13242
|
+
|
|
13243
|
+
// Open.
|
|
13244
|
+
modal.hidden = false;
|
|
13245
|
+
modal.classList.add('open');
|
|
13246
|
+
orgBtn.focus();
|
|
13268
13247
|
}
|
|
13269
13248
|
|
|
13270
13249
|
async function tfLaunchShareWithOthers(scope, level, selectedTitles, job, projectId, destination) {
|