codicent-app-sdk 0.6.6 → 0.6.8
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/dist/cjs/components/ListView.d.ts.map +1 -1
- package/dist/cjs/components/ListView.js +1 -1
- package/dist/cjs/components/RecordModal.d.ts.map +1 -1
- package/dist/cjs/components/RecordModal.js +1 -1
- package/dist/cjs/pages/ListPage.d.ts +49 -0
- package/dist/cjs/pages/ListPage.d.ts.map +1 -1
- package/dist/cjs/pages/ListPage.js +1 -1
- package/dist/esm/components/ListView.d.ts.map +1 -1
- package/dist/esm/components/ListView.js +1 -1
- package/dist/esm/components/RecordModal.d.ts.map +1 -1
- package/dist/esm/components/RecordModal.js +1 -1
- package/dist/esm/pages/ListPage.d.ts +49 -0
- package/dist/esm/pages/ListPage.d.ts.map +1 -1
- package/dist/esm/pages/ListPage.js +1 -1
- package/dist/index.d.ts +49 -0
- package/package.json +2 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ListView.d.ts","sourceRoot":"","sources":["../../../src/components/ListView.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAuC,MAAM,OAAO,CAAC;AAmB5D,uEAAuE;AACvE,MAAM,WAAW,YAAY;IAC3B,kHAAkH;IAClH,IAAI,EAAE,KAAK,CAAC,aAAa,CAAC;IAC1B,uCAAuC;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IACpD,oFAAoF;IACpF,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;
|
|
1
|
+
{"version":3,"file":"ListView.d.ts","sourceRoot":"","sources":["../../../src/components/ListView.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAuC,MAAM,OAAO,CAAC;AAmB5D,uEAAuE;AACvE,MAAM,WAAW,YAAY;IAC3B,kHAAkH;IAClH,IAAI,EAAE,KAAK,CAAC,aAAa,CAAC;IAC1B,uCAAuC;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IACpD,oFAAoF;IACpF,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AA+ND,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,UAAU,GAAG,MAAM,GAAG,UAAU,GAAG,WAAW,GAAG,SAAS,CAAC;IACxF,oDAAoD;IACpD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0DAA0D;IAC1D,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,2HAA2H;IAC3H,iBAAiB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9D,wFAAwF;IACxF,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,kFAAkF;IAClF,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gHAAgH;IAChH,WAAW,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IAC7B,2HAA2H;IAC3H,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,oIAAoI;IACpI,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC;CACrC;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAChC,OAAO,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAChE,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClE,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAChH,oBAAoB,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,IAAI,CAAC;CAC1E;AA6ID,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CA+iB5C,CAAC;;AAGF,wBAAoC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react/jsx-runtime"),t=require("react"),n=require("@fluentui/react-components"),i=require("@fluentui/react-icons"),r=require("../services/codicent.js"),a=require("../hooks/useLocalization.js");const o=n.makeStyles({container:{width:"100%",overflowX:"auto",userSelect:"text"},table:{width:"100%",borderCollapse:"collapse",backgroundColor:"#ffffff",fontSize:"14px",tableLayout:"fixed",userSelect:"text"},th:{textAlign:"left",padding:"12px 8px",borderBottom:"2px solid #e0e0e0",fontWeight:"600",backgroundColor:"#f5f5f5",position:"sticky",top:0,zIndex:1,cursor:"pointer",userSelect:"none","&:hover":{backgroundColor:"#e8e8e8"}},td:{padding:"12px 8px",borderBottom:"1px solid #e0e0e0",verticalAlign:"top",wordWrap:"break-word",overflow:"hidden",userSelect:"text"},tdTruncated:{overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap","@media (hover: none)":{cursor:"pointer"}},tr:{"&:hover":{backgroundColor:"#f9f9f9"}},emptyState:{padding:"20px",textAlign:"center",color:"#666"},sortIndicator:{marginLeft:"4px",fontSize:"10px"},hideOnMobile:{"@media (max-width: 768px)":{display:"none"}},dialogContent:{wordWrap:"break-word",whiteSpace:"pre-wrap",maxHeight:"60vh",overflowY:"auto"},thumbnail:{maxWidth:"50px",maxHeight:"50px",objectFit:"cover"},tooltip:{maxWidth:"600px",whiteSpace:"normal",wordWrap:"break-word"},editButton:{minWidth:"auto",padding:"4px 8px"},actionsColumn:{width:"100px",textAlign:"center"},filterInput:{width:"100%",padding:"4px 8px",fontSize:"14px",border:"1px solid #e0e0e0",borderRadius:"4px",paddingRight:"28px"},filterWrapper:{position:"relative"},clearFilterButton:{position:"absolute",right:"6px",top:"50%",transform:"translateY(-50%)",minWidth:"auto",height:"20px",padding:"0 6px",lineHeight:"18px"},filterToolbar:{display:"flex",justifyContent:"flex-end",padding:"8px",gap:"8px"},cellWithAction:{display:"flex",alignItems:"center",justifyContent:"space-between",gap:"4px"},actionIcon:{minWidth:"auto",padding:"2px",marginLeft:"4px",flexShrink:0,cursor:"pointer",opacity:.7,"&:hover":{opacity:1}},thumbnailRow:{display:"flex",gap:"4px",flexWrap:"wrap"},cellText:{flex:1,overflow:"hidden",textOverflow:"ellipsis"}}),l=e=>{if(/^\d{4}-\d{2}-\d{2}/.test(e)){const t=new Date(e);if(!isNaN(t.getTime()))return t.getTime()}const t=e.match(/^(\d{1,2})\.(\d{1,2})\.(\d{4})/);if(t){const e=parseInt(t[1],10),n=parseInt(t[2],10)-1,i=parseInt(t[3],10),r=new Date(i,n,e);if(r.getFullYear()===i&&r.getMonth()===n&&r.getDate()===e)return r.getTime()}return null},s=(e,t)=>{if("string"==typeof t)return e[t];for(const n of t)if(void 0!==e[n])return e[n]},c=n.makeStyles({img:{maxWidth:"40px",maxHeight:"40px",objectFit:"cover",borderRadius:"3px",display:"block"},fileIcon:{width:"24px",height:"24px",verticalAlign:"middle"}}),d=({fileId:n})=>{const[a,o]=t.useState(!0),l=c();return e.jsx("a",{href:r.CodicentService.getFileUrl(n),target:"_blank",rel:"noopener noreferrer",children:a?e.jsx("img",{src:r.CodicentService.getImageUrl(n,40),alt:"",className:l.img,onError:()=>o(!1)}):e.jsx(i.Attach24Regular,{className:l.fileIcon})})},p=({value:i,options:r,optionsLoader:a,minChars:o=2,maxResults:l=50,columnKey:s,item:c,actualIndex:d,onEnumChange:p,label:u,t:h})=>{const[x,m]=t.useState(i),[f,g]=t.useState([]),[y,j]=t.useState(!1),b=t.useRef(null);t.useEffect((()=>{m(i)}),[i]),t.useEffect((()=>{if(a){if(!(x.length<o))return b.current&&clearTimeout(b.current),b.current=setTimeout((async()=>{j(!0);try{const e=await a(x);g(e.slice(0,l))}finally{j(!1)}}),250),()=>{b.current&&clearTimeout(b.current)};g([])}}),[x,a,o,l]);const v=t.useMemo((()=>(r??[]).filter((e=>e.toLowerCase().includes(x.toLowerCase()))).slice(0,l)),[r,x,l]),C=a?f:v;return e.jsx(n.Combobox,{value:x,freeform:!0,"aria-label":u,placeholder:y?h("Loading..."):a&&x.length<o?h(`Type ${o}+ characters to search...`):void 0,onChange:e=>m(e.target.value),onOptionSelect:(e,t)=>{t.optionValue&&(m(t.optionValue),p&&p(c,s,t.optionValue,d))},onBlur:()=>{p&&p(c,s,x,d)},style:{width:"100%"},children:C.map((t=>e.jsx(n.Option,{value:t,children:t},t)))})},u=({data:c,columns:u,canEdit:h,onEdit:x,onDelete:m,onToggleCheckbox:f,onEnumChange:g,onFilteredDataChange:y})=>{const j=o(),{visibleColumns:b,defaultSortIndex:v,defaultSortDirection:C}=t.useMemo((()=>{const e=c&&c.length>0?Array.from(new Set(c.flatMap((e=>Object.keys(e))))):[],t=(u||e.map((e=>({key:e})))).filter((e=>!e.hidden)),n=t.findIndex((e=>e.defaultSort));return{visibleColumns:t,defaultSortIndex:n,defaultSortDirection:n>=0&&t[n].defaultSort||null}}),[c,u]),[w,S]=t.useState(v>=0?v:null),[k,N]=t.useState(C),[W,O]=t.useState(!1),[I,A]=t.useState({title:"",text:""}),[$,L]=t.useState({}),[M,T]=t.useState(0),{t:D}=a.default(),F=e=>e.title?D(e.title):Array.isArray(e.key)?e.key[0]:e.key,B=e=>{const t=[];return e.hideOnMobile&&t.push(j.hideOnMobile),t.join(" ")},R=(e,t)=>{L((n=>{const i={...n};return""===t.trim()?delete i[e]:i[e]=t,i}))},E=e=>null==e||"string"==typeof e&&e.startsWith("[")&&e.endsWith("]")?"":"object"==typeof e?JSON.stringify(e):String(e),q=t.useMemo((()=>{const e=[...c];if(null!==w&&k){const t=b[w];e.sort(((e,n)=>{const i=s(e,t.key),r=s(n,t.key);if(null==i)return 1;if(null==r)return-1;let a=0;if("string"==typeof i&&"string"==typeof r){const e=l(i),t=l(r);if(null!==e&&null!==t)a=e-t;else{const e=i.trim().replace(/[\s\u00a0]/g,"").replace(/,/g,""),t=r.trim().replace(/[\s\u00a0]/g,"").replace(/,/g,""),n=Number(e),o=Number(t);a=""!==e&&""!==t&&isFinite(n)&&isFinite(o)?n-o:i.localeCompare(r)}}else if("number"==typeof i&&"number"==typeof r)a=i-r;else{const e=Number(String(i).trim().replace(/[\s\u00a0]/g,"").replace(/,/g,"")),t=Number(String(r).trim().replace(/[\s\u00a0]/g,"").replace(/,/g,""));a=isFinite(e)&&isFinite(t)?e-t:String(i).localeCompare(String(r))}return"asc"===k?a:-a}))}return e}),[c,w,k,b]),z=t.useMemo((()=>q.filter((e=>{for(const[t,n]of Object.entries($)){const i=parseInt(t),r=b[i],a=s(e,r.key),o=E(a).toLowerCase(),l=n.toLowerCase();if(!("enum"===r.type&&r.enumOptions?o===l:o.includes(l)))return!1}return!0}))),[q,$,b]);t.useEffect((()=>{y&&y(z)}),[z,y]);const H="undefined"!=typeof window?window.innerHeight-250:600,P=Math.max(0,Math.floor(M/49)-5),_=Math.min(z.length,Math.ceil((M+H)/49)+5),V=z.slice(P,_),Y=49*z.length,U=49*P,K=(e,t)=>{if(void 0!==e.id)return String(e.id);return`row-${t}-${(e=>{let t=0;for(let n=0;n<e.length;n++)t=(t<<5)-t+e.charCodeAt(n),t|=0;return Math.abs(t)})(b.slice(0,3).map((t=>String(s(e,t.key)??""))).join("-"))}`};return c&&0!==c.length?e.jsxs(e.Fragment,{children:[e.jsx("div",{className:j.container,onScroll:e=>{T(e.currentTarget.scrollTop)},style:{maxHeight:"calc(100vh - 200px)",overflowY:"auto"},children:e.jsxs("table",{className:j.table,children:[e.jsxs("thead",{children:[e.jsxs("tr",{children:[b.map(((t,n)=>{const i=t.maxWidth?{width:`${t.maxWidth}px`,maxWidth:`${t.maxWidth}px`}:{};return e.jsxs("th",{className:`${j.th} ${B(t)}`.trim(),style:i,onClick:()=>(e=>{w===e?"asc"===k?N("desc"):"desc"===k&&(S(null),N(null)):(S(e),N("asc"))})(n),children:[F(t),w===n&&e.jsx("span",{className:j.sortIndicator,children:"asc"===k?"▲":"▼"})]},n)})),h&&e.jsx("th",{className:`${j.th} ${j.actionsColumn}`,style:{width:"100px"},children:D("Actions")})]}),e.jsxs("tr",{children:[b.map(((t,i)=>{const r=t.maxWidth?{width:`${t.maxWidth}px`,maxWidth:`${t.maxWidth}px`}:{};return e.jsx("th",{className:B(t),style:r,children:t.filterable&&e.jsx("div",{className:j.filterWrapper,children:"enum"===t.type&&t.enumOptions?e.jsxs(n.Select,{className:j.filterInput,value:$[i]||"",onChange:(e,t)=>R(i,t.value),onClick:e=>e.stopPropagation(),children:[e.jsx("option",{value:"",children:D("All")}),t.enumOptions.filter((e=>""!==e)).map((t=>e.jsx("option",{value:t,children:D(t)},t)))]}):e.jsxs(e.Fragment,{children:[e.jsx("input",{type:"text",className:j.filterInput,placeholder:D("Filter")+"...",value:$[i]||"",onChange:e=>R(i,e.target.value),onClick:e=>e.stopPropagation()}),($[i]||"").length>0&&e.jsx(n.Button,{appearance:"subtle",className:j.clearFilterButton,onClick:e=>{e.stopPropagation(),(e=>{L((t=>{const n={...t};return delete n[e],n}))})(i)},children:"×"})]})})},i)})),h&&e.jsx("th",{className:j.actionsColumn})]})]}),e.jsxs("tbody",{children:[P>0&&e.jsx("tr",{style:{height:`${U}px`},children:e.jsx("td",{colSpan:b.length+(h?1:0),style:{padding:0,border:"none"}})}),V.map(((t,a)=>{const o=t._index,l="number"==typeof o?o:P+a;return e.jsxs("tr",{className:j.tr,children:[b.map(((i,a)=>{const o=s(t,i.key),c=i.format?i.format(o):E(o),u=i.maxWidth?`${j.td} ${j.tdTruncated} ${B(i)}`.trim():`${j.td} ${B(i)}`.trim(),h=()=>{window.matchMedia("(hover: hover)").matches||i.maxWidth&&c.length>0&&(A({title:F(i),text:c}),O(!0))};if("thumbnail"===i.type){const t=Array.isArray(o)?o:[];return e.jsx("td",{className:u,children:e.jsx("div",{className:j.thumbnailRow,children:t.map((t=>e.jsx(d,{fileId:t},t)))})},a)}if("file"===i.type&&c)return e.jsx("td",{className:u,onClick:h,children:e.jsx("a",{href:r.CodicentService.getFileUrl(c),target:"_blank",rel:"noopener noreferrer",children:D("Download")})},a);if("checkbox"===i.type){const r=!0===o||"true"===o||"yes"===o||"1"===o;return e.jsx("td",{className:u,children:e.jsx(n.Checkbox,{checked:r,onChange:(e,n)=>{f&&f(t,i.key,!0===n.checked,l)}})},a)}if("enum"===i.type&&i.enumOptions&&i.editable)return e.jsx("td",{className:u,children:e.jsxs(n.Select,{value:c,"aria-label":i.title?D(i.title):Array.isArray(i.key)?i.key[0]:i.key,onChange:(e,n)=>{g&&g(t,i.key,n.value,l)},style:{width:"100%"},children:[!i.enumOptions.includes(c)&&c&&e.jsx("option",{value:c,children:c}),i.enumOptions.map((t=>e.jsx("option",{value:t,children:D(t)},t)))]})},a);if("combobox"===i.type&&i.editable&&(i.enumOptions||i.enumOptionsLoader))return e.jsx("td",{className:u,children:e.jsx(p,{value:c,options:i.enumOptions,optionsLoader:i.enumOptionsLoader,minChars:i.enumOptionsLoaderMinChars,maxResults:i.enumOptionsLoaderMaxResults,columnKey:i.key,item:t,actualIndex:l,onEnumChange:g,label:i.title?D(i.title):Array.isArray(i.key)?i.key[0]:i.key,t:D})},a);const x=()=>i.maxWidth&&c.length>0?e.jsx(n.Tooltip,{content:{children:c,style:{maxWidth:"600px",whiteSpace:"normal"}},relationship:"description",children:e.jsx("span",{children:c})}):c,m=()=>{if(!i.action)return null;const r=i.action,a=i.action.icon,o=e.jsx(n.Button,{appearance:"subtle",icon:e.jsx(a,{}),className:j.actionIcon,onClick:e=>{e.stopPropagation(),r.onClick(t)},size:"small"});return r.tooltip?e.jsx(n.Tooltip,{content:D(r.tooltip),relationship:"label",children:o}):o};return e.jsx("td",{className:u,onClick:h,children:i.action?e.jsxs("div",{className:j.cellWithAction,children:[i.action.iconLeft&&m(),e.jsx("span",{className:j.cellText,children:x()}),!i.action.iconLeft&&m()]}):x()},a)})),h&&(x||m)&&e.jsx("td",{className:`${j.td} ${j.actionsColumn}`,children:e.jsxs("div",{style:{display:"flex",gap:"4px",justifyContent:"center"},children:[x&&e.jsx(n.Button,{appearance:"subtle",icon:e.jsx(i.Edit24Regular,{}),className:j.editButton,onClick:()=>x(t,l),title:D("Edit")}),m&&e.jsx(n.Button,{appearance:"subtle",icon:e.jsx(i.Delete24Regular,{}),className:j.editButton,onClick:()=>m(t,l),title:D("Delete")})]})})]},K(t,l))})),_<z.length&&e.jsx("tr",{style:{height:Y-U-49*V.length+"px"},children:e.jsx("td",{colSpan:b.length+(h?1:0),style:{padding:0,border:"none"}})})]})]})}),e.jsx(n.Dialog,{open:W,onOpenChange:(e,t)=>O(t.open),children:e.jsx(n.DialogSurface,{children:e.jsxs(n.DialogBody,{children:[e.jsx(n.DialogTitle,{children:I.title}),e.jsx(n.DialogContent,{className:j.dialogContent,children:I.text})]})})})]}):e.jsx("div",{className:j.emptyState,children:D("No data to display")})};var h=t.memo(u);exports.ListView=u,exports.default=h;
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react/jsx-runtime"),t=require("react"),n=require("@fluentui/react-components"),i=require("@fluentui/react-icons"),r=require("../services/codicent.js"),l=require("../hooks/useLocalization.js");const o=n.makeStyles({container:{width:"100%",overflowX:"auto",userSelect:"text"},table:{width:"100%",borderCollapse:"collapse",backgroundColor:"#ffffff",fontSize:"14px",tableLayout:"fixed",userSelect:"text"},th:{textAlign:"left",padding:"12px 8px",borderBottom:"2px solid #e0e0e0",fontWeight:"600",backgroundColor:"#f5f5f5",position:"sticky",top:0,zIndex:1,cursor:"pointer",userSelect:"none","&:hover":{backgroundColor:"#e8e8e8"}},td:{padding:"12px 8px",borderBottom:"1px solid #e0e0e0",verticalAlign:"top",wordWrap:"break-word",overflow:"hidden",userSelect:"text"},tdTruncated:{overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap","@media (hover: none)":{cursor:"pointer"}},tr:{"&:hover":{backgroundColor:"#f9f9f9"}},emptyState:{padding:"20px",textAlign:"center",color:"#666"},sortIndicator:{marginLeft:"4px",fontSize:"10px"},hideOnMobile:{"@media (max-width: 768px)":{display:"none"}},dialogContent:{wordWrap:"break-word",whiteSpace:"pre-wrap",maxHeight:"60vh",overflowY:"auto"},thumbnail:{maxWidth:"50px",maxHeight:"50px",objectFit:"cover"},tooltip:{maxWidth:"600px",whiteSpace:"normal",wordWrap:"break-word"},editButton:{minWidth:"auto",padding:"4px 8px"},actionsColumn:{width:"100px",textAlign:"center"},filterInput:{width:"100%",padding:"4px 8px",fontSize:"14px",border:"1px solid #e0e0e0",borderRadius:"4px",paddingRight:"28px"},filterWrapper:{position:"relative"},clearFilterButton:{position:"absolute",right:"6px",top:"50%",transform:"translateY(-50%)",minWidth:"auto",height:"20px",padding:"0 6px",lineHeight:"18px"},filterToolbar:{display:"flex",justifyContent:"flex-end",padding:"8px",gap:"8px"},cellWithAction:{display:"flex",alignItems:"center",justifyContent:"space-between",gap:"4px"},actionIcon:{minWidth:"auto",padding:"2px",marginLeft:"4px",flexShrink:0,cursor:"pointer",opacity:.7,"&:hover":{opacity:1}},thumbnailRow:{display:"flex",gap:"4px",flexWrap:"wrap"},cellText:{flex:1,overflow:"hidden",textOverflow:"ellipsis"}}),a=e=>{if(/^\d{4}-\d{2}-\d{2}/.test(e)){const t=new Date(e);if(!isNaN(t.getTime()))return t.getTime()}const t=e.match(/^(\d{1,2})\.(\d{1,2})\.(\d{4})/);if(t){const e=parseInt(t[1],10),n=parseInt(t[2],10)-1,i=parseInt(t[3],10),r=new Date(i,n,e);if(r.getFullYear()===i&&r.getMonth()===n&&r.getDate()===e)return r.getTime()}return null},s=e=>{const t=e.trim().replace(/[\s\u00a0]/g,"");if(""===t||"-"===t)return null;const n=(t.match(/,/g)||[]).length,i=(t.match(/\./g)||[]).length;let r;r=1===n&&0===i?/,\d{1,2}$/.test(t)?t.replace(/,\d+$/,"").replace(/[^0-9-]/g,""):t.replace(/,/g,""):1===i&&0===n?/\.\d{1,2}$/.test(t)?t.replace(/\.\d+$/,"").replace(/[^0-9-]/g,""):t.replace(/\./g,""):t.replace(/[,.]/g,"");const l=Number(r);return""!==r&&isFinite(l)?l:null},c=(e,t)=>{if("string"==typeof t)return e[t];for(const n of t)if(void 0!==e[n])return e[n]},d=n.makeStyles({img:{maxWidth:"40px",maxHeight:"40px",objectFit:"cover",borderRadius:"3px",display:"block"},fileIcon:{width:"24px",height:"24px",verticalAlign:"middle"}}),p=({fileId:n})=>{const[l,o]=t.useState(!0),a=d();return e.jsx("a",{href:r.CodicentService.getFileUrl(n),target:"_blank",rel:"noopener noreferrer",children:l?e.jsx("img",{src:r.CodicentService.getImageUrl(n,40),alt:"",className:a.img,onError:()=>o(!1)}):e.jsx(i.Attach24Regular,{className:a.fileIcon})})},u=({value:i,options:r,optionsLoader:l,minChars:o=2,maxResults:a=50,columnKey:s,item:c,actualIndex:d,onEnumChange:p,label:u,t:h})=>{const[x,m]=t.useState(i),[f,g]=t.useState([]),[y,j]=t.useState(!1),b=t.useRef(null);t.useEffect((()=>{m(i)}),[i]),t.useEffect((()=>{if(l){if(!(x.length<o))return b.current&&clearTimeout(b.current),b.current=setTimeout((async()=>{j(!0);try{const e=await l(x);g(e.slice(0,a))}finally{j(!1)}}),250),()=>{b.current&&clearTimeout(b.current)};g([])}}),[x,l,o,a]);const v=t.useMemo((()=>(r??[]).filter((e=>e.toLowerCase().includes(x.toLowerCase()))).slice(0,a)),[r,x,a]),C=l?f:v;return e.jsx(n.Combobox,{value:x,freeform:!0,"aria-label":u,placeholder:y?h("Loading..."):l&&x.length<o?h(`Type ${o}+ characters to search...`):void 0,onChange:e=>m(e.target.value),onOptionSelect:(e,t)=>{t.optionValue&&(m(t.optionValue),p&&p(c,s,t.optionValue,d))},onBlur:()=>{p&&p(c,s,x,d)},style:{width:"100%"},children:C.map((t=>e.jsx(n.Option,{value:t,children:t},t)))})},h=({data:d,columns:h,canEdit:x,onEdit:m,onDelete:f,onToggleCheckbox:g,onEnumChange:y,onFilteredDataChange:j})=>{const b=o(),{visibleColumns:v,defaultSortIndex:C,defaultSortDirection:w}=t.useMemo((()=>{const e=d&&d.length>0?Array.from(new Set(d.flatMap((e=>Object.keys(e))))):[],t=(h||e.map((e=>({key:e})))).filter((e=>!e.hidden)),n=t.findIndex((e=>e.defaultSort));return{visibleColumns:t,defaultSortIndex:n,defaultSortDirection:n>=0&&t[n].defaultSort||null}}),[d,h]),[S,k]=t.useState(C>=0?C:null),[N,W]=t.useState(w),[O,I]=t.useState(!1),[$,A]=t.useState({title:"",text:""}),[L,M]=t.useState({}),[T,D]=t.useState(0),{t:B}=l.default(),F=e=>e.title?B(e.title):Array.isArray(e.key)?e.key[0]:e.key,R=e=>{const t=[];return e.hideOnMobile&&t.push(b.hideOnMobile),t.join(" ")},E=(e,t)=>{M((n=>{const i={...n};return""===t.trim()?delete i[e]:i[e]=t,i}))},q=e=>null==e||"string"==typeof e&&e.startsWith("[")&&e.endsWith("]")?"":"object"==typeof e?JSON.stringify(e):String(e),z=t.useMemo((()=>{const e=[...d];if(null!==S&&N){const t=v[S];e.sort(((e,n)=>{const i=c(e,t.key),r=c(n,t.key);if(null==i)return 1;if(null==r)return-1;let l=0;if("string"==typeof i&&"string"==typeof r){const e=a(i),t=a(r);if(null!==e&&null!==t)l=e-t;else{const e=s(i),t=s(r);l=null!==e&&null!==t?e-t:i.localeCompare(r)}}else if("number"==typeof i&&"number"==typeof r)l=i-r;else{const e=s(String(i)),t=s(String(r));l=null!==e&&null!==t?e-t:String(i).localeCompare(String(r))}return"asc"===N?l:-l}))}return e}),[d,S,N,v]),H=t.useMemo((()=>z.filter((e=>{for(const[t,n]of Object.entries(L)){const i=parseInt(t),r=v[i],l=c(e,r.key),o=q(l).toLowerCase(),a=n.toLowerCase();if(!("enum"===r.type&&r.enumOptions?o===a:o.includes(a)))return!1}return!0}))),[z,L,v]);t.useEffect((()=>{j&&j(H)}),[H,j]);const P="undefined"!=typeof window?window.innerHeight-250:600,_=Math.max(0,Math.floor(T/49)-5),V=Math.min(H.length,Math.ceil((T+P)/49)+5),Y=H.slice(_,V),U=49*H.length,K=49*_,J=(e,t)=>{if(void 0!==e.id)return String(e.id);return`row-${t}-${(e=>{let t=0;for(let n=0;n<e.length;n++)t=(t<<5)-t+e.charCodeAt(n),t|=0;return Math.abs(t)})(v.slice(0,3).map((t=>String(c(e,t.key)??""))).join("-"))}`};return d&&0!==d.length?e.jsxs(e.Fragment,{children:[e.jsx("div",{className:b.container,onScroll:e=>{D(e.currentTarget.scrollTop)},style:{maxHeight:"calc(100vh - 200px)",overflowY:"auto"},children:e.jsxs("table",{className:b.table,children:[e.jsxs("thead",{children:[e.jsxs("tr",{children:[v.map(((t,n)=>{const i=t.maxWidth?{width:`${t.maxWidth}px`,maxWidth:`${t.maxWidth}px`}:{};return e.jsxs("th",{className:`${b.th} ${R(t)}`.trim(),style:i,onClick:()=>(e=>{S===e?"asc"===N?W("desc"):"desc"===N&&(k(null),W(null)):(k(e),W("asc"))})(n),children:[F(t),S===n&&e.jsx("span",{className:b.sortIndicator,children:"asc"===N?"▲":"▼"})]},n)})),x&&e.jsx("th",{className:`${b.th} ${b.actionsColumn}`,style:{width:"100px"},children:B("Actions")})]}),e.jsxs("tr",{children:[v.map(((t,i)=>{const r=t.maxWidth?{width:`${t.maxWidth}px`,maxWidth:`${t.maxWidth}px`}:{};return e.jsx("th",{className:R(t),style:r,children:t.filterable&&e.jsx("div",{className:b.filterWrapper,children:"enum"===t.type&&t.enumOptions?e.jsxs(n.Select,{className:b.filterInput,value:L[i]||"",onChange:(e,t)=>E(i,t.value),onClick:e=>e.stopPropagation(),children:[e.jsx("option",{value:"",children:B("All")}),t.enumOptions.filter((e=>""!==e)).map((t=>e.jsx("option",{value:t,children:B(t)},t)))]}):e.jsxs(e.Fragment,{children:[e.jsx("input",{type:"text",className:b.filterInput,placeholder:B("Filter")+"...",value:L[i]||"",onChange:e=>E(i,e.target.value),onClick:e=>e.stopPropagation()}),(L[i]||"").length>0&&e.jsx(n.Button,{appearance:"subtle",className:b.clearFilterButton,onClick:e=>{e.stopPropagation(),(e=>{M((t=>{const n={...t};return delete n[e],n}))})(i)},children:"×"})]})})},i)})),x&&e.jsx("th",{className:b.actionsColumn})]})]}),e.jsxs("tbody",{children:[_>0&&e.jsx("tr",{style:{height:`${K}px`},children:e.jsx("td",{colSpan:v.length+(x?1:0),style:{padding:0,border:"none"}})}),Y.map(((t,l)=>{const o=t._index,a="number"==typeof o?o:_+l;return e.jsxs("tr",{className:b.tr,children:[v.map(((i,l)=>{const o=c(t,i.key),s=i.format?i.format(o):q(o),d=i.maxWidth?`${b.td} ${b.tdTruncated} ${R(i)}`.trim():`${b.td} ${R(i)}`.trim(),h=()=>{window.matchMedia("(hover: hover)").matches||i.maxWidth&&s.length>0&&(A({title:F(i),text:s}),I(!0))};if("thumbnail"===i.type){const t=Array.isArray(o)?o:[];return e.jsx("td",{className:d,children:e.jsx("div",{className:b.thumbnailRow,children:t.map((t=>e.jsx(p,{fileId:t},t)))})},l)}if("file"===i.type&&s)return e.jsx("td",{className:d,onClick:h,children:e.jsx("a",{href:r.CodicentService.getFileUrl(s),target:"_blank",rel:"noopener noreferrer",children:B("Download")})},l);if("checkbox"===i.type){const r=!0===o||"true"===o||"yes"===o||"1"===o;return e.jsx("td",{className:d,children:e.jsx(n.Checkbox,{checked:r,onChange:(e,n)=>{g&&g(t,i.key,!0===n.checked,a)}})},l)}if("enum"===i.type&&i.enumOptions&&i.editable)return e.jsx("td",{className:d,children:e.jsxs(n.Select,{value:s,"aria-label":i.title?B(i.title):Array.isArray(i.key)?i.key[0]:i.key,onChange:(e,n)=>{y&&y(t,i.key,n.value,a)},style:{width:"100%"},children:[!i.enumOptions.includes(s)&&s&&e.jsx("option",{value:s,children:s}),i.enumOptions.map((t=>e.jsx("option",{value:t,children:B(t)},t)))]})},l);if("combobox"===i.type&&i.editable&&(i.enumOptions||i.enumOptionsLoader))return e.jsx("td",{className:d,children:e.jsx(u,{value:s,options:i.enumOptions,optionsLoader:i.enumOptionsLoader,minChars:i.enumOptionsLoaderMinChars,maxResults:i.enumOptionsLoaderMaxResults,columnKey:i.key,item:t,actualIndex:a,onEnumChange:y,label:i.title?B(i.title):Array.isArray(i.key)?i.key[0]:i.key,t:B})},l);const x=()=>i.maxWidth&&s.length>0?e.jsx(n.Tooltip,{content:{children:s,style:{maxWidth:"600px",whiteSpace:"normal"}},relationship:"description",children:e.jsx("span",{children:s})}):s,m=()=>{if(!i.action)return null;const r=i.action,l=i.action.icon,o=e.jsx(n.Button,{appearance:"subtle",icon:e.jsx(l,{}),className:b.actionIcon,onClick:e=>{e.stopPropagation(),r.onClick(t)},size:"small"});return r.tooltip?e.jsx(n.Tooltip,{content:B(r.tooltip),relationship:"label",children:o}):o};return e.jsx("td",{className:d,onClick:h,children:i.action?e.jsxs("div",{className:b.cellWithAction,children:[i.action.iconLeft&&m(),e.jsx("span",{className:b.cellText,children:x()}),!i.action.iconLeft&&m()]}):x()},l)})),x&&(m||f)&&e.jsx("td",{className:`${b.td} ${b.actionsColumn}`,children:e.jsxs("div",{style:{display:"flex",gap:"4px",justifyContent:"center"},children:[m&&e.jsx(n.Button,{appearance:"subtle",icon:e.jsx(i.Edit24Regular,{}),className:b.editButton,onClick:()=>m(t,a),title:B("Edit")}),f&&e.jsx(n.Button,{appearance:"subtle",icon:e.jsx(i.Delete24Regular,{}),className:b.editButton,onClick:()=>f(t,a),title:B("Delete")})]})})]},J(t,a))})),V<H.length&&e.jsx("tr",{style:{height:U-K-49*Y.length+"px"},children:e.jsx("td",{colSpan:v.length+(x?1:0),style:{padding:0,border:"none"}})})]})]})}),e.jsx(n.Dialog,{open:O,onOpenChange:(e,t)=>I(t.open),children:e.jsx(n.DialogSurface,{children:e.jsxs(n.DialogBody,{children:[e.jsx(n.DialogTitle,{children:$.title}),e.jsx(n.DialogContent,{className:b.dialogContent,children:$.text})]})})})]}):e.jsx("div",{className:b.emptyState,children:B("No data to display")})};var x=t.memo(h);exports.ListView=h,exports.default=x;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RecordModal.d.ts","sourceRoot":"","sources":["../../../src/components/RecordModal.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAuC,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"RecordModal.d.ts","sourceRoot":"","sources":["../../../src/components/RecordModal.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAuC,MAAM,OAAO,CAAC;AAqB5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAwJ9C,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CA+KlD,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react/jsx-runtime"),a=require("react"),t=require("@fluentui/react-components"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react/jsx-runtime"),a=require("react"),t=require("@fluentui/react-components"),l=require("@fluentui/react-icons"),r=require("../hooks/useLocalization.js"),n=require("../services/codicent.js");const i=t.makeStyles({surface:{backgroundColor:t.tokens.colorNeutralBackground1,width:"min(calc(100vw - 32px), 560px)",maxWidth:"calc(100vw - 32px)"},content:{display:"flex",flexDirection:"column",gap:"16px",minWidth:"0",maxHeight:"60vh",overflowY:"auto"},field:{display:"flex",flexDirection:"column"},thumbnailRow:{display:"flex",flexWrap:"wrap",gap:"6px",marginTop:"4px"},thumbnailImg:{maxWidth:"60px",maxHeight:"60px",objectFit:"cover",borderRadius:"4px",display:"block"},thumbnailIcon:{width:"32px",height:"32px",verticalAlign:"middle"}}),o=({fileId:t,imgClassName:r,iconClassName:i})=>{const[o,s]=a.useState(!0);return e.jsx("a",{href:n.CodicentService.getFileUrl(t),target:"_blank",rel:"noopener noreferrer",children:o?e.jsx("img",{src:n.CodicentService.getImageUrl(t,60),alt:`File attachment ${t}`,className:r,onError:()=>s(!1)}):e.jsx(l.Attach24Regular,{className:i})})},s=({value:l,options:r,optionsLoader:n,minChars:i=2,maxResults:o=50,label:s,onChange:c,t:u})=>{const[d,m]=a.useState(l),[p,h]=a.useState([]),[x,f]=a.useState(!1),g=a.useRef(null);a.useEffect((()=>{m(l)}),[l]),a.useEffect((()=>{if(n){if(!(d.length<i))return g.current&&clearTimeout(g.current),g.current=setTimeout((async()=>{f(!0);try{const e=await n(d);h(e.slice(0,o))}finally{f(!1)}}),250),()=>{g.current&&clearTimeout(g.current)};h([])}}),[d,n,i,o]);const y=a.useMemo((()=>(r??[]).filter((e=>e.toLowerCase().includes(d.toLowerCase()))).slice(0,o)),[r,d,o]),b=n?p:y;return e.jsx(t.Combobox,{value:d,freeform:!0,"aria-label":s,placeholder:x?u("Loading..."):n&&d.length<i?u(`Type ${i}+ characters to search...`):void 0,onChange:e=>m(e.target.value),onOptionSelect:(e,a)=>{a.optionValue&&(m(a.optionValue),c(a.optionValue))},onBlur:()=>c(d),style:{width:"100%"},children:b.map((a=>e.jsx(t.Option,{value:a,children:a},a)))})},c=({open:l,onClose:n,onSave:c,columns:u,initialData:d,title:m})=>{const p=i(),{t:h}=r.default(),[x,f]=a.useState({}),[g,y]=a.useState(!1);a.useEffect((()=>{l&&f(d||{})}),[l,d]);const b=e=>Array.isArray(e.key)?e.key[0]:e.key,j=e=>{if(Array.isArray(e.key))for(const a of e.key)if(void 0!==x[a])return a;return b(e)},v=(e,a)=>{const t=j(e);f((e=>({...e,[t]:a})))},C=u.filter((e=>!e.hidden&&"file"!==e.type&&"thumbnail"!==e.type&&"createdAt"!==b(e))),k=u.filter((e=>!e.hidden&&"thumbnail"===e.type));return e.jsx(t.Dialog,{open:l,onOpenChange:(e,a)=>!g&&!1===a.open&&n(),children:e.jsx(t.DialogSurface,{className:p.surface,backdrop:{style:{backgroundColor:"rgba(0, 0, 0, 0.4)"}},children:e.jsxs(t.DialogBody,{children:[e.jsx(t.DialogTitle,{children:m||h(d?"Edit Record":"Add Record")}),e.jsxs(t.DialogContent,{className:p.content,children:[k.map(((a,l)=>{const r=b(a),n=a.title||r,i=d?.[r],s=Array.isArray(i)?i:[];return 0===s.length?null:e.jsx(t.Field,{label:n,className:p.field,children:e.jsx("div",{className:p.thumbnailRow,children:s.map((a=>e.jsx(o,{fileId:a,imgClassName:p.thumbnailImg,iconClassName:p.thumbnailIcon},a)))})},`thumb-${l}`)})),C.map(((a,l)=>{const r=b(a),n=(e=>{const a=j(e);return x[a]})(a),i=a.title||r;return"checkbox"===a.type?e.jsx(t.Field,{label:i,className:p.field,children:e.jsx(t.Checkbox,{checked:!0===n||"true"===n||"yes"===n||"1"===n,onChange:(e,t)=>v(a,t.checked)})},l):"textarea"===a.type?e.jsx(t.Field,{label:i,className:p.field,children:e.jsx(t.Textarea,{value:String(n??""),rows:a.rows??3,onChange:(e,t)=>v(a,t.value),placeholder:h("Enter")+" "+i.toLowerCase(),resize:"vertical"})},l):"enum"===a.type&&a.enumOptions?e.jsx(t.Field,{label:i,className:p.field,children:e.jsx(t.Select,{value:String(n??""),onChange:(e,t)=>v(a,t.value),children:a.enumOptions.map((a=>e.jsx("option",{value:a,children:a||h("(None)")},a)))})},l):"combobox"===a.type&&(a.enumOptions||a.enumOptionsLoader)?e.jsx(t.Field,{label:i,className:p.field,children:e.jsx(s,{value:String(n??""),options:a.enumOptions,optionsLoader:a.enumOptionsLoader,minChars:a.enumOptionsLoaderMinChars,maxResults:a.enumOptionsLoaderMaxResults,label:i,onChange:e=>v(a,e),t:h})},l):e.jsx(t.Field,{label:i,className:p.field,children:e.jsx(t.Input,{value:String(n??""),onChange:(e,t)=>v(a,t.value),placeholder:h("Enter")+" "+i.toLowerCase()})},l)}))]}),e.jsxs(t.DialogActions,{children:[e.jsx(t.Button,{appearance:"secondary",onClick:n,disabled:g,children:h("Cancel")}),e.jsx(t.Button,{appearance:"primary",onClick:async()=>{y(!0);try{await c(x),n()}catch(e){console.error("Failed to save record:",e)}finally{y(!1)}},disabled:g,children:h(g?"Saving...":"Save")})]})]})})})};exports.RecordModal=c,exports.default=c;
|
|
@@ -13,6 +13,55 @@ export interface ListPageProps {
|
|
|
13
13
|
/** Optional data filter applied after fetch. Useful for app-specific filtering (e.g. empty notes). */
|
|
14
14
|
filterData?: (data: DataMessage[], tag: string) => DataMessage[];
|
|
15
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* ListPage — data fetch & cache behaviour
|
|
18
|
+
*
|
|
19
|
+
* ## Fetch key guard
|
|
20
|
+
* A `fetchKey` string (`tag-contentTitle-loadAll-refreshKey-debouncedSearch`) is stored in
|
|
21
|
+
* `lastFetchKey` (ref). The fetch effect bails out early if the key hasn't changed, preventing
|
|
22
|
+
* duplicate calls when unrelated state updates re-render the component.
|
|
23
|
+
* The ref is reset to `""` on effect cleanup (unmount / dep change) so that re-navigation
|
|
24
|
+
* always triggers a fresh fetch.
|
|
25
|
+
*
|
|
26
|
+
* ## Race-condition protection
|
|
27
|
+
* `activeFetchId` (ref) is incremented each time a new fetch starts. Each in-flight promise
|
|
28
|
+
* captures its own `myFetchId` and checks `isActive()` before writing state. A superseded
|
|
29
|
+
* fetch (e.g. from rapid search typing or quick navigation) silently discards its result
|
|
30
|
+
* without calling `setSearching(false)`, so the spinner stays visible until the winning fetch
|
|
31
|
+
* completes.
|
|
32
|
+
*
|
|
33
|
+
* ## Cache strategy
|
|
34
|
+
* | Visit | Cache present? | Behaviour |
|
|
35
|
+
* |-------|---------------|-----------|
|
|
36
|
+
* | First | No | `searching=true` → API call → populate cache → show list |
|
|
37
|
+
* | First | Yes | Instant render from cache (no spinner) → background delta-fetch for records newer than the latest cached timestamp → silently prepend new rows |
|
|
38
|
+
* | Back-navigation | Yes | Unmount cleanup resets fetchKey → same as "First, cache present" |
|
|
39
|
+
* | Back-navigation | Expired | Same as "First, no cache" |
|
|
40
|
+
* | Refresh button | Any | Clears cache for tag + resets fetchKey + increments `refreshKey` → full API call |
|
|
41
|
+
*
|
|
42
|
+
* ## Search / filter flow
|
|
43
|
+
* - Typing triggers a 500 ms debounce before `debouncedSearch` updates.
|
|
44
|
+
* - `debouncedSearch` change → new fetchKey → new `activeFetchId` → previous in-flight
|
|
45
|
+
* fetch is superseded and its result discarded.
|
|
46
|
+
* - `filter_<field>=<value>` URL params are applied client-side after fetch (not sent to API)
|
|
47
|
+
* except for `filter_<tag>=<value>` which seeds `debouncedSearch` for server-side filtering.
|
|
48
|
+
* - `q=` URL param is kept in sync with the search box via a debounced `setSearchParams`
|
|
49
|
+
* call that preserves all other existing params (`canAdd`, `canEdit`, `filter_*`, etc.).
|
|
50
|
+
*
|
|
51
|
+
* ## URL params (all optional)
|
|
52
|
+
* | Param | Type | Default | Purpose |
|
|
53
|
+
* |-------|------|---------|---------|
|
|
54
|
+
* | `tag` | string | `"logbook"` | Data tag to query |
|
|
55
|
+
* | `title` | string | `"Loggbok"` | Page heading |
|
|
56
|
+
* | `contentTitle` | string | — | If set, fetches raw messages and maps this field as the display column |
|
|
57
|
+
* | `loadAll` | `"true"` | — | Removes PAGE_SIZE cap; disables Load-more |
|
|
58
|
+
* | `canAdd` | `"true"` | — | Shows Add Record button (opens RecordModal) |
|
|
59
|
+
* | `canEdit` | `"true"` | — | Shows per-row Edit/Delete buttons |
|
|
60
|
+
* | `canExport` | `"false"` to hide | visible | Shows Export to Excel button |
|
|
61
|
+
* | `addUrl` | string | — | External URL opened on Add click (alternative to modal) |
|
|
62
|
+
* | `q` | string | — | Initial search term; kept in sync with search box |
|
|
63
|
+
* | `filter_<field>` | string | — | Client-side row filter; `%USERNAME%` resolves to current user |
|
|
64
|
+
*/
|
|
16
65
|
export declare const ListPage: ({ state, getColumnDefs, getListConfig, filterData }: ListPageProps) => import("react/jsx-runtime").JSX.Element;
|
|
17
66
|
export default ListPage;
|
|
18
67
|
//# sourceMappingURL=ListPage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ListPage.d.ts","sourceRoot":"","sources":["../../../src/pages/ListPage.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAuB3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAkE3D,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,gBAAgB,CAAC;IACxB,+FAA+F;IAC/F,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,gBAAgB,EAAE,CAAC;IACpD;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,UAAU,GAAG,SAAS,CAAC;IACxD,sGAAsG;IACtG,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE,GAAG,EAAE,MAAM,KAAK,WAAW,EAAE,CAAC;CAClE;AAED,eAAO,MAAM,QAAQ,wDAAyD,aAAa,
|
|
1
|
+
{"version":3,"file":"ListPage.d.ts","sourceRoot":"","sources":["../../../src/pages/ListPage.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAuB3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAkE3D,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,gBAAgB,CAAC;IACxB,+FAA+F;IAC/F,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,gBAAgB,EAAE,CAAC;IACpD;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,UAAU,GAAG,SAAS,CAAC;IACxD,sGAAsG;IACtG,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE,GAAG,EAAE,MAAM,KAAK,WAAW,EAAE,CAAC;CAClE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,eAAO,MAAM,QAAQ,wDAAyD,aAAa,4CA+mB1F,CAAC;AAEF,eAAe,QAAQ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react/jsx-runtime"),t=require("react");require("../components/Markdown.js"),require("../components/Textarea.js"),require("../components/Button.js"),require("../components/CompoundButton.js");var r=require("@fluentui/react-components");require("../components/Spinner.js");var a=require("../components/TextHeader.js");require("../components/TypingIndicator.js"),require("../components/Dialog.js"),require("../components/ChatInput.js"),require("../components/CombinedPlaceholderDialog.js"),require("../components/ChatMessage.js"),require("../components/Header.js");var n=require("@fluentui/react-icons");require("../services/codicent.js");var s=require("../services/dataCache.js"),o=require("../utils/MessageContent.js");require("../node_modules/tinycolor2/esm/tinycolor.js"),require("../_virtual/index.js"),require("../config/index.js"),require("../utils/cacheManager.js"),require("../lib/wavtools/lib/wav_packer.js"),require("../lib/wavtools/lib/analysis/audio_analysis.js"),require("../lib/wavtools/lib/wav_stream_player.js"),require("../lib/wavtools/lib/wav_recorder.js");var i=require("../utils/excelExport.js");require("./AppFrame.js"),require("./Canvas.js"),require("./Chat.js"),require("./Compose.js"),require("./Snap.js"),require("./Search.js"),require("./Menu.js"),require("./Log.js"),require("./Login.js"),require("./Home.js"),require("./CrmPage.js"),require("./CrmPagePersistent.js"),require("./ImageView.js"),require("./FormInvite.js"),require("./FormAccept.js"),require("./Sales.js");var c=require("react-router-dom");require("./Purchase.js"),require("../components/Content.js");var l=require("../components/Page.js");require("./QrScan.js");var u=require("../hooks/useLocalization.js");require("../components/FileThumbnail.js"),require("react-dom/client"),require("../node_modules/@auth0/auth0-react/dist/auth0-react.esm.js"),require("../hooks/useAppStyles.js");var d=require("../hooks/useUserRoles.js");require("../components/MessageInput.js"),require("../components/UploadFile.js"),require("../components/SnapFooter.js"),require("../components/Profile.js"),require("../components/MessageItem.js"),require("../components/AiInput.js");var p=require("../components/SearchBox.js");require("../components/DataMessagePicker.js"),require("../components/HtmlView.js"),require("../components/Footer.js"),require("../components/QrCodeDialog.js"),require("../components/QrScanner.js"),require("../components/OfflineMessage.js"),require("../components/LanguageSelector.js");var m=require("../components/ListView.js"),g=require("../components/RecordModal.js");require("../components/BulkUploadDialog.js"),require("../components/CookieBanner.js"),require("../components/audit/AuditCircularProgress.js"),require("../components/audit/AuditHorizontalProgress.js"),require("../components/audit/AuditRoleIndicator.js"),require("../components/audit/AuditUnitSwitcher.js"),require("../components/audit/AuditAnswerCell.js"),require("../components/audit/AuditSearchBar.js"),require("../components/audit/AuditFilterChips.js"),require("../components/audit/AuditFilterBar.js"),require("../components/audit/AuditGroupsProgress.js"),require("../components/audit/AuditSummaryDashboard.js"),require("../components/audit/AuditRequirementDialog.js"),require("../components/audit/AuditUnitExportDialog.js"),require("../components/audit/AuditUnitImportDialog.js"),require("../components/audit/AuditBulkExportDialog.js"),require("../components/audit/AuditBulkUploadDialog.js"),require("../components/audit/AuditSortPresets.js");var f=require("../node_modules/lodash/lodash.js");const h=r.makeStyles({container:{width:"100%",flex:1,maxWidth:"100%",height:"100%",minHeight:0,backgroundColor:"#ffffff",display:"flex",flexDirection:"column",margin:"0 auto",overflow:"hidden","@media (max-width: 768px)":{maxWidth:"100%",borderRadius:"0"},touchAction:"pan-y",paddingLeft:"0",paddingRight:"0"},listContainer:{overflow:"hidden",flex:1,minHeight:0,marginTop:"10px"},headerRow:{display:"flex",justifyContent:"space-between",alignItems:"center",gap:"10px",flexWrap:"wrap"},buttonGroup:{display:"flex",gap:"8px",flexWrap:"wrap"},addButton:{minWidth:"auto",whiteSpace:"nowrap"},recordsCount:{fontSize:"14px",color:"#666",marginTop:"8px"},backButton:{marginBottom:"10px"},searchBox:{marginTop:"8px"},loadMoreContainer:{display:"flex",justifyContent:"center",padding:"16px 0",borderTop:"1px solid #e0e0e0",marginTop:"4px"}}),j=500,q=({state:q,getColumnDefs:x,getListConfig:C,filterData:S})=>{const[w,y]=c.useSearchParams(),A=w.get("tag")||"logbook",v=w.get("title")||"",k=w.get("contentTitle"),b="true"===w.get("loadAll"),D="true"===w.get("canAdd"),M="true"===w.get("canEdit"),B="false"!==w.get("canExport"),E=w.get("addUrl")||"",R=w.get("q")||"",[I,P]=t.useState(R),[_,T]=t.useState(R),{service:$}=q,[N,L]=t.useState([]),[F,U]=t.useState(!1),[O,H]=t.useState(!1),[W,z]=t.useState(!1),V=t.useRef(null),G=t.useRef(R),J=t.useRef(""),Q=t.useRef(!0),[K,X]=t.useState(0),[Y,Z]=t.useState(null),ee=h(),{t:te}=u.default(),re=c.useNavigate(),{getCurrentUserName:ae}=d.useUserRoles($,q.context.nickname,q.context.selectedApp),ne=t.useMemo((()=>(k?[{key:k,title:k,maxWidth:250}]:C?C(A)?.columns??[]:x?x(A):[]).map((e=>({...e,title:e.title?te(e.title):void 0})))),[k,A,te,x,C]),[se,oe]=t.useState(!1),[ie,ce]=t.useState(null),[le,ue]=t.useState(!1),[de,pe]=t.useState(null),me=t.useMemo((()=>`listpage_searches_${A}`),[A]),ge=e=>{try{const t=localStorage.getItem(e);return t?JSON.parse(t):[]}catch{return[]}},[fe,he]=t.useState((()=>ge(me)));t.useEffect((()=>{he(ge(me))}),[me]);const je=t.useCallback((e=>{const t=e.trim();t&&he((e=>{const r=[t,...e.filter((e=>e!==t))].slice(0,20);try{localStorage.setItem(me,JSON.stringify(r))}catch{}return r}))}),[me]),qe=t.useCallback((e=>{he((t=>{const r=t.filter((t=>t!==e));try{localStorage.setItem(me,JSON.stringify(r))}catch{}return r}))}),[me]),xe=t.useMemo((()=>f.lodashExports.debounce((e=>T(e)),500)),[T]);t.useEffect((()=>()=>{xe.cancel()}),[xe]);const Ce=t.useCallback((e=>{P(e),xe(e)}),[xe]),Se=t.useCallback((e=>{je(e)}),[je]);t.useEffect((()=>{if(!w.get("q")){const e=w.get(`filter_${A}`);if(e){let t=e;if("%USERNAME%"===t){const e=ae();if(!e)return;t=e}P(t),T(t),G.current=t}}}),[A,w,ae]),t.useEffect((()=>{const e=w.get("q")||"";e!==G.current&&(P(e),T(e),G.current=e,J.current="")}),[w]),t.useEffect((()=>(V.current&&clearTimeout(V.current),V.current=setTimeout((()=>{if(G.current!==I){const e={title:v,tag:A};k&&(e.contentTitle=k),I&&(e.q=I),b&&(e.loadAll="true"),y(e,{replace:!0}),G.current=I}}),500),()=>{V.current&&clearTimeout(V.current)})),[I,A,v,k,b,y]),t.useEffect((()=>{Q.current=!0;const e=`${A}-${k}-${b}-${K}-${_}`;if(e===J.current)return;J.current=e;const t=k?`${A}-${_}-${k}`:`${A}-${_||"all"}`,r=s.dataCache.get(t);if(!r){if(H(!1),U(!0),k)$.getMessagesFast([A],_).then((e=>{if(!Q.current)return void U(!1);const r=e.map((e=>{const t=new Date(e.createdAt).toLocaleString();return{id:e.id,data:{[k]:new o.default(e.content).content,createdAt:t},fileId:null,fileIds:[],tags:[A],mentions:[$.codicent],createdAt:t}}));s.dataCache.set(t,r),Q.current&&L(r)})).catch(console.warn).finally((()=>U(!1)));else{const e=_||"",r=b||e?void 0:j;$.readDataMessages(A,e,void 0,0,r).then((r=>{s.dataCache.set(t,r),Q.current?(L(r),H(!b&&!e&&r.length===j)):U(!1)})).catch(console.warn).finally((()=>U(!1)))}return()=>{Q.current=!1}}if(L(r),H(!b&&!k&&r.length>=j),!k&&!_&&r.length>0){const e=r.reduce(((e,t)=>t.createdAt>e?t.createdAt:e),r[0].createdAt);$.readDataMessages(A,"",void 0,void 0,void 0,e).then((e=>{Q.current&&L((r=>{const a=new Set(r.map((e=>e.id))),n=e.filter((e=>!a.has(e.id)));if(0===n.length)return r;const o=[...n,...r];return s.dataCache.set(t,o),o}))})).catch(console.warn)}}),[$,A,k,b,_,K]);const we=t.useMemo((()=>{const e={};w.forEach(((t,r)=>{r.startsWith("filter_")&&(e[r.replace("filter_","")]=t)}));let t=N.map(((e,t)=>({item:e,index:t})));for(const[r,a]of Object.entries(e)){const e=a.replace("%USERNAME%",ae()),n=q.context.nickname||"";t=t.filter((({item:t})=>{const a=t.data[r];return null!=a&&(String(a).includes(e)||String(a).includes(n))}))}if(S){const e=S(t.map((({item:e})=>e)),A),r=new Set(e.map((e=>e.id)));t=t.filter((({item:e})=>r.has(e.id)))}const r=t.map((({item:e,index:t})=>({...e.data,createdAt:e.createdAt,_id:e.id,originalMessageId:e.originalMessageId||e.id,_fileIds:e.fileIds??[],_index:t}))),a=C?.(A)?.deduplicateBy;if(a){const e=Array.isArray(a)?a:[a],t=t=>{for(const r of e){const e=t[r];if(null!=e&&""!==String(e).trim())return String(e)}},n=new Set;return r.filter((e=>{const r=t(e);return void 0===r||!n.has(r)&&(n.add(r),!0)}))}return r}),[N,w,q.context.nickname,ae,S,A,C]),ye=t.useMemo((()=>{const e=(I||"").trim().toLowerCase();if(!e)return we;const t=ne.filter((e=>!e.hidden)).map((e=>e.key));return we.filter((r=>{for(const a of t)if(Array.isArray(a))for(const t of a){const a=r[t];if(null!=a&&String(a).toLowerCase().includes(e))return!0}else{const t=r[a];if(null!=t&&String(t).toLowerCase().includes(e))return!0}return!1}))}),[we,I,ne]),Ae=t.useCallback((()=>{s.dataCache.clearPattern(A),J.current="",X((e=>e+1))}),[A]),ve=t.useCallback((async()=>{z(!0);try{const e=await $.readDataMessages(A,"",void 0,N.length,j),t=[...N,...e];L(t),s.dataCache.set(`${A}-all`,t),H(e.length===j)}catch(e){console.warn(e)}finally{z(!1)}}),[N,$,A]),ke=t.useCallback((e=>{Z(e)}),[]),be=()=>{ue(!1),pe(null)},De=t.useCallback((async()=>{const e=`${A}_${(new Date).toISOString().split("T")[0]}`.replace(/[/\\:*?"<>|]/g,"_");const t=null!==Y?Y:ye;await i.exportToExcel(t,ne,e,te)||console.warn("No data to export")}),[Y,ye,ne,A,te]),Me=t.useMemo((()=>null!==Y?Y.length:ye.length),[Y,ye]);return e.jsx(l.Page,{hideHeader:!0,children:e.jsxs("div",{className:ee.container,children:[e.jsx("div",{className:ee.backButton,children:e.jsx(r.Button,{appearance:"subtle",icon:e.jsx(n.ArrowLeft24Regular,{}),onClick:()=>re(-1),children:te("Tillbaka")})}),e.jsxs("div",{className:ee.headerRow,children:[e.jsx(a.default,{title:te(v||"Loggbok")}),e.jsxs("div",{className:ee.buttonGroup,children:[e.jsx(r.Button,{appearance:"subtle",icon:e.jsx(n.ArrowClockwise24Regular,{}),onClick:Ae,title:te("Refresh"),children:te("Refresh")}),B&&e.jsx(r.Button,{appearance:"subtle",icon:e.jsx(n.ArrowDownload24Regular,{}),onClick:De,title:te("Export to Excel"),children:te("Export to Excel")}),(D||E)&&e.jsx(r.Button,{appearance:"primary",icon:e.jsx(n.Add24Regular,{}),onClick:D?()=>{ce(null),oe(!0)}:()=>window.open(E,"_blank"),className:ee.addButton,children:te("Add Record")})]})]}),e.jsx("div",{className:ee.searchBox,children:e.jsx(p.default,{placeholder:te("Sök")+"...",value:I,onChange:Ce,recentSearches:fe,onCommitSearch:Se,onRemoveRecentSearch:qe})}),!F&&e.jsxs("div",{className:ee.recordsCount,children:[te("Total"),": ",Me," ",te("records"),Me!==N.length&&` (${te("filtered from")} ${N.length})`]}),e.jsxs("div",{className:ee.listContainer,children:[F&&e.jsx("p",{children:te("Söker")+"..."}),!F&&e.jsx(m.default,{data:ye,columns:ne,canEdit:M,onEdit:(e,t)=>{const r=N[t];r&&(ce({data:{...r.data},index:t}),oe(!0))},onDelete:(e,t)=>{const r=N[t];r&&(pe({index:t,id:r.id}),ue(!0))},onToggleCheckbox:async(e,t,r,a)=>{const n=N[a];if(n){const e=Array.isArray(t)?t[0]:t,o={...n.data,[e]:String(r)},i=await $.updateDataMessage(n.id,o);L((e=>{const t=[...e];return t[a]={...n,id:i,data:o},t})),s.dataCache.clearPattern(A)}},onEnumChange:async(e,t,r,a)=>{const n=N[a];if(n){const e=Array.isArray(t)?t[0]:t,o={...n.data,[e]:r},i=await $.updateDataMessage(n.id,o);L((e=>{const t=[...e];return t[a]={...n,id:i,data:o},t})),s.dataCache.clearPattern(A)}},onFilteredDataChange:ke})]}),O&&!I.trim()&&e.jsx("div",{className:ee.loadMoreContainer,children:e.jsx(r.Button,{appearance:"primary",size:"medium",onClick:ve,disabled:W,children:W?te("Laddar..."):te("Visa fler")+` (${N.length} ${te("laddade")})`})}),e.jsx(g.RecordModal,{open:se,onClose:()=>oe(!1),onSave:async e=>{if(ie){const t=N[ie.index];if(t){const r={};for(const t in e){const a=e[t];r[t]=null==a?"":String(a)}const a=await $.updateDataMessage(t.id,r);L((e=>{const n=[...e];return n[ie.index]={...t,id:a,data:r},n})),s.dataCache.clearPattern(A)}}else{const t={};for(const r in e){const a=e[r];t[r]=null==a?"":String(a)}const r={id:await $.createDataMessage(A,t),data:t,createdAt:(new Date).toISOString(),fileId:null,fileIds:[],tags:[A],mentions:[$.codicent]};L((e=>[r,...e])),s.dataCache.clearPattern(A)}},columns:ne,initialData:ie?.data}),e.jsx(r.Dialog,{open:le,onOpenChange:(e,t)=>!t.open&&be(),children:e.jsx(r.DialogSurface,{children:e.jsxs(r.DialogBody,{children:[e.jsx(r.DialogTitle,{children:te("Confirm Delete")}),e.jsx(r.DialogContent,{children:te("Are you sure you want to delete this record? This action cannot be undone.")}),e.jsxs(r.DialogActions,{children:[e.jsx(r.Button,{appearance:"secondary",onClick:be,children:te("Cancel")}),e.jsx(r.Button,{appearance:"primary",onClick:async()=>{if(de)try{await $.deleteDataMessage(de.id),L((e=>e.filter(((e,t)=>t!==de.index)))),s.dataCache.clearPattern(A)}catch(e){console.error("Failed to delete record:",e)}finally{ue(!1),pe(null)}},children:te("Delete")})]})]})})})]})})};exports.ListPage=q,exports.default=q;
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react/jsx-runtime"),t=require("react");require("../components/Markdown.js"),require("../components/Textarea.js"),require("../components/Button.js"),require("../components/CompoundButton.js");var r=require("@fluentui/react-components");require("../components/Spinner.js");var n=require("../components/TextHeader.js");require("../components/TypingIndicator.js"),require("../components/Dialog.js"),require("../components/ChatInput.js"),require("../components/CombinedPlaceholderDialog.js"),require("../components/ChatMessage.js"),require("../components/Header.js");var a=require("@fluentui/react-icons");require("../services/codicent.js");var s=require("../services/dataCache.js"),i=require("../utils/MessageContent.js");require("../node_modules/tinycolor2/esm/tinycolor.js"),require("../_virtual/index.js"),require("../config/index.js"),require("../utils/cacheManager.js"),require("../lib/wavtools/lib/wav_packer.js"),require("../lib/wavtools/lib/analysis/audio_analysis.js"),require("../lib/wavtools/lib/wav_stream_player.js"),require("../lib/wavtools/lib/wav_recorder.js");var o=require("../utils/excelExport.js");require("./AppFrame.js"),require("./Canvas.js"),require("./Chat.js"),require("./Compose.js"),require("./Snap.js"),require("./Search.js"),require("./Menu.js"),require("./Log.js"),require("./Login.js"),require("./Home.js"),require("./CrmPage.js"),require("./CrmPagePersistent.js"),require("./ImageView.js"),require("./FormInvite.js"),require("./FormAccept.js"),require("./Sales.js");var c=require("react-router-dom");require("./Purchase.js"),require("../components/Content.js");var l=require("../components/Page.js");require("./QrScan.js");var u=require("../hooks/useLocalization.js");require("../components/FileThumbnail.js"),require("react-dom/client"),require("../node_modules/@auth0/auth0-react/dist/auth0-react.esm.js"),require("../hooks/useAppStyles.js");var d=require("../hooks/useUserRoles.js");require("../components/MessageInput.js"),require("../components/UploadFile.js"),require("../components/SnapFooter.js"),require("../components/Profile.js"),require("../components/MessageItem.js"),require("../components/AiInput.js");var p=require("../components/SearchBox.js");require("../components/DataMessagePicker.js"),require("../components/HtmlView.js"),require("../components/Footer.js"),require("../components/QrCodeDialog.js"),require("../components/QrScanner.js"),require("../components/OfflineMessage.js"),require("../components/LanguageSelector.js");var m=require("../components/ListView.js"),g=require("../components/RecordModal.js");require("../components/BulkUploadDialog.js"),require("../components/CookieBanner.js"),require("../components/audit/AuditCircularProgress.js"),require("../components/audit/AuditHorizontalProgress.js"),require("../components/audit/AuditRoleIndicator.js"),require("../components/audit/AuditUnitSwitcher.js"),require("../components/audit/AuditAnswerCell.js"),require("../components/audit/AuditSearchBar.js"),require("../components/audit/AuditFilterChips.js"),require("../components/audit/AuditFilterBar.js"),require("../components/audit/AuditGroupsProgress.js"),require("../components/audit/AuditSummaryDashboard.js"),require("../components/audit/AuditRequirementDialog.js"),require("../components/audit/AuditUnitExportDialog.js"),require("../components/audit/AuditUnitImportDialog.js"),require("../components/audit/AuditBulkExportDialog.js"),require("../components/audit/AuditBulkUploadDialog.js"),require("../components/audit/AuditSortPresets.js");var f=require("../node_modules/lodash/lodash.js");const h=r.makeStyles({container:{width:"100%",flex:1,maxWidth:"100%",height:"100%",minHeight:0,backgroundColor:"#ffffff",display:"flex",flexDirection:"column",margin:"0 auto",overflow:"hidden","@media (max-width: 768px)":{maxWidth:"100%",borderRadius:"0"},touchAction:"pan-y",paddingLeft:"0",paddingRight:"0"},listContainer:{overflow:"hidden",flex:1,minHeight:0,marginTop:"10px"},headerRow:{display:"flex",justifyContent:"space-between",alignItems:"center",gap:"10px",flexWrap:"wrap"},buttonGroup:{display:"flex",gap:"8px",flexWrap:"wrap"},addButton:{minWidth:"auto",whiteSpace:"nowrap"},recordsCount:{fontSize:"14px",color:"#666",marginTop:"8px"},backButton:{marginBottom:"10px"},searchBox:{marginTop:"8px"},loadMoreContainer:{display:"flex",justifyContent:"center",padding:"16px 0",borderTop:"1px solid #e0e0e0",marginTop:"4px"}}),j=500,q=({state:q,getColumnDefs:x,getListConfig:C,filterData:S})=>{const[y,w]=c.useSearchParams(),A=y.get("tag")||"logbook",v=y.get("title")||"",k=y.get("contentTitle"),b="true"===y.get("loadAll"),D="true"===y.get("canAdd"),M="true"===y.get("canEdit"),R="false"!==y.get("canExport"),B=y.get("addUrl")||"",E=y.get("q")||"",[I,P]=t.useState(E),[_,T]=t.useState(E),{service:$}=q,[N,L]=t.useState([]),[U,F]=t.useState(!1),[O,H]=t.useState(!1),[W,z]=t.useState(!1),V=t.useRef(null),G=t.useRef(E),J=t.useRef(""),Q=t.useRef(0),K=t.useRef($);K.current=$;const X=!!$,[Y,Z]=t.useState(0),[ee,te]=t.useState(null),re=h(),{t:ne}=u.default(),ae=c.useNavigate(),{getCurrentUserName:se}=d.useUserRoles($,q.context.nickname,q.context.selectedApp),ie=t.useMemo((()=>(k?[{key:k,title:k,maxWidth:250}]:C?C(A)?.columns??[]:x?x(A):[]).map((e=>({...e,title:e.title?ne(e.title):void 0})))),[k,A,ne,x,C]),[oe,ce]=t.useState(!1),[le,ue]=t.useState(null),[de,pe]=t.useState(!1),[me,ge]=t.useState(null),fe=t.useMemo((()=>`listpage_searches_${A}`),[A]),he=e=>{try{const t=localStorage.getItem(e);return t?JSON.parse(t):[]}catch{return[]}},[je,qe]=t.useState((()=>he(fe)));t.useEffect((()=>{qe(he(fe))}),[fe]);const xe=t.useCallback((e=>{const t=e.trim();t&&qe((e=>{const r=[t,...e.filter((e=>e!==t))].slice(0,20);try{localStorage.setItem(fe,JSON.stringify(r))}catch{}return r}))}),[fe]),Ce=t.useCallback((e=>{qe((t=>{const r=t.filter((t=>t!==e));try{localStorage.setItem(fe,JSON.stringify(r))}catch{}return r}))}),[fe]),Se=t.useMemo((()=>f.lodashExports.debounce((e=>T(e)),500)),[T]);t.useEffect((()=>()=>{Se.cancel()}),[Se]);const ye=t.useCallback((e=>{P(e),Se(e)}),[Se]),we=t.useCallback((e=>{xe(e)}),[xe]);t.useEffect((()=>{if(!y.get("q")){const e=y.get(`filter_${A}`);if(e){let t=e;if("%USERNAME%"===t){const e=se();if(!e)return;t=e}P(t),T(t),G.current=t}}}),[A,y,se]),t.useEffect((()=>{const e=y.get("q")||"";e!==G.current&&e!==_&&(P(e),T(e),G.current=e,J.current="")}),[y]),t.useEffect((()=>(V.current&&clearTimeout(V.current),V.current=setTimeout((()=>{if(G.current!==I){const e=new URLSearchParams(y);I?e.set("q",I):e.delete("q"),w(e,{replace:!0}),G.current=I}}),500),()=>{V.current&&clearTimeout(V.current)})),[I,y,w]),t.useEffect((()=>{if(!K.current)return;const e=`${A}-${k}-${b}-${Y}-${_}`;if(e===J.current)return;J.current=e;const t=++Q.current,r=()=>t===Q.current,n=k?`${A}-${_}-${k}`:`${A}-${_||"all"}`,a=s.dataCache.get(n);if(!a){if(H(!1),F(!0),k)K.current.getMessagesFast([A],_).then((e=>{if(!r())return;const t=e.map((e=>{const t=new Date(e.createdAt).toLocaleString();return{id:e.id,data:{[k]:new i.default(e.content).content,createdAt:t},fileId:null,fileIds:[],tags:[A],mentions:[K.current.codicent],createdAt:t}}));s.dataCache.set(n,t),L(t)})).catch(console.warn).finally((()=>{r()&&F(!1)}));else{const e=_||"",t=b||e?void 0:j;K.current.readDataMessages(A,e,void 0,0,t).then((t=>{r()&&(s.dataCache.set(n,t),L(t),H(!b&&!e&&t.length===j))})).catch(console.warn).finally((()=>{r()&&F(!1)}))}return()=>{J.current=""}}if(L(a),H(!b&&!k&&a.length>=j),!k&&!_&&a.length>0){const e=a.reduce(((e,t)=>t.createdAt>e?t.createdAt:e),a[0].createdAt);K.current.readDataMessages(A,"",void 0,void 0,void 0,e).then((e=>{r()&&L((t=>{const r=new Set(t.map((e=>e.id))),a=e.filter((e=>!r.has(e.id)));if(0===a.length)return t;const i=[...a,...t];return s.dataCache.set(n,i),i}))})).catch(console.warn)}}),[A,k,b,_,Y,X]);const Ae=t.useMemo((()=>{const e={};y.forEach(((t,r)=>{r.startsWith("filter_")&&(e[r.replace("filter_","")]=t)}));let t=N.map(((e,t)=>({item:e,index:t})));for(const[r,n]of Object.entries(e)){const e=n.replace("%USERNAME%",se()),a=q.context.nickname||"";t=t.filter((({item:t})=>{const n=t.data[r];return null!=n&&(String(n).includes(e)||String(n).includes(a))}))}if(S){const e=S(t.map((({item:e})=>e)),A),r=new Set(e.map((e=>e.id)));t=t.filter((({item:e})=>r.has(e.id)))}const r=t.map((({item:e,index:t})=>({...e.data,createdAt:e.createdAt,_id:e.id,originalMessageId:e.originalMessageId||e.id,_fileIds:e.fileIds??[],_index:t}))),n=C?.(A)?.deduplicateBy;if(n){const e=Array.isArray(n)?n:[n],t=t=>{for(const r of e){const e=t[r];if(null!=e&&""!==String(e).trim())return String(e)}},a=new Set;return r.filter((e=>{const r=t(e);return void 0===r||!a.has(r)&&(a.add(r),!0)}))}return r}),[N,y,q.context.nickname,se,S,A,C]),ve=t.useMemo((()=>{const e=(I||"").trim().toLowerCase();if(!e)return Ae;const t=ie.filter((e=>!e.hidden)).map((e=>e.key));return Ae.filter((r=>{for(const n of t)if(Array.isArray(n))for(const t of n){const n=r[t];if(null!=n&&String(n).toLowerCase().includes(e))return!0}else{const t=r[n];if(null!=t&&String(t).toLowerCase().includes(e))return!0}return!1}))}),[Ae,I,ie]),ke=t.useCallback((()=>{s.dataCache.clearPattern(A),J.current="",Z((e=>e+1))}),[A]),be=t.useCallback((async()=>{z(!0);try{const e=await K.current.readDataMessages(A,"",void 0,N.length,j),t=[...N,...e];L(t),s.dataCache.set(`${A}-all`,t),H(e.length===j)}catch(e){console.warn(e)}finally{z(!1)}}),[N,A]),De=t.useCallback((e=>{te(e)}),[]),Me=()=>{pe(!1),ge(null)},Re=t.useCallback((async()=>{const e=`${A}_${(new Date).toISOString().split("T")[0]}`.replace(/[/\\:*?"<>|]/g,"_");const t=null!==ee?ee:ve;await o.exportToExcel(t,ie,e,ne)||console.warn("No data to export")}),[ee,ve,ie,A,ne]),Be=t.useMemo((()=>null!==ee?ee.length:ve.length),[ee,ve]);return e.jsx(l.Page,{hideHeader:!0,children:e.jsxs("div",{className:re.container,children:[e.jsx("div",{className:re.backButton,children:e.jsx(r.Button,{appearance:"subtle",icon:e.jsx(a.ArrowLeft24Regular,{}),onClick:()=>ae(-1),children:ne("Tillbaka")})}),e.jsxs("div",{className:re.headerRow,children:[e.jsx(n.default,{title:ne(v||"Loggbok")}),e.jsxs("div",{className:re.buttonGroup,children:[e.jsx(r.Button,{appearance:"subtle",icon:e.jsx(a.ArrowClockwise24Regular,{}),onClick:ke,title:ne("Refresh"),children:ne("Refresh")}),R&&e.jsx(r.Button,{appearance:"subtle",icon:e.jsx(a.ArrowDownload24Regular,{}),onClick:Re,title:ne("Export to Excel"),children:ne("Export to Excel")}),(D||B)&&e.jsx(r.Button,{appearance:"primary",icon:e.jsx(a.Add24Regular,{}),onClick:D?()=>{ue(null),ce(!0)}:()=>window.open(B,"_blank"),className:re.addButton,children:ne("Add Record")})]})]}),e.jsx("div",{className:re.searchBox,children:e.jsx(p.default,{placeholder:ne("Sök")+"...",value:I,onChange:ye,recentSearches:je,onCommitSearch:we,onRemoveRecentSearch:Ce})}),!U&&e.jsxs("div",{className:re.recordsCount,children:[ne("Total"),": ",Be," ",ne("records"),Be!==N.length&&` (${ne("filtered from")} ${N.length})`]}),e.jsxs("div",{className:re.listContainer,children:[U&&e.jsx("p",{children:ne("Söker")+"..."}),!U&&e.jsx(m.default,{data:ve,columns:ie,canEdit:M,onEdit:(e,t)=>{const r=N[t];r&&(ue({data:{...r.data,_fileIds:r.fileIds??[]},index:t}),ce(!0))},onDelete:(e,t)=>{const r=N[t];r&&(ge({index:t,id:r.id}),pe(!0))},onToggleCheckbox:async(e,t,r,n)=>{const a=N[n];if(a){const e=Array.isArray(t)?t[0]:t,i={...a.data,[e]:String(r)},o=await $.updateDataMessage(a.id,i);L((e=>{const t=[...e];return t[n]={...a,id:o,data:i},t})),s.dataCache.clearPattern(A)}},onEnumChange:async(e,t,r,n)=>{const a=N[n];if(a){const e=Array.isArray(t)?t[0]:t,i={...a.data,[e]:r},o=await $.updateDataMessage(a.id,i);L((e=>{const t=[...e];return t[n]={...a,id:o,data:i},t})),s.dataCache.clearPattern(A)}},onFilteredDataChange:De})]}),O&&!I.trim()&&e.jsx("div",{className:re.loadMoreContainer,children:e.jsx(r.Button,{appearance:"primary",size:"medium",onClick:be,disabled:W,children:W?ne("Laddar..."):ne("Visa fler")+` (${N.length} ${ne("laddade")})`})}),e.jsx(g.RecordModal,{open:oe,onClose:()=>ce(!1),onSave:async e=>{const t=new Set(ie.filter((e=>"thumbnail"===e.type)).map((e=>Array.isArray(e.key)?e.key[0]:e.key)));if(le){const r=N[le.index];if(r){const n={};for(const r in e){if(t.has(r))continue;const a=e[r];n[r]=null==a?"":String(a)}const a=await $.updateDataMessage(r.id,n);L((e=>{const t=[...e];return t[le.index]={...r,id:a,data:n},t})),s.dataCache.clearPattern(A)}}else{const r={};for(const n in e){if(t.has(n))continue;const a=e[n];r[n]=null==a?"":String(a)}const n={id:await $.createDataMessage(A,r),data:r,createdAt:(new Date).toISOString(),fileId:null,fileIds:[],tags:[A],mentions:[$.codicent]};L((e=>[n,...e])),s.dataCache.clearPattern(A)}},columns:ie,initialData:le?.data}),e.jsx(r.Dialog,{open:de,onOpenChange:(e,t)=>!t.open&&Me(),children:e.jsx(r.DialogSurface,{children:e.jsxs(r.DialogBody,{children:[e.jsx(r.DialogTitle,{children:ne("Confirm Delete")}),e.jsx(r.DialogContent,{children:ne("Are you sure you want to delete this record? This action cannot be undone.")}),e.jsxs(r.DialogActions,{children:[e.jsx(r.Button,{appearance:"secondary",onClick:Me,children:ne("Cancel")}),e.jsx(r.Button,{appearance:"primary",onClick:async()=>{if(me)try{await $.deleteDataMessage(me.id),L((e=>e.filter(((e,t)=>t!==me.index)))),s.dataCache.clearPattern(A)}catch(e){console.error("Failed to delete record:",e)}finally{pe(!1),ge(null)}},children:ne("Delete")})]})]})})})]})})};exports.ListPage=q,exports.default=q;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ListView.d.ts","sourceRoot":"","sources":["../../../src/components/ListView.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAuC,MAAM,OAAO,CAAC;AAmB5D,uEAAuE;AACvE,MAAM,WAAW,YAAY;IAC3B,kHAAkH;IAClH,IAAI,EAAE,KAAK,CAAC,aAAa,CAAC;IAC1B,uCAAuC;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IACpD,oFAAoF;IACpF,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;
|
|
1
|
+
{"version":3,"file":"ListView.d.ts","sourceRoot":"","sources":["../../../src/components/ListView.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAuC,MAAM,OAAO,CAAC;AAmB5D,uEAAuE;AACvE,MAAM,WAAW,YAAY;IAC3B,kHAAkH;IAClH,IAAI,EAAE,KAAK,CAAC,aAAa,CAAC;IAC1B,uCAAuC;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IACpD,oFAAoF;IACpF,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AA+ND,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,UAAU,GAAG,MAAM,GAAG,UAAU,GAAG,WAAW,GAAG,SAAS,CAAC;IACxF,oDAAoD;IACpD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0DAA0D;IAC1D,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,2HAA2H;IAC3H,iBAAiB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9D,wFAAwF;IACxF,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,kFAAkF;IAClF,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gHAAgH;IAChH,WAAW,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IAC7B,2HAA2H;IAC3H,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,oIAAoI;IACpI,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC;CACrC;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAChC,OAAO,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAChE,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClE,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAChH,oBAAoB,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,IAAI,CAAC;CAC1E;AA6ID,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CA+iB5C,CAAC;;AAGF,wBAAoC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as e,jsxs as t,Fragment as n}from"react/jsx-runtime";import i,{useMemo as r,useState as l,useEffect as o}from"react";import{makeStyles as a,Select as c,Button as s,Checkbox as d,Dialog as p,DialogSurface as h,DialogBody as u,DialogTitle as m,DialogContent as f,Combobox as g,Option as x,Tooltip as y}from"@fluentui/react-components";import{Edit24Regular as b,Delete24Regular as w,Attach24Regular as v}from"@fluentui/react-icons";import{CodicentService as C}from"../services/codicent.js";import k from"../hooks/useLocalization.js";const N=a({container:{width:"100%",overflowX:"auto",userSelect:"text"},table:{width:"100%",borderCollapse:"collapse",backgroundColor:"#ffffff",fontSize:"14px",tableLayout:"fixed",userSelect:"text"},th:{textAlign:"left",padding:"12px 8px",borderBottom:"2px solid #e0e0e0",fontWeight:"600",backgroundColor:"#f5f5f5",position:"sticky",top:0,zIndex:1,cursor:"pointer",userSelect:"none","&:hover":{backgroundColor:"#e8e8e8"}},td:{padding:"12px 8px",borderBottom:"1px solid #e0e0e0",verticalAlign:"top",wordWrap:"break-word",overflow:"hidden",userSelect:"text"},tdTruncated:{overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap","@media (hover: none)":{cursor:"pointer"}},tr:{"&:hover":{backgroundColor:"#f9f9f9"}},emptyState:{padding:"20px",textAlign:"center",color:"#666"},sortIndicator:{marginLeft:"4px",fontSize:"10px"},hideOnMobile:{"@media (max-width: 768px)":{display:"none"}},dialogContent:{wordWrap:"break-word",whiteSpace:"pre-wrap",maxHeight:"60vh",overflowY:"auto"},thumbnail:{maxWidth:"50px",maxHeight:"50px",objectFit:"cover"},tooltip:{maxWidth:"600px",whiteSpace:"normal",wordWrap:"break-word"},editButton:{minWidth:"auto",padding:"4px 8px"},actionsColumn:{width:"100px",textAlign:"center"},filterInput:{width:"100%",padding:"4px 8px",fontSize:"14px",border:"1px solid #e0e0e0",borderRadius:"4px",paddingRight:"28px"},filterWrapper:{position:"relative"},clearFilterButton:{position:"absolute",right:"6px",top:"50%",transform:"translateY(-50%)",minWidth:"auto",height:"20px",padding:"0 6px",lineHeight:"18px"},filterToolbar:{display:"flex",justifyContent:"flex-end",padding:"8px",gap:"8px"},cellWithAction:{display:"flex",alignItems:"center",justifyContent:"space-between",gap:"4px"},actionIcon:{minWidth:"auto",padding:"2px",marginLeft:"4px",flexShrink:0,cursor:"pointer",opacity:.7,"&:hover":{opacity:1}},thumbnailRow:{display:"flex",gap:"4px",flexWrap:"wrap"},cellText:{flex:1,overflow:"hidden",textOverflow:"ellipsis"}}),S=e=>{if(/^\d{4}-\d{2}-\d{2}/.test(e)){const t=new Date(e);if(!isNaN(t.getTime()))return t.getTime()}const t=e.match(/^(\d{1,2})\.(\d{1,2})\.(\d{4})/);if(t){const e=parseInt(t[1],10),n=parseInt(t[2],10)-1,i=parseInt(t[3],10),r=new Date(i,n,e);if(r.getFullYear()===i&&r.getMonth()===n&&r.getDate()===e)return r.getTime()}return null},W=(e,t)=>{if("string"==typeof t)return e[t];for(const n of t)if(void 0!==e[n])return e[n]},I=a({img:{maxWidth:"40px",maxHeight:"40px",objectFit:"cover",borderRadius:"3px",display:"block"},fileIcon:{width:"24px",height:"24px",verticalAlign:"middle"}}),O=({fileId:t})=>{const[n,i]=l(!0),r=I();return e("a",{href:C.getFileUrl(t),target:"_blank",rel:"noopener noreferrer",children:n?e("img",{src:C.getImageUrl(t,40),alt:"",className:r.img,onError:()=>i(!1)}):e(v,{className:r.fileIcon})})},A=({value:t,options:n,optionsLoader:a,minChars:c=2,maxResults:s=50,columnKey:d,item:p,actualIndex:h,onEnumChange:u,label:m,t:f})=>{const[y,b]=l(t),[w,v]=l([]),[C,k]=l(!1),N=i.useRef(null);o((()=>{b(t)}),[t]),o((()=>{if(a){if(!(y.length<c))return N.current&&clearTimeout(N.current),N.current=setTimeout((async()=>{k(!0);try{const e=await a(y);v(e.slice(0,s))}finally{k(!1)}}),250),()=>{N.current&&clearTimeout(N.current)};v([])}}),[y,a,c,s]);const S=r((()=>(n??[]).filter((e=>e.toLowerCase().includes(y.toLowerCase()))).slice(0,s)),[n,y,s]),W=a?w:S;return e(g,{value:y,freeform:!0,"aria-label":m,placeholder:C?f("Loading..."):a&&y.length<c?f(`Type ${c}+ characters to search...`):void 0,onChange:e=>b(e.target.value),onOptionSelect:(e,t)=>{t.optionValue&&(b(t.optionValue),u&&u(p,d,t.optionValue,h))},onBlur:()=>{u&&u(p,d,y,h)},style:{width:"100%"},children:W.map((t=>e(x,{value:t,children:t},t)))})},$=({data:i,columns:a,canEdit:g,onEdit:x,onDelete:v,onToggleCheckbox:I,onEnumChange:$,onFilteredDataChange:L})=>{const T=N(),{visibleColumns:j,defaultSortIndex:F,defaultSortDirection:M}=r((()=>{const e=i&&i.length>0?Array.from(new Set(i.flatMap((e=>Object.keys(e))))):[],t=(a||e.map((e=>({key:e})))).filter((e=>!e.hidden)),n=t.findIndex((e=>e.defaultSort));return{visibleColumns:t,defaultSortIndex:n,defaultSortDirection:n>=0&&t[n].defaultSort||null}}),[i,a]),[D,R]=l(F>=0?F:null),[B,E]=l(M),[z,H]=l(!1),[P,Y]=l({title:"",text:""}),[U,V]=l({}),[_,K]=l(0),{t:J}=k(),X=e=>e.title?J(e.title):Array.isArray(e.key)?e.key[0]:e.key,q=e=>{const t=[];return e.hideOnMobile&&t.push(T.hideOnMobile),t.join(" ")},G=(e,t)=>{V((n=>{const i={...n};return""===t.trim()?delete i[e]:i[e]=t,i}))},Q=e=>null==e||"string"==typeof e&&e.startsWith("[")&&e.endsWith("]")?"":"object"==typeof e?JSON.stringify(e):String(e),Z=r((()=>{const e=[...i];if(null!==D&&B){const t=j[D];e.sort(((e,n)=>{const i=W(e,t.key),r=W(n,t.key);if(null==i)return 1;if(null==r)return-1;let l=0;if("string"==typeof i&&"string"==typeof r){const e=S(i),t=S(r);if(null!==e&&null!==t)l=e-t;else{const e=i.trim().replace(/[\s\u00a0]/g,"").replace(/,/g,""),t=r.trim().replace(/[\s\u00a0]/g,"").replace(/,/g,""),n=Number(e),o=Number(t);l=""!==e&&""!==t&&isFinite(n)&&isFinite(o)?n-o:i.localeCompare(r)}}else if("number"==typeof i&&"number"==typeof r)l=i-r;else{const e=Number(String(i).trim().replace(/[\s\u00a0]/g,"").replace(/,/g,"")),t=Number(String(r).trim().replace(/[\s\u00a0]/g,"").replace(/,/g,""));l=isFinite(e)&&isFinite(t)?e-t:String(i).localeCompare(String(r))}return"asc"===B?l:-l}))}return e}),[i,D,B,j]),ee=r((()=>Z.filter((e=>{for(const[t,n]of Object.entries(U)){const i=parseInt(t),r=j[i],l=W(e,r.key),o=Q(l).toLowerCase(),a=n.toLowerCase();if(!("enum"===r.type&&r.enumOptions?o===a:o.includes(a)))return!1}return!0}))),[Z,U,j]);o((()=>{L&&L(ee)}),[ee,L]);const te="undefined"!=typeof window?window.innerHeight-250:600,ne=Math.max(0,Math.floor(_/49)-5),ie=Math.min(ee.length,Math.ceil((_+te)/49)+5),re=ee.slice(ne,ie),le=49*ee.length,oe=49*ne,ae=(e,t)=>{if(void 0!==e.id)return String(e.id);return`row-${t}-${(e=>{let t=0;for(let n=0;n<e.length;n++)t=(t<<5)-t+e.charCodeAt(n),t|=0;return Math.abs(t)})(j.slice(0,3).map((t=>String(W(e,t.key)??""))).join("-"))}`};return i&&0!==i.length?t(n,{children:[e("div",{className:T.container,onScroll:e=>{K(e.currentTarget.scrollTop)},style:{maxHeight:"calc(100vh - 200px)",overflowY:"auto"},children:t("table",{className:T.table,children:[t("thead",{children:[t("tr",{children:[j.map(((n,i)=>{const r=n.maxWidth?{width:`${n.maxWidth}px`,maxWidth:`${n.maxWidth}px`}:{};return t("th",{className:`${T.th} ${q(n)}`.trim(),style:r,onClick:()=>(e=>{D===e?"asc"===B?E("desc"):"desc"===B&&(R(null),E(null)):(R(e),E("asc"))})(i),children:[X(n),D===i&&e("span",{className:T.sortIndicator,children:"asc"===B?"▲":"▼"})]},i)})),g&&e("th",{className:`${T.th} ${T.actionsColumn}`,style:{width:"100px"},children:J("Actions")})]}),t("tr",{children:[j.map(((i,r)=>{const l=i.maxWidth?{width:`${i.maxWidth}px`,maxWidth:`${i.maxWidth}px`}:{};return e("th",{className:q(i),style:l,children:i.filterable&&e("div",{className:T.filterWrapper,children:"enum"===i.type&&i.enumOptions?t(c,{className:T.filterInput,value:U[r]||"",onChange:(e,t)=>G(r,t.value),onClick:e=>e.stopPropagation(),children:[e("option",{value:"",children:J("All")}),i.enumOptions.filter((e=>""!==e)).map((t=>e("option",{value:t,children:J(t)},t)))]}):t(n,{children:[e("input",{type:"text",className:T.filterInput,placeholder:J("Filter")+"...",value:U[r]||"",onChange:e=>G(r,e.target.value),onClick:e=>e.stopPropagation()}),(U[r]||"").length>0&&e(s,{appearance:"subtle",className:T.clearFilterButton,onClick:e=>{e.stopPropagation(),(e=>{V((t=>{const n={...t};return delete n[e],n}))})(r)},children:"×"})]})})},r)})),g&&e("th",{className:T.actionsColumn})]})]}),t("tbody",{children:[ne>0&&e("tr",{style:{height:`${oe}px`},children:e("td",{colSpan:j.length+(g?1:0),style:{padding:0,border:"none"}})}),re.map(((n,i)=>{const r=n._index,l="number"==typeof r?r:ne+i;return t("tr",{className:T.tr,children:[j.map(((i,r)=>{const o=W(n,i.key),a=i.format?i.format(o):Q(o),p=i.maxWidth?`${T.td} ${T.tdTruncated} ${q(i)}`.trim():`${T.td} ${q(i)}`.trim(),h=()=>{window.matchMedia("(hover: hover)").matches||i.maxWidth&&a.length>0&&(Y({title:X(i),text:a}),H(!0))};if("thumbnail"===i.type){const t=Array.isArray(o)?o:[];return e("td",{className:p,children:e("div",{className:T.thumbnailRow,children:t.map((t=>e(O,{fileId:t},t)))})},r)}if("file"===i.type&&a)return e("td",{className:p,onClick:h,children:e("a",{href:C.getFileUrl(a),target:"_blank",rel:"noopener noreferrer",children:J("Download")})},r);if("checkbox"===i.type){return e("td",{className:p,children:e(d,{checked:!0===o||"true"===o||"yes"===o||"1"===o,onChange:(e,t)=>{I&&I(n,i.key,!0===t.checked,l)}})},r)}if("enum"===i.type&&i.enumOptions&&i.editable)return e("td",{className:p,children:t(c,{value:a,"aria-label":i.title?J(i.title):Array.isArray(i.key)?i.key[0]:i.key,onChange:(e,t)=>{$&&$(n,i.key,t.value,l)},style:{width:"100%"},children:[!i.enumOptions.includes(a)&&a&&e("option",{value:a,children:a}),i.enumOptions.map((t=>e("option",{value:t,children:J(t)},t)))]})},r);if("combobox"===i.type&&i.editable&&(i.enumOptions||i.enumOptionsLoader))return e("td",{className:p,children:e(A,{value:a,options:i.enumOptions,optionsLoader:i.enumOptionsLoader,minChars:i.enumOptionsLoaderMinChars,maxResults:i.enumOptionsLoaderMaxResults,columnKey:i.key,item:n,actualIndex:l,onEnumChange:$,label:i.title?J(i.title):Array.isArray(i.key)?i.key[0]:i.key,t:J})},r);const u=()=>i.maxWidth&&a.length>0?e(y,{content:{children:a,style:{maxWidth:"600px",whiteSpace:"normal"}},relationship:"description",children:e("span",{children:a})}):a,m=()=>{if(!i.action)return null;const t=i.action,r=i.action.icon,l=e(s,{appearance:"subtle",icon:e(r,{}),className:T.actionIcon,onClick:e=>{e.stopPropagation(),t.onClick(n)},size:"small"});return t.tooltip?e(y,{content:J(t.tooltip),relationship:"label",children:l}):l};return e("td",{className:p,onClick:h,children:i.action?t("div",{className:T.cellWithAction,children:[i.action.iconLeft&&m(),e("span",{className:T.cellText,children:u()}),!i.action.iconLeft&&m()]}):u()},r)})),g&&(x||v)&&e("td",{className:`${T.td} ${T.actionsColumn}`,children:t("div",{style:{display:"flex",gap:"4px",justifyContent:"center"},children:[x&&e(s,{appearance:"subtle",icon:e(b,{}),className:T.editButton,onClick:()=>x(n,l),title:J("Edit")}),v&&e(s,{appearance:"subtle",icon:e(w,{}),className:T.editButton,onClick:()=>v(n,l),title:J("Delete")})]})})]},ae(n,l))})),ie<ee.length&&e("tr",{style:{height:le-oe-49*re.length+"px"},children:e("td",{colSpan:j.length+(g?1:0),style:{padding:0,border:"none"}})})]})]})}),e(p,{open:z,onOpenChange:(e,t)=>H(t.open),children:e(h,{children:t(u,{children:[e(m,{children:P.title}),e(f,{className:T.dialogContent,children:P.text})]})})})]}):e("div",{className:T.emptyState,children:J("No data to display")})};var L=i.memo($);export{$ as ListView,L as default};
|
|
1
|
+
import{jsx as e,jsxs as t,Fragment as n}from"react/jsx-runtime";import i,{useMemo as r,useState as l,useEffect as o}from"react";import{makeStyles as a,Select as c,Button as s,Checkbox as d,Dialog as p,DialogSurface as h,DialogBody as u,DialogTitle as m,DialogContent as f,Combobox as g,Option as x,Tooltip as y}from"@fluentui/react-components";import{Edit24Regular as b,Delete24Regular as w,Attach24Regular as v}from"@fluentui/react-icons";import{CodicentService as C}from"../services/codicent.js";import k from"../hooks/useLocalization.js";const N=a({container:{width:"100%",overflowX:"auto",userSelect:"text"},table:{width:"100%",borderCollapse:"collapse",backgroundColor:"#ffffff",fontSize:"14px",tableLayout:"fixed",userSelect:"text"},th:{textAlign:"left",padding:"12px 8px",borderBottom:"2px solid #e0e0e0",fontWeight:"600",backgroundColor:"#f5f5f5",position:"sticky",top:0,zIndex:1,cursor:"pointer",userSelect:"none","&:hover":{backgroundColor:"#e8e8e8"}},td:{padding:"12px 8px",borderBottom:"1px solid #e0e0e0",verticalAlign:"top",wordWrap:"break-word",overflow:"hidden",userSelect:"text"},tdTruncated:{overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap","@media (hover: none)":{cursor:"pointer"}},tr:{"&:hover":{backgroundColor:"#f9f9f9"}},emptyState:{padding:"20px",textAlign:"center",color:"#666"},sortIndicator:{marginLeft:"4px",fontSize:"10px"},hideOnMobile:{"@media (max-width: 768px)":{display:"none"}},dialogContent:{wordWrap:"break-word",whiteSpace:"pre-wrap",maxHeight:"60vh",overflowY:"auto"},thumbnail:{maxWidth:"50px",maxHeight:"50px",objectFit:"cover"},tooltip:{maxWidth:"600px",whiteSpace:"normal",wordWrap:"break-word"},editButton:{minWidth:"auto",padding:"4px 8px"},actionsColumn:{width:"100px",textAlign:"center"},filterInput:{width:"100%",padding:"4px 8px",fontSize:"14px",border:"1px solid #e0e0e0",borderRadius:"4px",paddingRight:"28px"},filterWrapper:{position:"relative"},clearFilterButton:{position:"absolute",right:"6px",top:"50%",transform:"translateY(-50%)",minWidth:"auto",height:"20px",padding:"0 6px",lineHeight:"18px"},filterToolbar:{display:"flex",justifyContent:"flex-end",padding:"8px",gap:"8px"},cellWithAction:{display:"flex",alignItems:"center",justifyContent:"space-between",gap:"4px"},actionIcon:{minWidth:"auto",padding:"2px",marginLeft:"4px",flexShrink:0,cursor:"pointer",opacity:.7,"&:hover":{opacity:1}},thumbnailRow:{display:"flex",gap:"4px",flexWrap:"wrap"},cellText:{flex:1,overflow:"hidden",textOverflow:"ellipsis"}}),S=e=>{if(/^\d{4}-\d{2}-\d{2}/.test(e)){const t=new Date(e);if(!isNaN(t.getTime()))return t.getTime()}const t=e.match(/^(\d{1,2})\.(\d{1,2})\.(\d{4})/);if(t){const e=parseInt(t[1],10),n=parseInt(t[2],10)-1,i=parseInt(t[3],10),r=new Date(i,n,e);if(r.getFullYear()===i&&r.getMonth()===n&&r.getDate()===e)return r.getTime()}return null},W=e=>{const t=e.trim().replace(/[\s\u00a0]/g,"");if(""===t||"-"===t)return null;const n=(t.match(/,/g)||[]).length,i=(t.match(/\./g)||[]).length;let r;r=1===n&&0===i?/,\d{1,2}$/.test(t)?t.replace(/,\d+$/,"").replace(/[^0-9-]/g,""):t.replace(/,/g,""):1===i&&0===n?/\.\d{1,2}$/.test(t)?t.replace(/\.\d+$/,"").replace(/[^0-9-]/g,""):t.replace(/\./g,""):t.replace(/[,.]/g,"");const l=Number(r);return""!==r&&isFinite(l)?l:null},I=(e,t)=>{if("string"==typeof t)return e[t];for(const n of t)if(void 0!==e[n])return e[n]},$=a({img:{maxWidth:"40px",maxHeight:"40px",objectFit:"cover",borderRadius:"3px",display:"block"},fileIcon:{width:"24px",height:"24px",verticalAlign:"middle"}}),O=({fileId:t})=>{const[n,i]=l(!0),r=$();return e("a",{href:C.getFileUrl(t),target:"_blank",rel:"noopener noreferrer",children:n?e("img",{src:C.getImageUrl(t,40),alt:"",className:r.img,onError:()=>i(!1)}):e(v,{className:r.fileIcon})})},A=({value:t,options:n,optionsLoader:a,minChars:c=2,maxResults:s=50,columnKey:d,item:p,actualIndex:h,onEnumChange:u,label:m,t:f})=>{const[y,b]=l(t),[w,v]=l([]),[C,k]=l(!1),N=i.useRef(null);o((()=>{b(t)}),[t]),o((()=>{if(a){if(!(y.length<c))return N.current&&clearTimeout(N.current),N.current=setTimeout((async()=>{k(!0);try{const e=await a(y);v(e.slice(0,s))}finally{k(!1)}}),250),()=>{N.current&&clearTimeout(N.current)};v([])}}),[y,a,c,s]);const S=r((()=>(n??[]).filter((e=>e.toLowerCase().includes(y.toLowerCase()))).slice(0,s)),[n,y,s]),W=a?w:S;return e(g,{value:y,freeform:!0,"aria-label":m,placeholder:C?f("Loading..."):a&&y.length<c?f(`Type ${c}+ characters to search...`):void 0,onChange:e=>b(e.target.value),onOptionSelect:(e,t)=>{t.optionValue&&(b(t.optionValue),u&&u(p,d,t.optionValue,h))},onBlur:()=>{u&&u(p,d,y,h)},style:{width:"100%"},children:W.map((t=>e(x,{value:t,children:t},t)))})},L=({data:i,columns:a,canEdit:g,onEdit:x,onDelete:v,onToggleCheckbox:$,onEnumChange:L,onFilteredDataChange:T})=>{const j=N(),{visibleColumns:M,defaultSortIndex:F,defaultSortDirection:D}=r((()=>{const e=i&&i.length>0?Array.from(new Set(i.flatMap((e=>Object.keys(e))))):[],t=(a||e.map((e=>({key:e})))).filter((e=>!e.hidden)),n=t.findIndex((e=>e.defaultSort));return{visibleColumns:t,defaultSortIndex:n,defaultSortDirection:n>=0&&t[n].defaultSort||null}}),[i,a]),[R,B]=l(F>=0?F:null),[E,z]=l(D),[H,P]=l(!1),[Y,U]=l({title:"",text:""}),[V,_]=l({}),[K,J]=l(0),{t:X}=k(),q=e=>e.title?X(e.title):Array.isArray(e.key)?e.key[0]:e.key,G=e=>{const t=[];return e.hideOnMobile&&t.push(j.hideOnMobile),t.join(" ")},Q=(e,t)=>{_((n=>{const i={...n};return""===t.trim()?delete i[e]:i[e]=t,i}))},Z=e=>null==e||"string"==typeof e&&e.startsWith("[")&&e.endsWith("]")?"":"object"==typeof e?JSON.stringify(e):String(e),ee=r((()=>{const e=[...i];if(null!==R&&E){const t=M[R];e.sort(((e,n)=>{const i=I(e,t.key),r=I(n,t.key);if(null==i)return 1;if(null==r)return-1;let l=0;if("string"==typeof i&&"string"==typeof r){const e=S(i),t=S(r);if(null!==e&&null!==t)l=e-t;else{const e=W(i),t=W(r);l=null!==e&&null!==t?e-t:i.localeCompare(r)}}else if("number"==typeof i&&"number"==typeof r)l=i-r;else{const e=W(String(i)),t=W(String(r));l=null!==e&&null!==t?e-t:String(i).localeCompare(String(r))}return"asc"===E?l:-l}))}return e}),[i,R,E,M]),te=r((()=>ee.filter((e=>{for(const[t,n]of Object.entries(V)){const i=parseInt(t),r=M[i],l=I(e,r.key),o=Z(l).toLowerCase(),a=n.toLowerCase();if(!("enum"===r.type&&r.enumOptions?o===a:o.includes(a)))return!1}return!0}))),[ee,V,M]);o((()=>{T&&T(te)}),[te,T]);const ne="undefined"!=typeof window?window.innerHeight-250:600,ie=Math.max(0,Math.floor(K/49)-5),re=Math.min(te.length,Math.ceil((K+ne)/49)+5),le=te.slice(ie,re),oe=49*te.length,ae=49*ie,ce=(e,t)=>{if(void 0!==e.id)return String(e.id);return`row-${t}-${(e=>{let t=0;for(let n=0;n<e.length;n++)t=(t<<5)-t+e.charCodeAt(n),t|=0;return Math.abs(t)})(M.slice(0,3).map((t=>String(I(e,t.key)??""))).join("-"))}`};return i&&0!==i.length?t(n,{children:[e("div",{className:j.container,onScroll:e=>{J(e.currentTarget.scrollTop)},style:{maxHeight:"calc(100vh - 200px)",overflowY:"auto"},children:t("table",{className:j.table,children:[t("thead",{children:[t("tr",{children:[M.map(((n,i)=>{const r=n.maxWidth?{width:`${n.maxWidth}px`,maxWidth:`${n.maxWidth}px`}:{};return t("th",{className:`${j.th} ${G(n)}`.trim(),style:r,onClick:()=>(e=>{R===e?"asc"===E?z("desc"):"desc"===E&&(B(null),z(null)):(B(e),z("asc"))})(i),children:[q(n),R===i&&e("span",{className:j.sortIndicator,children:"asc"===E?"▲":"▼"})]},i)})),g&&e("th",{className:`${j.th} ${j.actionsColumn}`,style:{width:"100px"},children:X("Actions")})]}),t("tr",{children:[M.map(((i,r)=>{const l=i.maxWidth?{width:`${i.maxWidth}px`,maxWidth:`${i.maxWidth}px`}:{};return e("th",{className:G(i),style:l,children:i.filterable&&e("div",{className:j.filterWrapper,children:"enum"===i.type&&i.enumOptions?t(c,{className:j.filterInput,value:V[r]||"",onChange:(e,t)=>Q(r,t.value),onClick:e=>e.stopPropagation(),children:[e("option",{value:"",children:X("All")}),i.enumOptions.filter((e=>""!==e)).map((t=>e("option",{value:t,children:X(t)},t)))]}):t(n,{children:[e("input",{type:"text",className:j.filterInput,placeholder:X("Filter")+"...",value:V[r]||"",onChange:e=>Q(r,e.target.value),onClick:e=>e.stopPropagation()}),(V[r]||"").length>0&&e(s,{appearance:"subtle",className:j.clearFilterButton,onClick:e=>{e.stopPropagation(),(e=>{_((t=>{const n={...t};return delete n[e],n}))})(r)},children:"×"})]})})},r)})),g&&e("th",{className:j.actionsColumn})]})]}),t("tbody",{children:[ie>0&&e("tr",{style:{height:`${ae}px`},children:e("td",{colSpan:M.length+(g?1:0),style:{padding:0,border:"none"}})}),le.map(((n,i)=>{const r=n._index,l="number"==typeof r?r:ie+i;return t("tr",{className:j.tr,children:[M.map(((i,r)=>{const o=I(n,i.key),a=i.format?i.format(o):Z(o),p=i.maxWidth?`${j.td} ${j.tdTruncated} ${G(i)}`.trim():`${j.td} ${G(i)}`.trim(),h=()=>{window.matchMedia("(hover: hover)").matches||i.maxWidth&&a.length>0&&(U({title:q(i),text:a}),P(!0))};if("thumbnail"===i.type){const t=Array.isArray(o)?o:[];return e("td",{className:p,children:e("div",{className:j.thumbnailRow,children:t.map((t=>e(O,{fileId:t},t)))})},r)}if("file"===i.type&&a)return e("td",{className:p,onClick:h,children:e("a",{href:C.getFileUrl(a),target:"_blank",rel:"noopener noreferrer",children:X("Download")})},r);if("checkbox"===i.type){return e("td",{className:p,children:e(d,{checked:!0===o||"true"===o||"yes"===o||"1"===o,onChange:(e,t)=>{$&&$(n,i.key,!0===t.checked,l)}})},r)}if("enum"===i.type&&i.enumOptions&&i.editable)return e("td",{className:p,children:t(c,{value:a,"aria-label":i.title?X(i.title):Array.isArray(i.key)?i.key[0]:i.key,onChange:(e,t)=>{L&&L(n,i.key,t.value,l)},style:{width:"100%"},children:[!i.enumOptions.includes(a)&&a&&e("option",{value:a,children:a}),i.enumOptions.map((t=>e("option",{value:t,children:X(t)},t)))]})},r);if("combobox"===i.type&&i.editable&&(i.enumOptions||i.enumOptionsLoader))return e("td",{className:p,children:e(A,{value:a,options:i.enumOptions,optionsLoader:i.enumOptionsLoader,minChars:i.enumOptionsLoaderMinChars,maxResults:i.enumOptionsLoaderMaxResults,columnKey:i.key,item:n,actualIndex:l,onEnumChange:L,label:i.title?X(i.title):Array.isArray(i.key)?i.key[0]:i.key,t:X})},r);const u=()=>i.maxWidth&&a.length>0?e(y,{content:{children:a,style:{maxWidth:"600px",whiteSpace:"normal"}},relationship:"description",children:e("span",{children:a})}):a,m=()=>{if(!i.action)return null;const t=i.action,r=i.action.icon,l=e(s,{appearance:"subtle",icon:e(r,{}),className:j.actionIcon,onClick:e=>{e.stopPropagation(),t.onClick(n)},size:"small"});return t.tooltip?e(y,{content:X(t.tooltip),relationship:"label",children:l}):l};return e("td",{className:p,onClick:h,children:i.action?t("div",{className:j.cellWithAction,children:[i.action.iconLeft&&m(),e("span",{className:j.cellText,children:u()}),!i.action.iconLeft&&m()]}):u()},r)})),g&&(x||v)&&e("td",{className:`${j.td} ${j.actionsColumn}`,children:t("div",{style:{display:"flex",gap:"4px",justifyContent:"center"},children:[x&&e(s,{appearance:"subtle",icon:e(b,{}),className:j.editButton,onClick:()=>x(n,l),title:X("Edit")}),v&&e(s,{appearance:"subtle",icon:e(w,{}),className:j.editButton,onClick:()=>v(n,l),title:X("Delete")})]})})]},ce(n,l))})),re<te.length&&e("tr",{style:{height:oe-ae-49*le.length+"px"},children:e("td",{colSpan:M.length+(g?1:0),style:{padding:0,border:"none"}})})]})]})}),e(p,{open:H,onOpenChange:(e,t)=>P(t.open),children:e(h,{children:t(u,{children:[e(m,{children:Y.title}),e(f,{className:j.dialogContent,children:Y.text})]})})})]}):e("div",{className:j.emptyState,children:X("No data to display")})};var T=i.memo(L);export{L as ListView,T as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RecordModal.d.ts","sourceRoot":"","sources":["../../../src/components/RecordModal.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAuC,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"RecordModal.d.ts","sourceRoot":"","sources":["../../../src/components/RecordModal.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAuC,MAAM,OAAO,CAAC;AAqB5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAwJ9C,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CA+KlD,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as e,jsxs as
|
|
1
|
+
import{jsx as e,jsxs as a}from"react/jsx-runtime";import r,{useState as n,useEffect as l,useMemo as t}from"react";import{makeStyles as o,tokens as i,Dialog as c,DialogSurface as s,DialogBody as d,DialogTitle as m,DialogContent as u,Field as p,Checkbox as h,Textarea as f,Select as g,Input as y,DialogActions as b,Button as x,Combobox as v,Option as C}from"@fluentui/react-components";import{Attach24Regular as k}from"@fluentui/react-icons";import w from"../hooks/useLocalization.js";import{CodicentService as N}from"../services/codicent.js";const L=o({surface:{backgroundColor:i.colorNeutralBackground1,width:"min(calc(100vw - 32px), 560px)",maxWidth:"calc(100vw - 32px)"},content:{display:"flex",flexDirection:"column",gap:"16px",minWidth:"0",maxHeight:"60vh",overflowY:"auto"},field:{display:"flex",flexDirection:"column"},thumbnailRow:{display:"flex",flexWrap:"wrap",gap:"6px",marginTop:"4px"},thumbnailImg:{maxWidth:"60px",maxHeight:"60px",objectFit:"cover",borderRadius:"4px",display:"block"},thumbnailIcon:{width:"32px",height:"32px",verticalAlign:"middle"}}),O=({fileId:a,imgClassName:r,iconClassName:l})=>{const[t,o]=n(!0);return e("a",{href:N.getFileUrl(a),target:"_blank",rel:"noopener noreferrer",children:t?e("img",{src:N.getImageUrl(a,60),alt:`File attachment ${a}`,className:r,onError:()=>o(!1)}):e(k,{className:l})})},A=({value:a,options:o,optionsLoader:i,minChars:c=2,maxResults:s=50,label:d,onChange:m,t:u})=>{const[p,h]=n(a),[f,g]=n([]),[y,b]=n(!1),x=r.useRef(null);l((()=>{h(a)}),[a]),l((()=>{if(i){if(!(p.length<c))return x.current&&clearTimeout(x.current),x.current=setTimeout((async()=>{b(!0);try{const e=await i(p);g(e.slice(0,s))}finally{b(!1)}}),250),()=>{x.current&&clearTimeout(x.current)};g([])}}),[p,i,c,s]);const k=t((()=>(o??[]).filter((e=>e.toLowerCase().includes(p.toLowerCase()))).slice(0,s)),[o,p,s]),w=i?f:k;return e(v,{value:p,freeform:!0,"aria-label":d,placeholder:y?u("Loading..."):i&&p.length<c?u(`Type ${c}+ characters to search...`):void 0,onChange:e=>h(e.target.value),onOptionSelect:(e,a)=>{a.optionValue&&(h(a.optionValue),m(a.optionValue))},onBlur:()=>m(p),style:{width:"100%"},children:w.map((a=>e(C,{value:a,children:a},a)))})},R=({open:r,onClose:t,onSave:o,columns:i,initialData:v,title:C})=>{const k=L(),{t:N}=w(),[R,S]=n({}),[I,T]=n(!1);l((()=>{r&&S(v||{})}),[r,v]);const j=e=>Array.isArray(e.key)?e.key[0]:e.key,E=e=>{if(Array.isArray(e.key))for(const a of e.key)if(void 0!==R[a])return a;return j(e)},F=(e,a)=>{const r=E(e);S((e=>({...e,[r]:a})))},W=i.filter((e=>!e.hidden&&"file"!==e.type&&"thumbnail"!==e.type&&"createdAt"!==j(e))),D=i.filter((e=>!e.hidden&&"thumbnail"===e.type));return e(c,{open:r,onOpenChange:(e,a)=>!I&&!1===a.open&&t(),children:e(s,{className:k.surface,backdrop:{style:{backgroundColor:"rgba(0, 0, 0, 0.4)"}},children:a(d,{children:[e(m,{children:C||N(v?"Edit Record":"Add Record")}),a(u,{className:k.content,children:[D.map(((a,r)=>{const n=j(a),l=a.title||n,t=v?.[n],o=Array.isArray(t)?t:[];return 0===o.length?null:e(p,{label:l,className:k.field,children:e("div",{className:k.thumbnailRow,children:o.map((a=>e(O,{fileId:a,imgClassName:k.thumbnailImg,iconClassName:k.thumbnailIcon},a)))})},`thumb-${r}`)})),W.map(((a,r)=>{const n=j(a),l=(e=>{const a=E(e);return R[a]})(a),t=a.title||n;return"checkbox"===a.type?e(p,{label:t,className:k.field,children:e(h,{checked:!0===l||"true"===l||"yes"===l||"1"===l,onChange:(e,r)=>F(a,r.checked)})},r):"textarea"===a.type?e(p,{label:t,className:k.field,children:e(f,{value:String(l??""),rows:a.rows??3,onChange:(e,r)=>F(a,r.value),placeholder:N("Enter")+" "+t.toLowerCase(),resize:"vertical"})},r):"enum"===a.type&&a.enumOptions?e(p,{label:t,className:k.field,children:e(g,{value:String(l??""),onChange:(e,r)=>F(a,r.value),children:a.enumOptions.map((a=>e("option",{value:a,children:a||N("(None)")},a)))})},r):"combobox"===a.type&&(a.enumOptions||a.enumOptionsLoader)?e(p,{label:t,className:k.field,children:e(A,{value:String(l??""),options:a.enumOptions,optionsLoader:a.enumOptionsLoader,minChars:a.enumOptionsLoaderMinChars,maxResults:a.enumOptionsLoaderMaxResults,label:t,onChange:e=>F(a,e),t:N})},r):e(p,{label:t,className:k.field,children:e(y,{value:String(l??""),onChange:(e,r)=>F(a,r.value),placeholder:N("Enter")+" "+t.toLowerCase()})},r)}))]}),a(b,{children:[e(x,{appearance:"secondary",onClick:t,disabled:I,children:N("Cancel")}),e(x,{appearance:"primary",onClick:async()=>{T(!0);try{await o(R),t()}catch(e){console.error("Failed to save record:",e)}finally{T(!1)}},disabled:I,children:N(I?"Saving...":"Save")})]})]})})})};export{R as RecordModal,R as default};
|
|
@@ -13,6 +13,55 @@ export interface ListPageProps {
|
|
|
13
13
|
/** Optional data filter applied after fetch. Useful for app-specific filtering (e.g. empty notes). */
|
|
14
14
|
filterData?: (data: DataMessage[], tag: string) => DataMessage[];
|
|
15
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* ListPage — data fetch & cache behaviour
|
|
18
|
+
*
|
|
19
|
+
* ## Fetch key guard
|
|
20
|
+
* A `fetchKey` string (`tag-contentTitle-loadAll-refreshKey-debouncedSearch`) is stored in
|
|
21
|
+
* `lastFetchKey` (ref). The fetch effect bails out early if the key hasn't changed, preventing
|
|
22
|
+
* duplicate calls when unrelated state updates re-render the component.
|
|
23
|
+
* The ref is reset to `""` on effect cleanup (unmount / dep change) so that re-navigation
|
|
24
|
+
* always triggers a fresh fetch.
|
|
25
|
+
*
|
|
26
|
+
* ## Race-condition protection
|
|
27
|
+
* `activeFetchId` (ref) is incremented each time a new fetch starts. Each in-flight promise
|
|
28
|
+
* captures its own `myFetchId` and checks `isActive()` before writing state. A superseded
|
|
29
|
+
* fetch (e.g. from rapid search typing or quick navigation) silently discards its result
|
|
30
|
+
* without calling `setSearching(false)`, so the spinner stays visible until the winning fetch
|
|
31
|
+
* completes.
|
|
32
|
+
*
|
|
33
|
+
* ## Cache strategy
|
|
34
|
+
* | Visit | Cache present? | Behaviour |
|
|
35
|
+
* |-------|---------------|-----------|
|
|
36
|
+
* | First | No | `searching=true` → API call → populate cache → show list |
|
|
37
|
+
* | First | Yes | Instant render from cache (no spinner) → background delta-fetch for records newer than the latest cached timestamp → silently prepend new rows |
|
|
38
|
+
* | Back-navigation | Yes | Unmount cleanup resets fetchKey → same as "First, cache present" |
|
|
39
|
+
* | Back-navigation | Expired | Same as "First, no cache" |
|
|
40
|
+
* | Refresh button | Any | Clears cache for tag + resets fetchKey + increments `refreshKey` → full API call |
|
|
41
|
+
*
|
|
42
|
+
* ## Search / filter flow
|
|
43
|
+
* - Typing triggers a 500 ms debounce before `debouncedSearch` updates.
|
|
44
|
+
* - `debouncedSearch` change → new fetchKey → new `activeFetchId` → previous in-flight
|
|
45
|
+
* fetch is superseded and its result discarded.
|
|
46
|
+
* - `filter_<field>=<value>` URL params are applied client-side after fetch (not sent to API)
|
|
47
|
+
* except for `filter_<tag>=<value>` which seeds `debouncedSearch` for server-side filtering.
|
|
48
|
+
* - `q=` URL param is kept in sync with the search box via a debounced `setSearchParams`
|
|
49
|
+
* call that preserves all other existing params (`canAdd`, `canEdit`, `filter_*`, etc.).
|
|
50
|
+
*
|
|
51
|
+
* ## URL params (all optional)
|
|
52
|
+
* | Param | Type | Default | Purpose |
|
|
53
|
+
* |-------|------|---------|---------|
|
|
54
|
+
* | `tag` | string | `"logbook"` | Data tag to query |
|
|
55
|
+
* | `title` | string | `"Loggbok"` | Page heading |
|
|
56
|
+
* | `contentTitle` | string | — | If set, fetches raw messages and maps this field as the display column |
|
|
57
|
+
* | `loadAll` | `"true"` | — | Removes PAGE_SIZE cap; disables Load-more |
|
|
58
|
+
* | `canAdd` | `"true"` | — | Shows Add Record button (opens RecordModal) |
|
|
59
|
+
* | `canEdit` | `"true"` | — | Shows per-row Edit/Delete buttons |
|
|
60
|
+
* | `canExport` | `"false"` to hide | visible | Shows Export to Excel button |
|
|
61
|
+
* | `addUrl` | string | — | External URL opened on Add click (alternative to modal) |
|
|
62
|
+
* | `q` | string | — | Initial search term; kept in sync with search box |
|
|
63
|
+
* | `filter_<field>` | string | — | Client-side row filter; `%USERNAME%` resolves to current user |
|
|
64
|
+
*/
|
|
16
65
|
export declare const ListPage: ({ state, getColumnDefs, getListConfig, filterData }: ListPageProps) => import("react/jsx-runtime").JSX.Element;
|
|
17
66
|
export default ListPage;
|
|
18
67
|
//# sourceMappingURL=ListPage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ListPage.d.ts","sourceRoot":"","sources":["../../../src/pages/ListPage.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAuB3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAkE3D,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,gBAAgB,CAAC;IACxB,+FAA+F;IAC/F,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,gBAAgB,EAAE,CAAC;IACpD;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,UAAU,GAAG,SAAS,CAAC;IACxD,sGAAsG;IACtG,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE,GAAG,EAAE,MAAM,KAAK,WAAW,EAAE,CAAC;CAClE;AAED,eAAO,MAAM,QAAQ,wDAAyD,aAAa,
|
|
1
|
+
{"version":3,"file":"ListPage.d.ts","sourceRoot":"","sources":["../../../src/pages/ListPage.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAuB3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAkE3D,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,gBAAgB,CAAC;IACxB,+FAA+F;IAC/F,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,gBAAgB,EAAE,CAAC;IACpD;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,UAAU,GAAG,SAAS,CAAC;IACxD,sGAAsG;IACtG,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE,GAAG,EAAE,MAAM,KAAK,WAAW,EAAE,CAAC;CAClE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,eAAO,MAAM,QAAQ,wDAAyD,aAAa,4CA+mB1F,CAAC;AAEF,eAAe,QAAQ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as t,jsxs as e}from"react/jsx-runtime";import{useState as o,useRef as n,useMemo as r,useEffect as i,useCallback as a}from"react";import"../components/Markdown.js";import"../components/Textarea.js";import"../components/Button.js";import"../components/CompoundButton.js";import{makeStyles as s,Button as c,Dialog as l,DialogSurface as d,DialogBody as m,DialogTitle as p,DialogContent as u,DialogActions as g}from"@fluentui/react-components";import"../components/Spinner.js";import f from"../components/TextHeader.js";import"../components/TypingIndicator.js";import"../components/Dialog.js";import"../components/ChatInput.js";import"../components/CombinedPlaceholderDialog.js";import"../components/ChatMessage.js";import"../components/Header.js";import{ArrowLeft24Regular as h,ArrowClockwise24Regular as j,ArrowDownload24Regular as x,Add24Regular as w}from"@fluentui/react-icons";import"../services/codicent.js";import{dataCache as y}from"../services/dataCache.js";import C from"../utils/MessageContent.js";import"../node_modules/tinycolor2/esm/tinycolor.js";import"../_virtual/index.js";import"../config/index.js";import"../utils/cacheManager.js";import"../lib/wavtools/lib/wav_packer.js";import"../lib/wavtools/lib/analysis/audio_analysis.js";import"../lib/wavtools/lib/wav_stream_player.js";import"../lib/wavtools/lib/wav_recorder.js";import{exportToExcel as A}from"../utils/excelExport.js";import"./AppFrame.js";import"./Canvas.js";import"./Chat.js";import"./Compose.js";import"./Snap.js";import"./Search.js";import"./Menu.js";import"./Log.js";import"./Login.js";import"./Home.js";import"./CrmPage.js";import"./CrmPagePersistent.js";import"./ImageView.js";import"./FormInvite.js";import"./FormAccept.js";import"./Sales.js";import{useSearchParams as S,useNavigate as v}from"react-router-dom";import"./Purchase.js";import"../components/Content.js";import{Page as k}from"../components/Page.js";import"./QrScan.js";import b from"../hooks/useLocalization.js";import"../components/FileThumbnail.js";import"react-dom/client";import"../node_modules/@auth0/auth0-react/dist/auth0-react.esm.js";import"../hooks/useAppStyles.js";import{useUserRoles as D}from"../hooks/useUserRoles.js";import"../components/MessageInput.js";import"../components/UploadFile.js";import"../components/SnapFooter.js";import"../components/Profile.js";import"../components/MessageItem.js";import"../components/AiInput.js";import M from"../components/SearchBox.js";import"../components/DataMessagePicker.js";import"../components/HtmlView.js";import"../components/Footer.js";import"../components/QrCodeDialog.js";import"../components/QrScanner.js";import"../components/OfflineMessage.js";import"../components/LanguageSelector.js";import I from"../components/ListView.js";import{RecordModal as _}from"../components/RecordModal.js";import"../components/BulkUploadDialog.js";import"../components/CookieBanner.js";import"../components/audit/AuditCircularProgress.js";import"../components/audit/AuditHorizontalProgress.js";import"../components/audit/AuditRoleIndicator.js";import"../components/audit/AuditUnitSwitcher.js";import"../components/audit/AuditAnswerCell.js";import"../components/audit/AuditSearchBar.js";import"../components/audit/AuditFilterChips.js";import"../components/audit/AuditFilterBar.js";import"../components/audit/AuditGroupsProgress.js";import"../components/audit/AuditSummaryDashboard.js";import"../components/audit/AuditRequirementDialog.js";import"../components/audit/AuditUnitExportDialog.js";import"../components/audit/AuditUnitImportDialog.js";import"../components/audit/AuditBulkExportDialog.js";import"../components/audit/AuditBulkUploadDialog.js";import"../components/audit/AuditSortPresets.js";import{l as T}from"../node_modules/lodash/lodash.js";const $=s({container:{width:"100%",flex:1,maxWidth:"100%",height:"100%",minHeight:0,backgroundColor:"#ffffff",display:"flex",flexDirection:"column",margin:"0 auto",overflow:"hidden","@media (max-width: 768px)":{maxWidth:"100%",borderRadius:"0"},touchAction:"pan-y",paddingLeft:"0",paddingRight:"0"},listContainer:{overflow:"hidden",flex:1,minHeight:0,marginTop:"10px"},headerRow:{display:"flex",justifyContent:"space-between",alignItems:"center",gap:"10px",flexWrap:"wrap"},buttonGroup:{display:"flex",gap:"8px",flexWrap:"wrap"},addButton:{minWidth:"auto",whiteSpace:"nowrap"},recordsCount:{fontSize:"14px",color:"#666",marginTop:"8px"},backButton:{marginBottom:"10px"},searchBox:{marginTop:"8px"},loadMoreContainer:{display:"flex",justifyContent:"center",padding:"16px 0",borderTop:"1px solid #e0e0e0",marginTop:"4px"}}),P=500,B=({state:s,getColumnDefs:B,getListConfig:E,filterData:N})=>{const[R,L]=S(),F=R.get("tag")||"logbook",U=R.get("title")||"",H=R.get("contentTitle"),O="true"===R.get("loadAll"),W="true"===R.get("canAdd"),q="true"===R.get("canEdit"),z="false"!==R.get("canExport"),V=R.get("addUrl")||"",G=R.get("q")||"",[J,Q]=o(G),[K,X]=o(G),{service:Y}=s,[Z,tt]=o([]),[et,ot]=o(!1),[nt,rt]=o(!1),[it,at]=o(!1),st=n(null),ct=n(G),lt=n(""),dt=n(!0),[mt,pt]=o(0),[ut,gt]=o(null),ft=$(),{t:ht}=b(),jt=v(),{getCurrentUserName:xt}=D(Y,s.context.nickname,s.context.selectedApp),wt=r((()=>(H?[{key:H,title:H,maxWidth:250}]:E?E(F)?.columns??[]:B?B(F):[]).map((t=>({...t,title:t.title?ht(t.title):void 0})))),[H,F,ht,B,E]),[yt,Ct]=o(!1),[At,St]=o(null),[vt,kt]=o(!1),[bt,Dt]=o(null),Mt=r((()=>`listpage_searches_${F}`),[F]),It=t=>{try{const e=localStorage.getItem(t);return e?JSON.parse(e):[]}catch{return[]}},[_t,Tt]=o((()=>It(Mt)));i((()=>{Tt(It(Mt))}),[Mt]);const $t=a((t=>{const e=t.trim();e&&Tt((t=>{const o=[e,...t.filter((t=>t!==e))].slice(0,20);try{localStorage.setItem(Mt,JSON.stringify(o))}catch{}return o}))}),[Mt]),Pt=a((t=>{Tt((e=>{const o=e.filter((e=>e!==t));try{localStorage.setItem(Mt,JSON.stringify(o))}catch{}return o}))}),[Mt]),Bt=r((()=>T.debounce((t=>X(t)),500)),[X]);i((()=>()=>{Bt.cancel()}),[Bt]);const Et=a((t=>{Q(t),Bt(t)}),[Bt]),Nt=a((t=>{$t(t)}),[$t]);i((()=>{if(!R.get("q")){const t=R.get(`filter_${F}`);if(t){let e=t;if("%USERNAME%"===e){const t=xt();if(!t)return;e=t}Q(e),X(e),ct.current=e}}}),[F,R,xt]),i((()=>{const t=R.get("q")||"";t!==ct.current&&(Q(t),X(t),ct.current=t,lt.current="")}),[R]),i((()=>(st.current&&clearTimeout(st.current),st.current=setTimeout((()=>{if(ct.current!==J){const t={title:U,tag:F};H&&(t.contentTitle=H),J&&(t.q=J),O&&(t.loadAll="true"),L(t,{replace:!0}),ct.current=J}}),500),()=>{st.current&&clearTimeout(st.current)})),[J,F,U,H,O,L]),i((()=>{dt.current=!0;const t=`${F}-${H}-${O}-${mt}-${K}`;if(t===lt.current)return;lt.current=t;const e=H?`${F}-${K}-${H}`:`${F}-${K||"all"}`,o=y.get(e);if(!o){if(rt(!1),ot(!0),H)Y.getMessagesFast([F],K).then((t=>{if(!dt.current)return void ot(!1);const o=t.map((t=>{const e=new Date(t.createdAt).toLocaleString();return{id:t.id,data:{[H]:new C(t.content).content,createdAt:e},fileId:null,fileIds:[],tags:[F],mentions:[Y.codicent],createdAt:e}}));y.set(e,o),dt.current&&tt(o)})).catch(console.warn).finally((()=>ot(!1)));else{const t=K||"",o=O||t?void 0:P;Y.readDataMessages(F,t,void 0,0,o).then((o=>{y.set(e,o),dt.current?(tt(o),rt(!O&&!t&&o.length===P)):ot(!1)})).catch(console.warn).finally((()=>ot(!1)))}return()=>{dt.current=!1}}if(tt(o),rt(!O&&!H&&o.length>=P),!H&&!K&&o.length>0){const t=o.reduce(((t,e)=>e.createdAt>t?e.createdAt:t),o[0].createdAt);Y.readDataMessages(F,"",void 0,void 0,void 0,t).then((t=>{dt.current&&tt((o=>{const n=new Set(o.map((t=>t.id))),r=t.filter((t=>!n.has(t.id)));if(0===r.length)return o;const i=[...r,...o];return y.set(e,i),i}))})).catch(console.warn)}}),[Y,F,H,O,K,mt]);const Rt=r((()=>{const t={};R.forEach(((e,o)=>{o.startsWith("filter_")&&(t[o.replace("filter_","")]=e)}));let e=Z.map(((t,e)=>({item:t,index:e})));for(const[o,n]of Object.entries(t)){const t=n.replace("%USERNAME%",xt()),r=s.context.nickname||"";e=e.filter((({item:e})=>{const n=e.data[o];return null!=n&&(String(n).includes(t)||String(n).includes(r))}))}if(N){const t=N(e.map((({item:t})=>t)),F),o=new Set(t.map((t=>t.id)));e=e.filter((({item:t})=>o.has(t.id)))}const o=e.map((({item:t,index:e})=>({...t.data,createdAt:t.createdAt,_id:t.id,originalMessageId:t.originalMessageId||t.id,_fileIds:t.fileIds??[],_index:e}))),n=E?.(F)?.deduplicateBy;if(n){const t=Array.isArray(n)?n:[n],e=e=>{for(const o of t){const t=e[o];if(null!=t&&""!==String(t).trim())return String(t)}},r=new Set;return o.filter((t=>{const o=e(t);return void 0===o||!r.has(o)&&(r.add(o),!0)}))}return o}),[Z,R,s.context.nickname,xt,N,F,E]),Lt=r((()=>{const t=(J||"").trim().toLowerCase();if(!t)return Rt;const e=wt.filter((t=>!t.hidden)).map((t=>t.key));return Rt.filter((o=>{for(const n of e)if(Array.isArray(n))for(const e of n){const n=o[e];if(null!=n&&String(n).toLowerCase().includes(t))return!0}else{const e=o[n];if(null!=e&&String(e).toLowerCase().includes(t))return!0}return!1}))}),[Rt,J,wt]),Ft=a((()=>{y.clearPattern(F),lt.current="",pt((t=>t+1))}),[F]),Ut=a((async()=>{at(!0);try{const t=await Y.readDataMessages(F,"",void 0,Z.length,P),e=[...Z,...t];tt(e),y.set(`${F}-all`,e),rt(t.length===P)}catch(t){console.warn(t)}finally{at(!1)}}),[Z,Y,F]),Ht=a((t=>{gt(t)}),[]),Ot=()=>{kt(!1),Dt(null)},Wt=a((async()=>{const t=`${F}_${(new Date).toISOString().split("T")[0]}`.replace(/[/\\:*?"<>|]/g,"_");const e=null!==ut?ut:Lt;await A(e,wt,t,ht)||console.warn("No data to export")}),[ut,Lt,wt,F,ht]),qt=r((()=>null!==ut?ut.length:Lt.length),[ut,Lt]);return t(k,{hideHeader:!0,children:e("div",{className:ft.container,children:[t("div",{className:ft.backButton,children:t(c,{appearance:"subtle",icon:t(h,{}),onClick:()=>jt(-1),children:ht("Tillbaka")})}),e("div",{className:ft.headerRow,children:[t(f,{title:ht(U||"Loggbok")}),e("div",{className:ft.buttonGroup,children:[t(c,{appearance:"subtle",icon:t(j,{}),onClick:Ft,title:ht("Refresh"),children:ht("Refresh")}),z&&t(c,{appearance:"subtle",icon:t(x,{}),onClick:Wt,title:ht("Export to Excel"),children:ht("Export to Excel")}),(W||V)&&t(c,{appearance:"primary",icon:t(w,{}),onClick:W?()=>{St(null),Ct(!0)}:()=>window.open(V,"_blank"),className:ft.addButton,children:ht("Add Record")})]})]}),t("div",{className:ft.searchBox,children:t(M,{placeholder:ht("Sök")+"...",value:J,onChange:Et,recentSearches:_t,onCommitSearch:Nt,onRemoveRecentSearch:Pt})}),!et&&e("div",{className:ft.recordsCount,children:[ht("Total"),": ",qt," ",ht("records"),qt!==Z.length&&` (${ht("filtered from")} ${Z.length})`]}),e("div",{className:ft.listContainer,children:[et&&t("p",{children:ht("Söker")+"..."}),!et&&t(I,{data:Lt,columns:wt,canEdit:q,onEdit:(t,e)=>{const o=Z[e];o&&(St({data:{...o.data},index:e}),Ct(!0))},onDelete:(t,e)=>{const o=Z[e];o&&(Dt({index:e,id:o.id}),kt(!0))},onToggleCheckbox:async(t,e,o,n)=>{const r=Z[n];if(r){const t=Array.isArray(e)?e[0]:e,i={...r.data,[t]:String(o)},a=await Y.updateDataMessage(r.id,i);tt((t=>{const e=[...t];return e[n]={...r,id:a,data:i},e})),y.clearPattern(F)}},onEnumChange:async(t,e,o,n)=>{const r=Z[n];if(r){const t=Array.isArray(e)?e[0]:e,i={...r.data,[t]:o},a=await Y.updateDataMessage(r.id,i);tt((t=>{const e=[...t];return e[n]={...r,id:a,data:i},e})),y.clearPattern(F)}},onFilteredDataChange:Ht})]}),nt&&!J.trim()&&t("div",{className:ft.loadMoreContainer,children:t(c,{appearance:"primary",size:"medium",onClick:Ut,disabled:it,children:it?ht("Laddar..."):ht("Visa fler")+` (${Z.length} ${ht("laddade")})`})}),t(_,{open:yt,onClose:()=>Ct(!1),onSave:async t=>{if(At){const e=Z[At.index];if(e){const o={};for(const e in t){const n=t[e];o[e]=null==n?"":String(n)}const n=await Y.updateDataMessage(e.id,o);tt((t=>{const r=[...t];return r[At.index]={...e,id:n,data:o},r})),y.clearPattern(F)}}else{const e={};for(const o in t){const n=t[o];e[o]=null==n?"":String(n)}const o={id:await Y.createDataMessage(F,e),data:e,createdAt:(new Date).toISOString(),fileId:null,fileIds:[],tags:[F],mentions:[Y.codicent]};tt((t=>[o,...t])),y.clearPattern(F)}},columns:wt,initialData:At?.data}),t(l,{open:vt,onOpenChange:(t,e)=>!e.open&&Ot(),children:t(d,{children:e(m,{children:[t(p,{children:ht("Confirm Delete")}),t(u,{children:ht("Are you sure you want to delete this record? This action cannot be undone.")}),e(g,{children:[t(c,{appearance:"secondary",onClick:Ot,children:ht("Cancel")}),t(c,{appearance:"primary",onClick:async()=>{if(bt)try{await Y.deleteDataMessage(bt.id),tt((t=>t.filter(((t,e)=>e!==bt.index)))),y.clearPattern(F)}catch(t){console.error("Failed to delete record:",t)}finally{kt(!1),Dt(null)}},children:ht("Delete")})]})]})})})]})})};export{B as ListPage,B as default};
|
|
1
|
+
import{jsx as t,jsxs as e}from"react/jsx-runtime";import{useState as o,useRef as n,useMemo as r,useEffect as i,useCallback as a}from"react";import"../components/Markdown.js";import"../components/Textarea.js";import"../components/Button.js";import"../components/CompoundButton.js";import{makeStyles as s,Button as c,Dialog as l,DialogSurface as d,DialogBody as m,DialogTitle as p,DialogContent as u,DialogActions as g}from"@fluentui/react-components";import"../components/Spinner.js";import f from"../components/TextHeader.js";import"../components/TypingIndicator.js";import"../components/Dialog.js";import"../components/ChatInput.js";import"../components/CombinedPlaceholderDialog.js";import"../components/ChatMessage.js";import"../components/Header.js";import{ArrowLeft24Regular as h,ArrowClockwise24Regular as j,ArrowDownload24Regular as x,Add24Regular as y}from"@fluentui/react-icons";import"../services/codicent.js";import{dataCache as w}from"../services/dataCache.js";import S from"../utils/MessageContent.js";import"../node_modules/tinycolor2/esm/tinycolor.js";import"../_virtual/index.js";import"../config/index.js";import"../utils/cacheManager.js";import"../lib/wavtools/lib/wav_packer.js";import"../lib/wavtools/lib/analysis/audio_analysis.js";import"../lib/wavtools/lib/wav_stream_player.js";import"../lib/wavtools/lib/wav_recorder.js";import{exportToExcel as A}from"../utils/excelExport.js";import"./AppFrame.js";import"./Canvas.js";import"./Chat.js";import"./Compose.js";import"./Snap.js";import"./Search.js";import"./Menu.js";import"./Log.js";import"./Login.js";import"./Home.js";import"./CrmPage.js";import"./CrmPagePersistent.js";import"./ImageView.js";import"./FormInvite.js";import"./FormAccept.js";import"./Sales.js";import{useSearchParams as C,useNavigate as k}from"react-router-dom";import"./Purchase.js";import"../components/Content.js";import{Page as v}from"../components/Page.js";import"./QrScan.js";import b from"../hooks/useLocalization.js";import"../components/FileThumbnail.js";import"react-dom/client";import"../node_modules/@auth0/auth0-react/dist/auth0-react.esm.js";import"../hooks/useAppStyles.js";import{useUserRoles as D}from"../hooks/useUserRoles.js";import"../components/MessageInput.js";import"../components/UploadFile.js";import"../components/SnapFooter.js";import"../components/Profile.js";import"../components/MessageItem.js";import"../components/AiInput.js";import I from"../components/SearchBox.js";import"../components/DataMessagePicker.js";import"../components/HtmlView.js";import"../components/Footer.js";import"../components/QrCodeDialog.js";import"../components/QrScanner.js";import"../components/OfflineMessage.js";import"../components/LanguageSelector.js";import M from"../components/ListView.js";import{RecordModal as _}from"../components/RecordModal.js";import"../components/BulkUploadDialog.js";import"../components/CookieBanner.js";import"../components/audit/AuditCircularProgress.js";import"../components/audit/AuditHorizontalProgress.js";import"../components/audit/AuditRoleIndicator.js";import"../components/audit/AuditUnitSwitcher.js";import"../components/audit/AuditAnswerCell.js";import"../components/audit/AuditSearchBar.js";import"../components/audit/AuditFilterChips.js";import"../components/audit/AuditFilterBar.js";import"../components/audit/AuditGroupsProgress.js";import"../components/audit/AuditSummaryDashboard.js";import"../components/audit/AuditRequirementDialog.js";import"../components/audit/AuditUnitExportDialog.js";import"../components/audit/AuditUnitImportDialog.js";import"../components/audit/AuditBulkExportDialog.js";import"../components/audit/AuditBulkUploadDialog.js";import"../components/audit/AuditSortPresets.js";import{l as P}from"../node_modules/lodash/lodash.js";const $=s({container:{width:"100%",flex:1,maxWidth:"100%",height:"100%",minHeight:0,backgroundColor:"#ffffff",display:"flex",flexDirection:"column",margin:"0 auto",overflow:"hidden","@media (max-width: 768px)":{maxWidth:"100%",borderRadius:"0"},touchAction:"pan-y",paddingLeft:"0",paddingRight:"0"},listContainer:{overflow:"hidden",flex:1,minHeight:0,marginTop:"10px"},headerRow:{display:"flex",justifyContent:"space-between",alignItems:"center",gap:"10px",flexWrap:"wrap"},buttonGroup:{display:"flex",gap:"8px",flexWrap:"wrap"},addButton:{minWidth:"auto",whiteSpace:"nowrap"},recordsCount:{fontSize:"14px",color:"#666",marginTop:"8px"},backButton:{marginBottom:"10px"},searchBox:{marginTop:"8px"},loadMoreContainer:{display:"flex",justifyContent:"center",padding:"16px 0",borderTop:"1px solid #e0e0e0",marginTop:"4px"}}),T=500,B=({state:s,getColumnDefs:B,getListConfig:E,filterData:N})=>{const[R,L]=C(),F=R.get("tag")||"logbook",U=R.get("title")||"",H=R.get("contentTitle"),O="true"===R.get("loadAll"),W="true"===R.get("canAdd"),q="true"===R.get("canEdit"),z="false"!==R.get("canExport"),V=R.get("addUrl")||"",G=R.get("q")||"",[J,Q]=o(G),[K,X]=o(G),{service:Y}=s,[Z,tt]=o([]),[et,ot]=o(!1),[nt,rt]=o(!1),[it,at]=o(!1),st=n(null),ct=n(G),lt=n(""),dt=n(0),mt=n(Y);mt.current=Y;const pt=!!Y,[ut,gt]=o(0),[ft,ht]=o(null),jt=$(),{t:xt}=b(),yt=k(),{getCurrentUserName:wt}=D(Y,s.context.nickname,s.context.selectedApp),St=r((()=>(H?[{key:H,title:H,maxWidth:250}]:E?E(F)?.columns??[]:B?B(F):[]).map((t=>({...t,title:t.title?xt(t.title):void 0})))),[H,F,xt,B,E]),[At,Ct]=o(!1),[kt,vt]=o(null),[bt,Dt]=o(!1),[It,Mt]=o(null),_t=r((()=>`listpage_searches_${F}`),[F]),Pt=t=>{try{const e=localStorage.getItem(t);return e?JSON.parse(e):[]}catch{return[]}},[$t,Tt]=o((()=>Pt(_t)));i((()=>{Tt(Pt(_t))}),[_t]);const Bt=a((t=>{const e=t.trim();e&&Tt((t=>{const o=[e,...t.filter((t=>t!==e))].slice(0,20);try{localStorage.setItem(_t,JSON.stringify(o))}catch{}return o}))}),[_t]),Et=a((t=>{Tt((e=>{const o=e.filter((e=>e!==t));try{localStorage.setItem(_t,JSON.stringify(o))}catch{}return o}))}),[_t]),Nt=r((()=>P.debounce((t=>X(t)),500)),[X]);i((()=>()=>{Nt.cancel()}),[Nt]);const Rt=a((t=>{Q(t),Nt(t)}),[Nt]),Lt=a((t=>{Bt(t)}),[Bt]);i((()=>{if(!R.get("q")){const t=R.get(`filter_${F}`);if(t){let e=t;if("%USERNAME%"===e){const t=wt();if(!t)return;e=t}Q(e),X(e),ct.current=e}}}),[F,R,wt]),i((()=>{const t=R.get("q")||"";t!==ct.current&&t!==K&&(Q(t),X(t),ct.current=t,lt.current="")}),[R]),i((()=>(st.current&&clearTimeout(st.current),st.current=setTimeout((()=>{if(ct.current!==J){const t=new URLSearchParams(R);J?t.set("q",J):t.delete("q"),L(t,{replace:!0}),ct.current=J}}),500),()=>{st.current&&clearTimeout(st.current)})),[J,R,L]),i((()=>{if(!mt.current)return;const t=`${F}-${H}-${O}-${ut}-${K}`;if(t===lt.current)return;lt.current=t;const e=++dt.current,o=()=>e===dt.current,n=H?`${F}-${K}-${H}`:`${F}-${K||"all"}`,r=w.get(n);if(!r){if(rt(!1),ot(!0),H)mt.current.getMessagesFast([F],K).then((t=>{if(!o())return;const e=t.map((t=>{const e=new Date(t.createdAt).toLocaleString();return{id:t.id,data:{[H]:new S(t.content).content,createdAt:e},fileId:null,fileIds:[],tags:[F],mentions:[mt.current.codicent],createdAt:e}}));w.set(n,e),tt(e)})).catch(console.warn).finally((()=>{o()&&ot(!1)}));else{const t=K||"",e=O||t?void 0:T;mt.current.readDataMessages(F,t,void 0,0,e).then((e=>{o()&&(w.set(n,e),tt(e),rt(!O&&!t&&e.length===T))})).catch(console.warn).finally((()=>{o()&&ot(!1)}))}return()=>{lt.current=""}}if(tt(r),rt(!O&&!H&&r.length>=T),!H&&!K&&r.length>0){const t=r.reduce(((t,e)=>e.createdAt>t?e.createdAt:t),r[0].createdAt);mt.current.readDataMessages(F,"",void 0,void 0,void 0,t).then((t=>{o()&&tt((e=>{const o=new Set(e.map((t=>t.id))),r=t.filter((t=>!o.has(t.id)));if(0===r.length)return e;const i=[...r,...e];return w.set(n,i),i}))})).catch(console.warn)}}),[F,H,O,K,ut,pt]);const Ft=r((()=>{const t={};R.forEach(((e,o)=>{o.startsWith("filter_")&&(t[o.replace("filter_","")]=e)}));let e=Z.map(((t,e)=>({item:t,index:e})));for(const[o,n]of Object.entries(t)){const t=n.replace("%USERNAME%",wt()),r=s.context.nickname||"";e=e.filter((({item:e})=>{const n=e.data[o];return null!=n&&(String(n).includes(t)||String(n).includes(r))}))}if(N){const t=N(e.map((({item:t})=>t)),F),o=new Set(t.map((t=>t.id)));e=e.filter((({item:t})=>o.has(t.id)))}const o=e.map((({item:t,index:e})=>({...t.data,createdAt:t.createdAt,_id:t.id,originalMessageId:t.originalMessageId||t.id,_fileIds:t.fileIds??[],_index:e}))),n=E?.(F)?.deduplicateBy;if(n){const t=Array.isArray(n)?n:[n],e=e=>{for(const o of t){const t=e[o];if(null!=t&&""!==String(t).trim())return String(t)}},r=new Set;return o.filter((t=>{const o=e(t);return void 0===o||!r.has(o)&&(r.add(o),!0)}))}return o}),[Z,R,s.context.nickname,wt,N,F,E]),Ut=r((()=>{const t=(J||"").trim().toLowerCase();if(!t)return Ft;const e=St.filter((t=>!t.hidden)).map((t=>t.key));return Ft.filter((o=>{for(const n of e)if(Array.isArray(n))for(const e of n){const n=o[e];if(null!=n&&String(n).toLowerCase().includes(t))return!0}else{const e=o[n];if(null!=e&&String(e).toLowerCase().includes(t))return!0}return!1}))}),[Ft,J,St]),Ht=a((()=>{w.clearPattern(F),lt.current="",gt((t=>t+1))}),[F]),Ot=a((async()=>{at(!0);try{const t=await mt.current.readDataMessages(F,"",void 0,Z.length,T),e=[...Z,...t];tt(e),w.set(`${F}-all`,e),rt(t.length===T)}catch(t){console.warn(t)}finally{at(!1)}}),[Z,F]),Wt=a((t=>{ht(t)}),[]),qt=()=>{Dt(!1),Mt(null)},zt=a((async()=>{const t=`${F}_${(new Date).toISOString().split("T")[0]}`.replace(/[/\\:*?"<>|]/g,"_");const e=null!==ft?ft:Ut;await A(e,St,t,xt)||console.warn("No data to export")}),[ft,Ut,St,F,xt]),Vt=r((()=>null!==ft?ft.length:Ut.length),[ft,Ut]);return t(v,{hideHeader:!0,children:e("div",{className:jt.container,children:[t("div",{className:jt.backButton,children:t(c,{appearance:"subtle",icon:t(h,{}),onClick:()=>yt(-1),children:xt("Tillbaka")})}),e("div",{className:jt.headerRow,children:[t(f,{title:xt(U||"Loggbok")}),e("div",{className:jt.buttonGroup,children:[t(c,{appearance:"subtle",icon:t(j,{}),onClick:Ht,title:xt("Refresh"),children:xt("Refresh")}),z&&t(c,{appearance:"subtle",icon:t(x,{}),onClick:zt,title:xt("Export to Excel"),children:xt("Export to Excel")}),(W||V)&&t(c,{appearance:"primary",icon:t(y,{}),onClick:W?()=>{vt(null),Ct(!0)}:()=>window.open(V,"_blank"),className:jt.addButton,children:xt("Add Record")})]})]}),t("div",{className:jt.searchBox,children:t(I,{placeholder:xt("Sök")+"...",value:J,onChange:Rt,recentSearches:$t,onCommitSearch:Lt,onRemoveRecentSearch:Et})}),!et&&e("div",{className:jt.recordsCount,children:[xt("Total"),": ",Vt," ",xt("records"),Vt!==Z.length&&` (${xt("filtered from")} ${Z.length})`]}),e("div",{className:jt.listContainer,children:[et&&t("p",{children:xt("Söker")+"..."}),!et&&t(M,{data:Ut,columns:St,canEdit:q,onEdit:(t,e)=>{const o=Z[e];o&&(vt({data:{...o.data,_fileIds:o.fileIds??[]},index:e}),Ct(!0))},onDelete:(t,e)=>{const o=Z[e];o&&(Mt({index:e,id:o.id}),Dt(!0))},onToggleCheckbox:async(t,e,o,n)=>{const r=Z[n];if(r){const t=Array.isArray(e)?e[0]:e,i={...r.data,[t]:String(o)},a=await Y.updateDataMessage(r.id,i);tt((t=>{const e=[...t];return e[n]={...r,id:a,data:i},e})),w.clearPattern(F)}},onEnumChange:async(t,e,o,n)=>{const r=Z[n];if(r){const t=Array.isArray(e)?e[0]:e,i={...r.data,[t]:o},a=await Y.updateDataMessage(r.id,i);tt((t=>{const e=[...t];return e[n]={...r,id:a,data:i},e})),w.clearPattern(F)}},onFilteredDataChange:Wt})]}),nt&&!J.trim()&&t("div",{className:jt.loadMoreContainer,children:t(c,{appearance:"primary",size:"medium",onClick:Ot,disabled:it,children:it?xt("Laddar..."):xt("Visa fler")+` (${Z.length} ${xt("laddade")})`})}),t(_,{open:At,onClose:()=>Ct(!1),onSave:async t=>{const e=new Set(St.filter((t=>"thumbnail"===t.type)).map((t=>Array.isArray(t.key)?t.key[0]:t.key)));if(kt){const o=Z[kt.index];if(o){const n={};for(const o in t){if(e.has(o))continue;const r=t[o];n[o]=null==r?"":String(r)}const r=await Y.updateDataMessage(o.id,n);tt((t=>{const e=[...t];return e[kt.index]={...o,id:r,data:n},e})),w.clearPattern(F)}}else{const o={};for(const n in t){if(e.has(n))continue;const r=t[n];o[n]=null==r?"":String(r)}const n={id:await Y.createDataMessage(F,o),data:o,createdAt:(new Date).toISOString(),fileId:null,fileIds:[],tags:[F],mentions:[Y.codicent]};tt((t=>[n,...t])),w.clearPattern(F)}},columns:St,initialData:kt?.data}),t(l,{open:bt,onOpenChange:(t,e)=>!e.open&&qt(),children:t(d,{children:e(m,{children:[t(p,{children:xt("Confirm Delete")}),t(u,{children:xt("Are you sure you want to delete this record? This action cannot be undone.")}),e(g,{children:[t(c,{appearance:"secondary",onClick:qt,children:xt("Cancel")}),t(c,{appearance:"primary",onClick:async()=>{if(It)try{await Y.deleteDataMessage(It.id),tt((t=>t.filter(((t,e)=>e!==It.index)))),w.clearPattern(F)}catch(t){console.error("Failed to delete record:",t)}finally{Dt(!1),Mt(null)}},children:xt("Delete")})]})]})})})]})})};export{B as ListPage,B as default};
|
package/dist/index.d.ts
CHANGED
|
@@ -2562,6 +2562,55 @@ interface ListPageProps {
|
|
|
2562
2562
|
/** Optional data filter applied after fetch. Useful for app-specific filtering (e.g. empty notes). */
|
|
2563
2563
|
filterData?: (data: DataMessage[], tag: string) => DataMessage[];
|
|
2564
2564
|
}
|
|
2565
|
+
/**
|
|
2566
|
+
* ListPage — data fetch & cache behaviour
|
|
2567
|
+
*
|
|
2568
|
+
* ## Fetch key guard
|
|
2569
|
+
* A `fetchKey` string (`tag-contentTitle-loadAll-refreshKey-debouncedSearch`) is stored in
|
|
2570
|
+
* `lastFetchKey` (ref). The fetch effect bails out early if the key hasn't changed, preventing
|
|
2571
|
+
* duplicate calls when unrelated state updates re-render the component.
|
|
2572
|
+
* The ref is reset to `""` on effect cleanup (unmount / dep change) so that re-navigation
|
|
2573
|
+
* always triggers a fresh fetch.
|
|
2574
|
+
*
|
|
2575
|
+
* ## Race-condition protection
|
|
2576
|
+
* `activeFetchId` (ref) is incremented each time a new fetch starts. Each in-flight promise
|
|
2577
|
+
* captures its own `myFetchId` and checks `isActive()` before writing state. A superseded
|
|
2578
|
+
* fetch (e.g. from rapid search typing or quick navigation) silently discards its result
|
|
2579
|
+
* without calling `setSearching(false)`, so the spinner stays visible until the winning fetch
|
|
2580
|
+
* completes.
|
|
2581
|
+
*
|
|
2582
|
+
* ## Cache strategy
|
|
2583
|
+
* | Visit | Cache present? | Behaviour |
|
|
2584
|
+
* |-------|---------------|-----------|
|
|
2585
|
+
* | First | No | `searching=true` → API call → populate cache → show list |
|
|
2586
|
+
* | First | Yes | Instant render from cache (no spinner) → background delta-fetch for records newer than the latest cached timestamp → silently prepend new rows |
|
|
2587
|
+
* | Back-navigation | Yes | Unmount cleanup resets fetchKey → same as "First, cache present" |
|
|
2588
|
+
* | Back-navigation | Expired | Same as "First, no cache" |
|
|
2589
|
+
* | Refresh button | Any | Clears cache for tag + resets fetchKey + increments `refreshKey` → full API call |
|
|
2590
|
+
*
|
|
2591
|
+
* ## Search / filter flow
|
|
2592
|
+
* - Typing triggers a 500 ms debounce before `debouncedSearch` updates.
|
|
2593
|
+
* - `debouncedSearch` change → new fetchKey → new `activeFetchId` → previous in-flight
|
|
2594
|
+
* fetch is superseded and its result discarded.
|
|
2595
|
+
* - `filter_<field>=<value>` URL params are applied client-side after fetch (not sent to API)
|
|
2596
|
+
* except for `filter_<tag>=<value>` which seeds `debouncedSearch` for server-side filtering.
|
|
2597
|
+
* - `q=` URL param is kept in sync with the search box via a debounced `setSearchParams`
|
|
2598
|
+
* call that preserves all other existing params (`canAdd`, `canEdit`, `filter_*`, etc.).
|
|
2599
|
+
*
|
|
2600
|
+
* ## URL params (all optional)
|
|
2601
|
+
* | Param | Type | Default | Purpose |
|
|
2602
|
+
* |-------|------|---------|---------|
|
|
2603
|
+
* | `tag` | string | `"logbook"` | Data tag to query |
|
|
2604
|
+
* | `title` | string | `"Loggbok"` | Page heading |
|
|
2605
|
+
* | `contentTitle` | string | — | If set, fetches raw messages and maps this field as the display column |
|
|
2606
|
+
* | `loadAll` | `"true"` | — | Removes PAGE_SIZE cap; disables Load-more |
|
|
2607
|
+
* | `canAdd` | `"true"` | — | Shows Add Record button (opens RecordModal) |
|
|
2608
|
+
* | `canEdit` | `"true"` | — | Shows per-row Edit/Delete buttons |
|
|
2609
|
+
* | `canExport` | `"false"` to hide | visible | Shows Export to Excel button |
|
|
2610
|
+
* | `addUrl` | string | — | External URL opened on Add click (alternative to modal) |
|
|
2611
|
+
* | `q` | string | — | Initial search term; kept in sync with search box |
|
|
2612
|
+
* | `filter_<field>` | string | — | Client-side row filter; `%USERNAME%` resolves to current user |
|
|
2613
|
+
*/
|
|
2565
2614
|
declare const ListPage: ({ state, getColumnDefs, getListConfig, filterData }: ListPageProps) => react_jsx_runtime.JSX.Element;
|
|
2566
2615
|
|
|
2567
2616
|
declare const CrmPage: React__default.FC<{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codicent-app-sdk",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.8",
|
|
4
4
|
"description": "SDK for building AI-powered applications with Codicent",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/cjs/index.js",
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
"build": "rollup -c",
|
|
36
36
|
"dev": "rollup -c -w",
|
|
37
37
|
"test": "jest",
|
|
38
|
+
"smoke": "node scripts/smoke.mjs",
|
|
38
39
|
"prepare": "npm run build",
|
|
39
40
|
"predeploy": "npm run build && cp -r dist/* docs/",
|
|
40
41
|
"deploy": "gh-pages -d docs",
|