Add AirBase grid widget and management skill
This commit is contained in:
@@ -498,6 +498,22 @@
|
||||
"Fields"
|
||||
]
|
||||
},
|
||||
"airbase-grid": {
|
||||
"ru": [
|
||||
"Таблица AirBase",
|
||||
"Записи AirBase с фильтрами, сортировкой, изменением ячеек и массовыми действиями.",
|
||||
"Запись",
|
||||
"Обновлено",
|
||||
"Поля таблицы"
|
||||
],
|
||||
"en": [
|
||||
"AirBase grid",
|
||||
"AirBase records with field filters, sorting, cell edits and bulk actions.",
|
||||
"Record",
|
||||
"Updated",
|
||||
"Table fields"
|
||||
]
|
||||
},
|
||||
"documents": {
|
||||
"ru": [
|
||||
"Документы",
|
||||
@@ -1028,6 +1044,30 @@
|
||||
],
|
||||
"sort": "asc"
|
||||
},
|
||||
"airbase-grid": {
|
||||
"listTool": "shd_airbase_records",
|
||||
"listArgs": {
|
||||
"limit": 100,
|
||||
"include_fields": true,
|
||||
"include_view_meta": true
|
||||
},
|
||||
"paths": [
|
||||
"data.records",
|
||||
"data"
|
||||
],
|
||||
"view": "table",
|
||||
"contextRequired": true,
|
||||
"contextSets": [
|
||||
[
|
||||
"base",
|
||||
"project_code"
|
||||
],
|
||||
[
|
||||
"table"
|
||||
]
|
||||
],
|
||||
"sort": "asc"
|
||||
},
|
||||
"documents": {
|
||||
"listTool": "shd_list_contracts",
|
||||
"listArgs": {
|
||||
|
||||
@@ -15,6 +15,7 @@ __SHD_WIDGET_ACTIONS_CSS__
|
||||
<main class="shell" data-shd-widget-engine="shd-universal-v1" data-widget-module="__SHD_WIDGET_MODULE__"><section class="card">
|
||||
<div class="eyebrow">SHD MCP</div><h1 id="title">SHD</h1><p class="lede" id="desc"></p><div class="summary" id="summary"></div>
|
||||
<div class="toolbar"><input class="search" id="search" type="search" autocomplete="off"><button class="refresh" id="refresh" type="button"></button></div>
|
||||
<div class="toolbar" id="airbase-grid-controls" hidden><select id="airbase-filter-field" aria-label="Filter field"></select><input id="airbase-filter-value" type="search" autocomplete="off"><select id="airbase-sort-field" aria-label="Sort field"></select><button id="airbase-sort-direction" type="button"></button><button id="airbase-clear-filters" type="button"></button></div>
|
||||
<div class="status" id="status" role="status" aria-live="polite"></div>
|
||||
<div class="table-wrap"><table><thead><tr><th id="head-title"></th><th id="head-status"></th><th id="head-date"></th><th id="head-value"></th></tr></thead><tbody id="rows"></tbody></table><div class="empty" id="empty" hidden></div></div><div class="visual" id="visual" hidden></div>
|
||||
<section class="details" id="details" hidden aria-live="polite"><div class="detail-head"><div><h2 id="detail-title"></h2><div class="sub" id="detail-sub"></div></div><button class="close" id="close" type="button">×</button></div><div class="grid" id="grid"></div></section>
|
||||
@@ -24,6 +25,7 @@ __SHD_WIDGET_ACTIONS_CSS__
|
||||
'use strict';
|
||||
var DEFAULT_MODULE='__SHD_WIDGET_MODULE__';
|
||||
var C={ru:{refresh:'Обновить',search:'Поиск по названию, статусу или ID',loading:'Загрузка…',empty:'Нет данных для отображения.',records:'записей',status:'Статус',date:'Дата',value:'Детали',id:'ID',details:'Детали',close:'Закрыть',load:'Не удалось загрузить данные.',detail:'Не удалось загрузить детали.',context:'Для обновления нужен контекст источника',total:'Всего',amount:'Сумма',planned:'План',capacity:'Ёмкость',utilization:'Загрузка',overload:'Перегрузка',warnings:'Предупреждения',complete:'Готово',pending:'Ожидают',approved:'Согласовано',rejected:'Отклонено',progress:'Прогресс',score:'Оценка',member:'Участник',role:'Роль',permissions:'Разрешения',preview:'Предпросмотр',noWarnings:'Предупреждений нет.',health:'Состояние',yes:'Да',no:'Нет'},en:{refresh:'Refresh',search:'Search by name, status or ID',loading:'Loading…',empty:'No data to display.',records:'records',status:'Status',date:'Date',value:'Details',id:'ID',details:'Details',close:'Close',load:'Could not load data.',detail:'Could not load details.',context:'A source context is required to refresh.',total:'Total',amount:'Amount',planned:'Planned',capacity:'Capacity',utilization:'Utilization',overload:'Overload',warnings:'Warnings',complete:'Complete',pending:'Pending',approved:'Approved',rejected:'Rejected',progress:'Progress',score:'Score',member:'Member',role:'Role',permissions:'Permissions',preview:'Preview',noWarnings:'No warnings.',health:'Health',yes:'Yes',no:'No'}};
|
||||
var G={ru:{filterField:'Фильтр по полю',filterValue:'Значение для фильтра',sortField:'Сортировать по',ascending:'Сортировка: А—Я',descending:'Сортировка: Я—А',clear:'Сбросить фильтры',allFields:'Все поля',record:'Запись'},en:{filterField:'Filter field',filterValue:'Filter value',sortField:'Sort by',ascending:'Sort: A—Z',descending:'Sort: Z—A',clear:'Clear filters',allFields:'All fields',record:'Record'}};
|
||||
var FIELD_LABELS={ru:{id:'ID',key:'Ключ',project_id:'ID проекта',task_project_id:'ID проекта задачи',linked_project_ids:'Связанные проекты',project_code:'Код проекта',base_reference:'Ссылка на базу',base_public_id:'Публичный ID базы',table_public_id:'Публичный ID таблицы',record_public_id:'Публичный ID записи',title:'Название',name:'Название',description:'Описание',status:'Статус',status_id:'ID статуса',is_done:'Завершено',is_complete:'Завершено',section:'Раздел',sort_order:'Порядок сортировки',created_at:'Создано',updated_at:'Обновлено',due_date:'Срок',deadline:'Дедлайн',starts_at:'Начало',ends_at:'Окончание',url:'Ссылка',diagnostic:'Диагностика',message:'Сообщение',type:'Тип',state:'Состояние',phase:'Этап',health:'Состояние',email:'Электронная почта',username:'Имя пользователя',role:'Роль',permissions:'Разрешения',source:'Источник',module:'Модуль',table:'Таблица',fields:'Поля',value:'Значение',stage:'Стадия',approval_status:'Статус согласования',approval_state:'Состояние согласования',priority:'Приоритет',assignee:'Исполнитель',owner:'Владелец',type:'Тип',category:'Категория',permissions:'Разрешения',permission:'Разрешение',read:'Чтение',write:'Запись',manage:'Управление',admin:'Администратор',view:'Просмотр',create:'Создание',update:'Изменение',delete:'Удаление',error:'Ошибка',warning:'Предупреждение',message:'Сообщение',path:'Путь',link:'Ссылка',amount:'Сумма',total:'Итого',quantity:'Количество',available_quantity:'Доступное количество',stock:'Остаток',planned:'План',planned_hours:'Плановые часы',capacity:'Ёмкость',capacity_hours:'Часы ёмкости',utilization:'Загрузка',utilization_percent:'Загрузка, %',overload:'Перегрузка',overload_hours:'Часы перегрузки',score:'Оценка',progress:'Прогресс',completeness_score:'Оценка полноты',completion_percent:'Полнота, %',availability_percent:'Доступность, %',record_count:'Количество записей',revision:'Ревизия',pages:'Страницы',page_count:'Количество страниц',date:'Дата',is_archived:'В архиве',low_stock:'Мало на складе',critical:'Критический',meta:'Метаданные'},en:{id:'ID',key:'Key',project_id:'Project ID',task_project_id:'Task project ID',linked_project_ids:'Linked projects',project_code:'Project code',base_reference:'Base reference',base_public_id:'Public base ID',table_public_id:'Public table ID',record_public_id:'Public record ID',title:'Title',name:'Name',description:'Description',status:'Status',status_id:'Status ID',is_done:'Completed',is_complete:'Completed',section:'Section',sort_order:'Sort order',created_at:'Created',updated_at:'Updated',due_date:'Due date',deadline:'Deadline',starts_at:'Starts',ends_at:'Ends',url:'URL',diagnostic:'Diagnostics',message:'Message',type:'Type',state:'State',phase:'Phase',health:'Health',email:'Email',username:'Username',role:'Role',permissions:'Permissions',source:'Source',module:'Module',table:'Table',fields:'Fields',value:'Value',stage:'Stage',approval_status:'Approval status',approval_state:'Approval state',priority:'Priority',assignee:'Assignee',owner:'Owner',type:'Type',category:'Category',permissions:'Permissions',permission:'Permission',read:'Read',write:'Write',manage:'Manage',admin:'Admin',view:'View',create:'Create',update:'Update',delete:'Delete',error:'Error',warning:'Warning',message:'Message',path:'Path',link:'Link',amount:'Amount',total:'Total',quantity:'Quantity',available_quantity:'Available quantity',stock:'Stock',planned:'Planned',planned_hours:'Planned hours',capacity:'Capacity',capacity_hours:'Capacity hours',utilization:'Utilization',utilization_percent:'Utilization, %',overload:'Overload',overload_hours:'Overload hours',score:'Score',progress:'Progress',completeness_score:'Completeness score',completion_percent:'Completeness, %',availability_percent:'Availability, %',record_count:'Record count',revision:'Revision',pages:'Pages',page_count:'Page count',date:'Date',is_archived:'Archived',low_stock:'Low stock',critical:'Critical',meta:'Metadata'}};
|
||||
var VALUE_LABELS={ru:{Tasks_Status_Todo:'К выполнению',Tasks_Status_Done:'Завершено',Tasks_Status_In_Progress:'В работе',Tasks_Status_Review:'На проверке',Modules_Done:'Завершено',todo:'К выполнению',to_do:'К выполнению','to do':'К выполнению',in_progress:'В работе','in progress':'В работе','in-progress':'В работе',in_progress_status:'В работе',done:'Завершено',completed:'Завершено',complete:'Завершено',closed:'Закрыто',active:'Активно',pending:'Ожидает',review:'На проверке',approved:'Согласовано',rejected:'Отклонено',archived:'В архиве',not_set:'Не задано'},en:{Tasks_Status_Todo:'To do',Tasks_Status_Done:'Done',Tasks_Status_In_Progress:'In progress',Tasks_Status_Review:'In review',Modules_Done:'Done',todo:'To do',to_do:'To do','to do':'To do',in_progress:'In progress','in progress':'In progress','in-progress':'In progress',in_progress_status:'In progress',done:'Done',completed:'Completed',complete:'Complete',closed:'Closed',active:'Active',pending:'Pending',review:'In review',approved:'Approved',rejected:'Rejected',archived:'Archived',not_set:'Not set'}};
|
||||
var MODULE_CONFIG=__SHD_WIDGET_CONFIG__;
|
||||
@@ -31,6 +33,7 @@ __SHD_WIDGET_ACTIONS_CSS__
|
||||
var S=MODULE_CONFIG.defaults;
|
||||
var pending=new Map(),nextId=1,rows=[],state={module:DEFAULT_MODULE,config:Object.assign({},S[DEFAULT_MODULE]),lang:'ru',timezone:'',busy:false};
|
||||
var e={title:document.getElementById('title'),desc:document.getElementById('desc'),search:document.getElementById('search'),refresh:document.getElementById('refresh'),status:document.getElementById('status'),summary:document.getElementById('summary'),tableWrap:document.querySelector('.table-wrap'),visual:document.getElementById('visual'),rows:document.getElementById('rows'),empty:document.getElementById('empty'),details:document.getElementById('details'),detailTitle:document.getElementById('detail-title'),detailSub:document.getElementById('detail-sub'),grid:document.getElementById('grid'),close:document.getElementById('close'),ht:document.getElementById('head-title'),hs:document.getElementById('head-status'),hd:document.getElementById('head-date'),hv:document.getElementById('head-value')};
|
||||
var g={controls:document.getElementById('airbase-grid-controls'),filterField:document.getElementById('airbase-filter-field'),filterValue:document.getElementById('airbase-filter-value'),sortField:document.getElementById('airbase-sort-field'),sortDirection:document.getElementById('airbase-sort-direction'),clear:document.getElementById('airbase-clear-filters'),header:document.querySelector('.table-wrap thead tr')},gridState={filterKey:'',filterValue:'',sortKey:'title',direction:'asc'};
|
||||
function lang(){var x=typeof window!=='undefined'&&window.openai&&window.openai.locale;x=String(x||document.documentElement.lang||'ru').toLowerCase();return x.indexOf('en')===0?'en':'ru'}
|
||||
function t(k){return(C[state.lang]||C.ru)[k]||k}
|
||||
function obj(x){return x&&typeof x==='object'&&!Array.isArray(x)}
|
||||
@@ -53,6 +56,12 @@ __SHD_WIDGET_ACTIONS_CSS__
|
||||
function value(x){if(!x)return'';if(x.availability_percent!==undefined&&x.availability_percent!==null)return str(x.availability_percent)+'%';if(x.quantity!==undefined&&x.quantity!==null)return str(x.quantity);if(x.record_count!==undefined&&x.record_count!==null)return str(x.record_count);return str(x.value!==undefined?x.value:(x.guest_name||x.space_name||x.group_name||x.controller_type||x.type||x.source||x.module||''))}
|
||||
function sub(x){return str(x&&(x.subtitle||x.project_code||x.space_name||x.channel_name||x.group_name||x.code||x.email))}
|
||||
function normalize(x,i){var y=obj(x)?Object.assign({},x):{value:x};y.id=id(x,i);y.title=title(x,i);y.subtitle=sub(x);y.status=status(x);y.date=date(x);y.value=value(x);return y}
|
||||
function airBaseValues(x){if(obj(x&&x.values))return x.values;if(obj(x&&x.cells))return x.cells;if(obj(x&&x.fields))return x.fields;var values={};Object.keys(x||{}).forEach(function(key){if(['id','title','subtitle','status','date','value','meta','record_id','table_id','table_code','created_at','updated_at'].indexOf(key)===-1)values[key]=x[key]});return values}
|
||||
function airBaseKeys(){var found={};rows.forEach(function(record){Object.keys(airBaseValues(record)).forEach(function(key){found[key]=true})});return Object.keys(found)}
|
||||
function fillSelect(select,keys,selected,includeAll){select.replaceChildren();if(includeAll){var all=make('option',G[state.lang].allFields);all.value='';select.append(all)}keys.forEach(function(key){var option=make('option',fieldLabel(key));option.value=key;select.append(option)});select.value=keys.indexOf(selected)!==-1||(!includeAll&&selected==='')?selected:(includeAll?'':(keys[0]||''))}
|
||||
function updateSortDirection(){g.sortDirection.textContent=gridState.direction==='asc'?G[state.lang].ascending:G[state.lang].descending;g.sortDirection.setAttribute('aria-label',g.sortDirection.textContent)}
|
||||
function updateGridControls(){var enabled=state.module==='airbase-grid';g.controls.hidden=!enabled;if(!enabled)return;var keys=airBaseKeys(),sortKeys=['title','id'].concat(keys.filter(function(key){return key!=='title'&&key!=='id'}));if(keys.indexOf(gridState.filterKey)===-1)gridState.filterKey='';if(sortKeys.indexOf(gridState.sortKey)===-1)gridState.sortKey=keys[0]||'title';fillSelect(g.filterField,keys,gridState.filterKey,true);fillSelect(g.sortField,sortKeys,gridState.sortKey,false);g.filterValue.value=gridState.filterValue;g.filterField.setAttribute('aria-label',G[state.lang].filterField);g.filterValue.placeholder=G[state.lang].filterValue;g.sortField.setAttribute('aria-label',G[state.lang].sortField);g.clear.textContent=G[state.lang].clear;updateSortDirection()}
|
||||
function airBaseCellValue(record,key){if(key==='title')return record.title;if(key==='id')return record.id;return airBaseValues(record)[key]}
|
||||
function dateOnlyText(raw){var parts=raw.split('-').map(Number);if(parts.length!==3||parts.some(function(part){return!Number.isFinite(part)}))return null;var date=new Date(Date.UTC(parts[0],parts[1]-1,parts[2],12));try{return new Intl.DateTimeFormat(state.lang,{dateStyle:'medium',timeZone:'UTC'}).format(date)}catch(err){return null}}
|
||||
function dateText(x){if(x===null||x===undefined||x==='')return'—';var n;if(x instanceof Date)n=x.getTime();else if(typeof x==='number')n=Math.abs(x)<100000000000?x*1000:x;else{var raw=String(x).trim();if(/^\d{4}-\d{2}-\d{2}$/.test(raw)){var only=dateOnlyText(raw);if(only)return only}var numeric=Number(raw);n=raw!==''&&Number.isFinite(numeric)?(Math.abs(numeric)<100000000000?numeric*1000:numeric):Date.parse(raw);if(Number.isNaN(n)&&raw)n=Date.parse(raw.replace(/([+-]\d{2}):(\d{2})$/,'$1$2'))}if(!Number.isFinite(n))return String(x);var options={dateStyle:'medium',timeStyle:'medium'};if(state.timezone)options.timeZone=state.timezone;try{return new Intl.DateTimeFormat(state.lang,options).format(new Date(n))}catch(err){return String(x)}}
|
||||
function make(tag,v,cls){var n=document.createElement(tag);if(cls)n.className=cls;if(v!==undefined)n.textContent=v;return n}
|
||||
@@ -87,8 +96,8 @@ __SHD_WIDGET_ACTIONS_CSS__
|
||||
function renderTree(a){if(!a.length){visualEmpty();return}var by={};a.forEach(function(x,i){var p=treeParent(x);(by[p]||(by[p]=[])).push({x:x,i:i})});var tree=make('div',undefined,'tree');function branch(parent,host,seen){(by[parent]||[]).forEach(function(entry){var id=treeId(entry.x,entry.i);if(seen[id])return;var wrap=make('div',undefined,'tree-node');wrap.append(visualCard(entry.x));host.append(wrap);var child=make('div',undefined,'tree-children');branch(id,child,Object.assign({},seen,(function(){var o={};o[id]=true;return o})()));if(child.childNodes.length)wrap.append(child)})}branch('',tree,{});if(!tree.childNodes.length)a.forEach(function(x){tree.append(visualCard(x))});e.visual.append(tree)}
|
||||
function renderPreview(a){if(!a.length){visualEmpty();return}var grid=make('div',undefined,'preview-grid');a.forEach(function(x){var card=interactiveRecord(make('article',undefined,'preview-card'),x);card.append(make('strong',x.title||'SHD','visual-title'));var fields=make('div',undefined,'preview-fields');Object.keys(x).filter(function(k){return['id','title','subtitle','status','date','value','meta'].indexOf(k)===-1}).slice(0,10).forEach(function(k){var cell=make('div',undefined,'preview-field');cell.append(make('strong',fieldLabel(k)+': '),make('span',detailText(x[k],k)));fields.append(cell)});card.append(fields);card.onclick=function(){details(x)};grid.append(card)});e.visual.append(grid)}
|
||||
function renderVisual(a){e.visual.replaceChildren();var v=state.config.view||'table';if(v==='kanban')renderKanban(a);else if(v==='workload'||v==='dashboard')renderDashboard(a,v);else if(v==='timeline')renderTimeline(a);else if(v==='funnel')renderFunnel(a);else if(v==='approval')renderStatusSummary(a,['approval_status','approval_state']);else if(v==='completeness'||v==='progress')renderProgress(a);else if(v==='health')renderStatusSummary(a,['health','status']);else if(v==='calendar')renderCalendar(a);else if(v==='matrix')renderMatrix(a);else if(v==='warnings')renderWarnings(a);else if(v==='tree')renderTree(a);else if(v==='preview')renderPreview(a);else renderDashboard(a,'dashboard')}
|
||||
function renderTable(a){e.rows.replaceChildren();e.empty.hidden=a.length!==0;a.forEach(function(x){var r=document.createElement('tr');r.className='record';recordAttrs(r,x);r.tabIndex=0;r.setAttribute('role','button');r.setAttribute('aria-label',x.title);var n=make('td');n.append(make('span',x.title,'title'));if(x.subtitle)n.append(make('span',x.subtitle,'sub'));var s=make('span',detailText(x.status,'status'),'pill');if(x.status)s.classList.add(String(x.status).toLowerCase().replace(/[^a-z0-9_-]+/g,'-'));var sc=make('td');sc.append(s);r.append(n,sc,make('td',dateText(x.date)),make('td',detailText(x.value,'value')));r.onclick=function(){details(x)};r.onkeydown=function(ev){if(ev.key==='Enter'||ev.key===' '){ev.preventDefault();details(x)}};e.rows.append(r)});renderSummary()}
|
||||
function renderRows(){var q=e.search.value.trim().toLowerCase(),a=rows.filter(function(x){return!q||[x.title,x.subtitle,x.status,x.id,x.value].map(str).join(' ').toLowerCase().indexOf(q)!==-1});if(state.config.view&&state.config.view!=='table'){e.tableWrap.hidden=true;e.visual.hidden=false;e.empty.hidden=true;renderVisual(a);renderSummary();return}e.tableWrap.hidden=false;e.visual.hidden=true;renderTable(a)}
|
||||
function renderTable(a){var grid=state.module==='airbase-grid',keys=grid?airBaseKeys():[];e.rows.replaceChildren();e.empty.hidden=a.length!==0;[e.ht,e.hs,e.hd,e.hv].forEach(function(head){head.hidden=grid});Array.prototype.forEach.call(g.header.querySelectorAll('[data-grid-head]'),function(head){head.remove()});if(grid){var first=make('th',G[state.lang].record);first.dataset.gridHead='true';g.header.append(first);keys.forEach(function(key){var head=make('th',fieldLabel(key));head.dataset.gridHead='true';g.header.append(head)})}a.forEach(function(x){var r=document.createElement('tr');r.className='record';recordAttrs(r,x);r.tabIndex=0;r.setAttribute('role','button');r.setAttribute('aria-label',x.title);var n=make('td');n.append(make('span',x.title,'title'));if(x.subtitle)n.append(make('span',x.subtitle,'sub'));if(grid){r.append(n);var values=airBaseValues(x);keys.forEach(function(key){r.append(make('td',detailText(values[key],key)))});}else{var s=make('span',detailText(x.status,'status'),'pill');if(x.status)s.classList.add(String(x.status).toLowerCase().replace(/[^a-z0-9_-]+/g,'-'));var sc=make('td');sc.append(s);r.append(n,sc,make('td',dateText(x.date)),make('td',detailText(x.value,'value')))}r.onclick=function(){details(x)};r.onkeydown=function(ev){if(ev.key==='Enter'||ev.key===' '){ev.preventDefault();details(x)}};e.rows.append(r)});renderSummary()}
|
||||
function renderRows(){updateGridControls();var q=e.search.value.trim().toLowerCase(),grid=state.module==='airbase-grid',filterKey=g.filterField.value,filterValue=g.filterValue.value.trim().toLowerCase(),a=rows.filter(function(x){var cells=airBaseValues(x),allValues=[x.title,x.subtitle,x.status,x.id,x.value].concat(Object.keys(cells).map(function(key){return cells[key]}));var matchesSearch=!q||allValues.map(str).join(' ').toLowerCase().indexOf(q)!==-1;if(!matchesSearch)return false;if(!grid||filterValue==='')return true;var values=filterKey?[airBaseCellValue(x,filterKey)]:Object.keys(cells).map(function(key){return cells[key]});return values.map(str).join(' ').toLowerCase().indexOf(filterValue)!==-1});if(grid){var sortKey=g.sortField.value||'title',direction=gridState.direction==='asc'?1:-1;a.sort(function(left,right){var lv=airBaseCellValue(left,sortKey),rv=airBaseCellValue(right,sortKey),ln=Number(lv),rn=Number(rv);if(lv!==''&&rv!==''&&Number.isFinite(ln)&&Number.isFinite(rn)&&ln!==rn)return(ln-rn)*direction;return str(lv).localeCompare(str(rv),state.lang,{numeric:true,sensitivity:'base'})*direction})}if(state.config.view&&state.config.view!=='table'){e.tableWrap.hidden=true;e.visual.hidden=false;e.empty.hidden=true;renderVisual(a);renderSummary();return}e.tableWrap.hidden=false;e.visual.hidden=true;renderTable(a)}
|
||||
function setTimezone(p){var source=payload(p)||{},data=source.data!==undefined?source.data:source,timezone=data&&data.timezone||source.timezone;if(typeof timezone==='string'&&timezone)state.timezone=timezone}
|
||||
function render(x){var p=unwrap(x);applyConfig(p);setTimezone(p);rows=list(p).map(normalize);var dir=state.config.sort==='asc'?1:-1;rows.sort(function(a,b){var x=Date.parse(a.date),y=Date.parse(b.date);if(!Number.isNaN(x)&&!Number.isNaN(y)&&x!==y)return(x-y)*dir;return a.title.localeCompare(b.title,state.lang)*dir});window.__SHD_WIDGET_STATE__=p;renderRows();window.dispatchEvent(new CustomEvent('shd-widget-data',{detail:p}))}
|
||||
function setStatus(x,bad){e.status.textContent=x||'';e.status.className=bad?'status error':'status'}
|
||||
@@ -98,6 +107,7 @@ __SHD_WIDGET_ACTIONS_CSS__
|
||||
function contextReady(a){if(!state.config.contextRequired)return true;if(Array.isArray(state.config.contextSets)&&state.config.contextSets.length)return state.config.contextSets.every(function(set){return set.some(function(k){return a[k]!==undefined&&a[k]!==null&&a[k]!==''})});var keys=Array.isArray(state.config.contextKeys)&&state.config.contextKeys.length?state.config.contextKeys:['base','project_code','project'];var ready=state.config.contextAll?keys.every(function(k){return a[k]!==undefined&&a[k]!==null&&a[k]!==''}):keys.some(function(k){return a[k]!==undefined&&a[k]!==null&&a[k]!==''});return ready}
|
||||
function refresh(){if(state.busy)return;var a=merge(state.config.listArgs,state.config.sourceArgs);if(!contextReady(a)){setStatus(t('context'),true);return}if(!state.config.listTool)return;state.busy=true;e.refresh.disabled=true;setStatus(t('loading'),false);req('tools/call',{name:state.config.listTool,arguments:a}).then(function(x){render(x);setStatus('',false)}).catch(function(err){setStatus(err.message||t('load'),true)}).finally(function(){state.busy=false;e.refresh.disabled=false})}
|
||||
function init(){return req('ui/initialize',{protocolVersion:'2026-01-26',appInfo:{name:'SHD '+(M[state.module]||M.discussions).ru[0],title:'SHD MCP',version:'1.0.0',websiteUrl:'https://shd.xyz.su'},appCapabilities:{}}).then(function(){notify('ui/notifications/initialized',{})}).catch(function(){})}
|
||||
g.filterField.onchange=function(){gridState.filterKey=g.filterField.value;renderRows()};g.filterValue.oninput=function(){gridState.filterValue=g.filterValue.value;renderRows()};g.sortField.onchange=function(){gridState.sortKey=g.sortField.value;renderRows()};g.sortDirection.onclick=function(){gridState.direction=gridState.direction==='asc'?'desc':'asc';renderRows()};g.clear.onclick=function(){gridState.filterKey='';gridState.filterValue='';e.search.value='';renderRows()};
|
||||
window.addEventListener('message',function(ev){if(ev.source!==window.parent)return;var m=ev.data;if(!m||m.jsonrpc!=='2.0')return;if(m.id!==undefined&&pending.has(m.id)){var q=pending.get(m.id);pending.delete(m.id);window.clearTimeout(q.timeout);if(m.error)q.reject(Error(m.error.message||t('load')));else q.resolve(m.result);return}if(m.method==='ui/notifications/tool-input'&&!rows.length){try{render(m.params||{})}catch(err){setStatus(err.message||t('load'),true)}}if(m.method==='ui/notifications/tool-result'){try{render(m.params&&m.params.structuredContent)}catch(err){setStatus(err.message||t('load'),true)}}},{passive:true});
|
||||
e.search.oninput=renderRows;e.refresh.onclick=refresh;e.close.onclick=function(){e.details.hidden=true};state.lang=lang();labels();void init();var out=typeof window!=='undefined'&&window.openai?window.openai.toolOutput:null;if(out){try{render(out)}catch(err){setStatus(err.message||t('load'),true)}}else{var input=typeof window!=='undefined'&&window.openai?window.openai.toolInput:null;if(input){try{render(input)}catch(err){setStatus(err.message||t('load'),true)}}else refresh()}
|
||||
}());
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"name": "shd-airbase-grid",
|
||||
"version": "1.0.0",
|
||||
"resources": [
|
||||
{
|
||||
"file": "index.html",
|
||||
"mediaType": "text/html;profile=mcp-app",
|
||||
"uri": "ui://shd/airbase-grid/v1.html"
|
||||
}
|
||||
],
|
||||
"license": "../../../../../LICENSE",
|
||||
"source": {
|
||||
"repository": "https://github.com/bulava92/shd-mcp-plugin"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user