feat: support tri-state column sorting#501
Conversation
|
@yukina3230 is attempting to deploy a commit to the zknpr's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces a three-state column sorting cycle (none -> ascending -> descending -> none) on repeated clicks of the same column. It also refactors the HTML structure and CSS of the sort indicator to prevent it from being clipped by text-overflow ellipsis on narrow columns by rendering it as its own flex item with flex-shrink: 0. There are no review comments, so I have no feedback to provide.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 172b960890
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| @@ -364,45 +364,45 @@ | |||
| </div> | |||
|
|
|||
| <script nonce="<!--NONCE-->"> | |||
| "use strict";(()=>{var he=window.parent;var Pt=6e4,Dt=0,G=new Map;function ge(){return window.location.ancestorOrigins?.[0]||"*"}async function Ne(e){if(e.length<=65536)return Nt(e);let o=32768,l=[];for(let a=0;a<e.length;a+=o){let s=e.subarray(a,Math.min(a+o,e.length));l.push(String.fromCharCode.apply(null,s)),a>0&&a/o%4===0&&await new Promise(i=>setTimeout(i,0))}return btoa(l.join(""))}function Nt(e){let o=[];for(let l=0;l<e.length;l+=32768){let a=e.subarray(l,Math.min(l+32768,e.length));o.push(String.fromCharCode.apply(null,a))}return btoa(o.join(""))}function kt(e){let t=atob(e),o=new Uint8Array(t.length);for(let l=0;l<t.length;l++)o[l]=t.charCodeAt(l);return o}async function pe(e){if(e instanceof Uint8Array)return{__type:"Uint8Array",base64:await Ne(e)};if(ArrayBuffer.isView(e)){let t=new Uint8Array(e.buffer,e.byteOffset,e.byteLength);return{__type:"Uint8Array",base64:await Ne(t)}}if(Array.isArray(e))return Promise.all(e.map(pe));if(e&&typeof e=="object"&&Object.prototype.toString.call(e)==="[object Object]"){let t={};for(let o of Object.keys(e))t[o]=await pe(e[o]);return t}return e}async function At(e){return Promise.all(e.map(pe))}function fe(e){if(e&&typeof e=="object"&&!Array.isArray(e)){let t=Object.keys(e);if(e.__type==="Uint8Array"&&typeof e.base64=="string"&&t.length===2&&t.includes("__type")&&t.includes("base64"))return kt(e.base64);if(e.__type==="Uint8Array"&&Array.isArray(e.data)&&t.length===2&&t.includes("__type")&&t.includes("data"))return new Uint8Array(e.data);let o={};for(let l of Object.keys(e))o[l]=fe(e[l]);return o}return Array.isArray(e)?e.map(fe):e}async function E(e,t){let o=`rpc_${++Dt}_${Date.now()}`,l=await At(t);return new Promise((a,s)=>{let i=setTimeout(()=>{G.has(o)&&(G.delete(o),s(new Error(`RPC timeout: ${e}`)))},Pt);G.set(o,{resolve:a,reject:s,timeoutId:i}),he.postMessage({channel:"rpc",content:{kind:"invoke",messageId:o,targetMethod:e,payload:l}},ge())})}function ke(e){if(!e||e.kind!=="response")return;let t=G.get(e.messageId);if(t)if(clearTimeout(t.timeoutId),G.delete(e.messageId),e.success){let o=fe(e.data);t.resolve(o)}else t.reject(new Error(e.errorMessage||"RPC failed"))}function Ae(e,t){he.postMessage({kind:"result",correlationId:e,payload:t},ge())}function ye(e,t){he.postMessage({kind:"result",correlationId:e,errorText:t},ge())}var y={initialize:()=>E("initialize",[]),exportDb:e=>E("exportDb",[e]),refreshFile:()=>E("refreshFile",[]),fireEditEvent:e=>E("fireEditEvent",[e]),exportTable:(e,t,o,l,a,s)=>E("exportTable",[e,t,o,l,a,s]),updateCell:(e,t,o,l,a)=>E("updateCell",[e,t,o,l,a]),insertRow:(e,t)=>E("insertRow",[e,t]),deleteRows:(e,t)=>E("deleteRows",[e,t]),deleteColumns:(e,t)=>E("deleteColumns",[e,t]),createTable:(e,t)=>E("createTable",[e,t]),updateCellBatch:(e,t,o)=>E("updateCellBatch",[e,t,o]),addColumn:(e,t,o,l)=>E("addColumn",[e,t,o,l]),fetchTableData:(e,t)=>E("fetchTableData",[e,t]),fetchTableCount:(e,t)=>E("fetchTableCount",[e,t]),fetchSchema:()=>E("fetchSchema",[]),getTableInfo:e=>E("getTableInfo",[e]),getPragmas:()=>E("getPragmas",[]),setPragma:(e,t)=>E("setPragma",[e,t]),getExtensionSettings:()=>E("getExtensionSettings",[]),updateExtensionSetting:(e,t)=>E("updateExtensionSetting",[e,t]),ping:()=>E("ping",[]),openCellEditor:()=>Promise.resolve({success:!1,message:"Not available in web mode"}),readWorkspaceFileUri:()=>Promise.resolve(null),triggerUndo:()=>Promise.resolve(),triggerRedo:()=>Promise.resolve(),saveFile:(e,t)=>{let o=new Blob([t]),l=URL.createObjectURL(o),a=document.createElement("a");return a.href=l,a.download=e,document.body.appendChild(a),a.click(),document.body.removeChild(a),setTimeout(()=>URL.revokeObjectURL(l),100),Promise.resolve()},selectFile:()=>new Promise(e=>{let t=document.createElement("input");t.type="file",t.style.display="none",t.onchange=async o=>{if(o.target.files.length>0){let l=o.target.files[0],a=await l.arrayBuffer();e({name:l.name,data:new Uint8Array(a)})}else e(void 0)},document.body.appendChild(t),t.click(),setTimeout(()=>document.body.removeChild(t),1e3)})};var n={isDbConnected:!1,selectedTable:null,selectedTableType:"table",currentPageIndex:0,rowsPerPage:500,totalRecordCount:0,totalPageCount:1,tableColumns:[],sortedColumn:null,sortAscending:!0,filterQuery:"",filterTimer:null,selectedRowIds:new Set,gridData:[],editingCellInfo:null,activeCellInput:null,isSavingCell:!1,isLoadingData:!1,lastDoubleClickTime:0,isTransitioningEdit:!1,transitionLockTimeout:null,selectedCells:[],lastSelectedCell:null,lastSelectedColumnIndex:null,lastSelectedRowIndex:null,columnWidths:{},resizingColumn:null,resizeStartX:0,resizeStartWidth:0,columnFilters:{},pinnedColumns:new Set,pinnedRowIds:new Set,cellPreviewInfo:null,cellPreviewWrapEnabled:!0,selectedColumns:new Set,scrollPosition:{top:0,left:0},schemaCache:{tables:[],views:[],indexes:[]},sidebarFilter:"",dateFormat:"raw",cellEditBehavior:"inline"},Ce;function $(){Ce&&clearTimeout(Ce),Ce=setTimeout(()=>{n.selectedTable,n.selectedTableType,n.currentPageIndex,n.rowsPerPage,n.sortedColumn,n.sortAscending,n.filterQuery,n.columnWidths,n.columnFilters,Array.from(n.pinnedColumns),Array.from(n.pinnedRowIds),Array.from(n.selectedColumns),n.sidebarFilter,n.scrollPosition,n.dateFormat,n.cellEditBehavior},500)}function J(e){return e==null?"":String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function te(e){let t=Number(e);if(!Number.isFinite(t))throw new Error(`Invalid rowid: ${e}`);return t}function _(e,t=null,o="raw",l=null){if(e==null)return"NULL";if(e instanceof Uint8Array)return"[BLOB]";if(o!=="raw"&&$t(t,l)){let s=Mt(e,o);if(s)return s}return typeof e=="string"&&e.length>100?e.substring(0,100)+"...":String(e)}function $t(e,t){if(e){let o=e.toUpperCase();if(o.includes("DATE")||o.includes("TIME")||o.includes("TIMESTAMP"))return!0}if(t){let o=t.toUpperCase();return o.endsWith("_AT")||o.endsWith("_ON")||o.includes("DATE")||o.includes("TIME")||o==="CREATED"||o==="UPDATED"}return!1}function Mt(e,t){if(!e)return null;let o;if(e instanceof Date)o=e;else if(typeof e=="number")e<1e11?o=new Date(e*1e3):o=new Date(e);else{let l=String(e);/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/.test(l)&&(l=l.replace(" ","T"));let a=Date.parse(l);if(isNaN(a))return null;o=new Date(a)}if(isNaN(o.getTime()))return null;switch(t){case"local":return o.toLocaleString();case"iso":return o.toISOString();case"relative":return Ft(o);default:return String(e)}}function Ft(e){let t=Math.floor((new Date-e)/1e3),o={year:31536e3,month:2592e3,week:604800,day:86400,hour:3600,minute:60,second:1},l;for(let[a,s]of Object.entries(o))if(l=Math.floor(t/s),l>0)return l===1?`1 ${a} ago`:`${l} ${a}s ago`;return"Just now"}function u(e){let t=document.getElementById("statusText");t&&(t.textContent=e)}function $e(){let e=document.getElementById("gridContainer");e&&(e.innerHTML=` | |||
| "use strict";(()=>{var ne=typeof acquireVsCodeApi<"u"?acquireVsCodeApi():null;function Fe(e){ne&&ne.setState(e)}var Ut=6e4,Ft=0,ge=new Map;async function Ue(e){if(e.length<=65536)return Ot(e);let o=32768,l=[];for(let a=0;a<e.length;a+=o){let s=e.subarray(a,Math.min(a+o,e.length));l.push(String.fromCharCode.apply(null,s)),a>0&&a/o%4===0&&await new Promise(r=>setTimeout(r,0))}return btoa(l.join(""))}function Ot(e){let o=[];for(let l=0;l<e.length;l+=32768){let a=e.subarray(l,Math.min(l+32768,e.length));o.push(String.fromCharCode.apply(null,a))}return btoa(o.join(""))}async function he(e){if(e instanceof Uint8Array)return{__type:"Uint8Array",base64:await Ue(e)};if(ArrayBuffer.isView(e)){let t=new Uint8Array(e.buffer,e.byteOffset,e.byteLength);return{__type:"Uint8Array",base64:await Ue(t)}}if(Array.isArray(e))return Promise.all(e.map(he));if(e&&typeof e=="object"&&Object.prototype.toString.call(e)==="[object Object]"){let t={};for(let o of Object.keys(e))t[o]=await he(e[o]);return t}return e}async function zt(e){return Promise.all(e.map(he))}async function E(e,t){let o=`rpc_${++Ft}_${Date.now()}`,l=await zt(t);return new Promise((a,s)=>{let r=setTimeout(()=>{ge.has(o)&&(ge.delete(o),s(new Error(`RPC timeout: ${e}`)))},Ut);ge.set(o,{resolve:a,reject:s,timeoutId:r}),ne?ne.postMessage({channel:"rpc",content:{kind:"invoke",messageId:o,targetMethod:e,payload:l}}):console.warn("VS Code API not available")})}var C={initialize:()=>E("initialize",[]),exportDb:e=>E("exportDb",[e]),refreshFile:()=>E("refreshFile",[]),fireEditEvent:e=>E("fireEditEvent",[e]),exportTable:(e,t,o,l,a,s)=>E("exportTable",[e,t,o,l,a,s]),updateCell:(e,t,o,l,a)=>E("updateCell",[e,t,o,l,a]),insertRow:(e,t)=>E("insertRow",[e,t]),deleteRows:(e,t)=>E("deleteRows",[e,t]),deleteColumns:(e,t)=>E("deleteColumns",[e,t]),createTable:(e,t)=>E("createTable",[e,t]),updateCellBatch:(e,t,o)=>E("updateCellBatch",[e,t,o]),addColumn:(e,t,o,l)=>E("addColumn",[e,t,o,l]),fetchTableData:(e,t)=>E("fetchTableData",[e,t]),fetchTableCount:(e,t)=>E("fetchTableCount",[e,t]),fetchSchema:()=>E("fetchSchema",[]),getTableInfo:e=>E("getTableInfo",[e]),getPragmas:()=>E("getPragmas",[]),setPragma:(e,t)=>E("setPragma",[e,t]),getExtensionSettings:()=>E("getExtensionSettings",[]),updateExtensionSetting:(e,t)=>E("updateExtensionSetting",[e,t]),ping:()=>E("ping",[]),openCellEditor:(e,t,o,l,a)=>E("openCellEditor",[e,t,o,l,a]),readWorkspaceFileUri:e=>E("readWorkspaceFileUri",[e]),saveFile:(e,t)=>E("saveFile",[e,t]),selectFile:()=>E("selectFile",[]),triggerUndo:()=>E("triggerUndo",[]),triggerRedo:()=>E("triggerRedo",[])};var n={isDbConnected:!1,selectedTable:null,selectedTableType:"table",currentPageIndex:0,rowsPerPage:500,totalRecordCount:0,totalPageCount:1,tableColumns:[],sortedColumn:null,sortAscending:!0,filterQuery:"",filterTimer:null,selectedRowIds:new Set,gridData:[],editingCellInfo:null,activeCellInput:null,isSavingCell:!1,isLoadingData:!1,lastDoubleClickTime:0,isTransitioningEdit:!1,transitionLockTimeout:null,selectedCells:[],lastSelectedCell:null,lastSelectedColumnIndex:null,lastSelectedRowIndex:null,columnWidths:{},resizingColumn:null,resizeStartX:0,resizeStartWidth:0,columnFilters:{},pinnedColumns:new Set,pinnedRowIds:new Set,cellPreviewInfo:null,cellPreviewWrapEnabled:!0,selectedColumns:new Set,scrollPosition:{top:0,left:0},schemaCache:{tables:[],views:[],indexes:[]},sidebarFilter:"",dateFormat:"raw",cellEditBehavior:"inline"},ye;function M(){ye&&clearTimeout(ye),ye=setTimeout(()=>{Fe({selectedTable:n.selectedTable,selectedTableType:n.selectedTableType,currentPageIndex:n.currentPageIndex,rowsPerPage:n.rowsPerPage,sortedColumn:n.sortedColumn,sortAscending:n.sortAscending,filterQuery:n.filterQuery,columnWidths:n.columnWidths,columnFilters:n.columnFilters,pinnedColumns:Array.from(n.pinnedColumns),pinnedRowIds:Array.from(n.pinnedRowIds),selectedColumns:Array.from(n.selectedColumns),sidebarFilter:n.sidebarFilter,scrollPosition:n.scrollPosition,dateFormat:n.dateFormat,cellEditBehavior:n.cellEditBehavior})},500)}var be=window.parent;var jt=6e4,Vt=0,J=new Map;function we(){return window.location.ancestorOrigins?.[0]||"*"}async function Oe(e){if(e.length<=65536)return _t(e);let o=32768,l=[];for(let a=0;a<e.length;a+=o){let s=e.subarray(a,Math.min(a+o,e.length));l.push(String.fromCharCode.apply(null,s)),a>0&&a/o%4===0&&await new Promise(r=>setTimeout(r,0))}return btoa(l.join(""))}function _t(e){let o=[];for(let l=0;l<e.length;l+=32768){let a=e.subarray(l,Math.min(l+32768,e.length));o.push(String.fromCharCode.apply(null,a))}return btoa(o.join(""))}function Wt(e){let t=atob(e),o=new Uint8Array(t.length);for(let l=0;l<t.length;l++)o[l]=t.charCodeAt(l);return o}async function Ce(e){if(e instanceof Uint8Array)return{__type:"Uint8Array",base64:await Oe(e)};if(ArrayBuffer.isView(e)){let t=new Uint8Array(e.buffer,e.byteOffset,e.byteLength);return{__type:"Uint8Array",base64:await Oe(t)}}if(Array.isArray(e))return Promise.all(e.map(Ce));if(e&&typeof e=="object"&&Object.prototype.toString.call(e)==="[object Object]"){let t={};for(let o of Object.keys(e))t[o]=await Ce(e[o]);return t}return e}async function Kt(e){return Promise.all(e.map(Ce))}function xe(e){if(e&&typeof e=="object"&&!Array.isArray(e)){let t=Object.keys(e);if(e.__type==="Uint8Array"&&typeof e.base64=="string"&&t.length===2&&t.includes("__type")&&t.includes("base64"))return Wt(e.base64);if(e.__type==="Uint8Array"&&Array.isArray(e.data)&&t.length===2&&t.includes("__type")&&t.includes("data"))return new Uint8Array(e.data);let o={};for(let l of Object.keys(e))o[l]=xe(e[l]);return o}return Array.isArray(e)?e.map(xe):e}async function I(e,t){let o=`rpc_${++Vt}_${Date.now()}`,l=await Kt(t);return new Promise((a,s)=>{let r=setTimeout(()=>{J.has(o)&&(J.delete(o),s(new Error(`RPC timeout: ${e}`)))},jt);J.set(o,{resolve:a,reject:s,timeoutId:r}),be.postMessage({channel:"rpc",content:{kind:"invoke",messageId:o,targetMethod:e,payload:l}},we())})}function ze(e){if(!e||e.kind!=="response")return;let t=J.get(e.messageId);if(t)if(clearTimeout(t.timeoutId),J.delete(e.messageId),e.success){let o=xe(e.data);t.resolve(o)}else t.reject(new Error(e.errorMessage||"RPC failed"))}function je(e,t){be.postMessage({kind:"result",correlationId:e,payload:t},we())}function Ee(e,t){be.postMessage({kind:"result",correlationId:e,errorText:t},we())}var Ie={initialize:()=>I("initialize",[]),exportDb:e=>I("exportDb",[e]),refreshFile:()=>I("refreshFile",[]),fireEditEvent:e=>I("fireEditEvent",[e]),exportTable:(e,t,o,l,a,s)=>I("exportTable",[e,t,o,l,a,s]),updateCell:(e,t,o,l,a)=>I("updateCell",[e,t,o,l,a]),insertRow:(e,t)=>I("insertRow",[e,t]),deleteRows:(e,t)=>I("deleteRows",[e,t]),deleteColumns:(e,t)=>I("deleteColumns",[e,t]),createTable:(e,t)=>I("createTable",[e,t]),updateCellBatch:(e,t,o)=>I("updateCellBatch",[e,t,o]),addColumn:(e,t,o,l)=>I("addColumn",[e,t,o,l]),fetchTableData:(e,t)=>I("fetchTableData",[e,t]),fetchTableCount:(e,t)=>I("fetchTableCount",[e,t]),fetchSchema:()=>I("fetchSchema",[]),getTableInfo:e=>I("getTableInfo",[e]),getPragmas:()=>I("getPragmas",[]),setPragma:(e,t)=>I("setPragma",[e,t]),getExtensionSettings:()=>I("getExtensionSettings",[]),updateExtensionSetting:(e,t)=>I("updateExtensionSetting",[e,t]),ping:()=>I("ping",[]),openCellEditor:()=>Promise.resolve({success:!1,message:"Not available in web mode"}),readWorkspaceFileUri:()=>Promise.resolve(null),triggerUndo:()=>Promise.resolve(),triggerRedo:()=>Promise.resolve(),saveFile:(e,t)=>{let o=new Blob([t]),l=URL.createObjectURL(o),a=document.createElement("a");return a.href=l,a.download=e,document.body.appendChild(a),a.click(),document.body.removeChild(a),setTimeout(()=>URL.revokeObjectURL(l),100),Promise.resolve()},selectFile:()=>new Promise(e=>{let t=document.createElement("input");t.type="file",t.style.display="none",t.onchange=async o=>{if(o.target.files.length>0){let l=o.target.files[0],a=await l.arrayBuffer();e({name:l.name,data:new Uint8Array(a)})}else e(void 0)},document.body.appendChild(t),t.click(),setTimeout(()=>document.body.removeChild(t),1e3)})};function X(e){return e==null?"":String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function oe(e){let t=Number(e);if(!Number.isFinite(t))throw new Error(`Invalid rowid: ${e}`);return t}function K(e,t=null,o="raw",l=null){if(e==null)return"NULL";if(e instanceof Uint8Array)return"[BLOB]";if(o!=="raw"&&qt(t,l)){let s=Ht(e,o);if(s)return s}return typeof e=="string"&&e.length>100?e.substring(0,100)+"...":String(e)}function qt(e,t){if(e){let o=e.toUpperCase();if(o.includes("DATE")||o.includes("TIME")||o.includes("TIMESTAMP"))return!0}if(t){let o=t.toUpperCase();return o.endsWith("_AT")||o.endsWith("_ON")||o.includes("DATE")||o.includes("TIME")||o==="CREATED"||o==="UPDATED"}return!1}function Ht(e,t){if(!e)return null;let o;if(e instanceof Date)o=e;else if(typeof e=="number")e<1e11?o=new Date(e*1e3):o=new Date(e);else{let l=String(e);/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/.test(l)&&(l=l.replace(" ","T"));let a=Date.parse(l);if(isNaN(a))return null;o=new Date(a)}if(isNaN(o.getTime()))return null;switch(t){case"local":return o.toLocaleString();case"iso":return o.toISOString();case"relative":return Gt(o);default:return String(e)}}function Gt(e){let t=Math.floor((new Date-e)/1e3),o={year:31536e3,month:2592e3,week:604800,day:86400,hour:3600,minute:60,second:1},l;for(let[a,s]of Object.entries(o))if(l=Math.floor(t/s),l>0)return l===1?`1 ${a} ago`:`${l} ${a}s ago`;return"Just now"}function u(e){let t=document.getElementById("statusText");t&&(t.textContent=e)}function Ve(){let e=document.getElementById("gridContainer");e&&(e.innerHTML=` | |||
There was a problem hiding this comment.
Keep the web demo on the parent-window RPC client
This generated web-demo bundle now includes both the VS Code RPC client (acquireVsCodeApi/C) and the parent-window client (Ie), but the bundled schema/data paths call C.fetchSchema, C.getTableInfo, and C.fetchTableData. In the website iframe acquireVsCodeApi is undefined, so those calls only log VS Code API not available and then hang until timeout instead of posting to window.parent; selecting any table in the public demo will never load data.
Useful? React with 👍 / 👎.
172b960 to
0e88ee1
Compare
Press Enter in the global or a column filter to jump between cells whose displayed text contains the active term, cycling with Enter/Shift+Enter, a current/total counter, and an outlined active-match cell. Initial Enter applies the filter (one fetch); subsequent presses cycle locally without re-querying. Match navigation resets on sort/page/page-size/filter-text/date-format changes. Review hardening (Gemini + 4 Codex rounds): fixed the btnApplyFilter MouseEvent-as-direction crash; guarded the toolbar filter against concurrent reloads (state.isGridReloading); preventDefault + IME (isComposing) handling on Enter; String() around formatter output in match scan; failed/superseded filter-submit lifecycle (loadTableData returns success; only a fully-applied load navigates, failures revert for retry); pinned active-match z-index; removed dead filterTimer. Composes with #498/#499/#501. tsc + 454 unit tests green. Co-authored-by: yukina3230 <75545944+yukina3230@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Thanks for this, @yukina3230! 🙏 Clean take on the none → asc → desc → none cycle, and I really like moving the sort arrow out of the |
Description
sortedColumnon "none" to omit ORDER BY and restore original row order..header-textinto a dedicated flex item.flex-shrink: 0on the arrow to prevent clipping on narrow/truncated columns.Type of Change
Checklist
npm testpasses locallynpm run buildcompletes without errorstextContentrendering, strict CSP)Screenshots
tri_state.webm