Skip to content

Commit a2f8f79

Browse files
Scott DoverScott Dover
authored andcommitted
chore: prep for code review
Signed-off-by: Scott Dover <[email protected]>
1 parent 402a220 commit a2f8f79

File tree

6 files changed

+59
-80
lines changed

6 files changed

+59
-80
lines changed

client/src/connection/itc/ItcLibraryAdapter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ class ItcLibraryAdapter implements LibraryAdapter {
127127
}
128128
: {};
129129

130-
const { rows } = await this.getRows(item, start, limit);
130+
const { rows } = await this.getRows(item, start, limit, []);
131131

132132
rows.unshift(columns);
133133

client/src/connection/itc/script.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ class SASRunner{
258258
$this.dataConnection, # Use the active connection
259259
3, # adOpenStatic
260260
1, # adLockReadOnly
261-
1 # adCmdTableDirect
261+
1 # adCmdText
262262
)
263263
264264
$records = [List[List[object]]]::new()

client/src/webview/ColumnHeader.tsx

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ const ColumnHeader = ({
4848
column.sort && currentSortedColumns.length > 1
4949
? `${column.sortIndex + 1}`
5050
: "";
51+
const dropdownClassname =
52+
currentColumn?.colId === column.colId ? "active dropdown" : "dropdown";
5153

5254
const applyColumnState = (state: ColumnState[]) => {
5355
api.applyColumnState({ state, defaultState: { sort: null } });
@@ -104,38 +106,20 @@ const ColumnHeader = ({
104106

105107
return (
106108
<div className={`ag-cell-label-container ${theme}`} role="presentation">
107-
<div
108-
data-ref="eLabel"
109-
className="ag-header-cell-label"
110-
role="presentation"
111-
>
112-
<span
113-
className={`header-icon ${getIconForColumnType(columnType)}`}
114-
></span>
109+
<div className="ag-header-cell-label" role="presentation">
110+
<span className={`header-icon ${getIconForColumnType(columnType)}`} />
115111
<span className="ag-header-cell-text">{column.colId}</span>
116-
117112
<span className="sort-icon-wrapper">
118113
{!!column.sort && (
119114
<>
120-
<span
121-
className={`sort-icon ${column.sort === "asc" ? "ascending" : "descending"}`}
122-
></span>
123-
{!!columnNumber && (
124-
<span className="sort-number">{columnNumber}</span>
125-
)}
115+
<span className={`icon ${column.sort}`}></span>
116+
{!!columnNumber && <span className="number">{columnNumber}</span>}
126117
</>
127118
)}
128119
</span>
129-
130-
<div
131-
className={
132-
currentColumn?.colId === column.colId
133-
? "active dropdown"
134-
: "dropdown"
135-
}
136-
>
120+
<div className={dropdownClassname}>
137121
<button ref={ref} type="button" onClick={displayColumnMenu}>
138-
<span></span>
122+
<span />
139123
</button>
140124
</div>
141125
</div>

client/src/webview/ColumnHeaderMenu.tsx

Lines changed: 42 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
3-
4-
import { Fragment, useEffect, useRef, useState } from "react";
3+
import { useEffect, useRef, useState } from "react";
54

65
import { AgColumn } from "ag-grid-community";
76

@@ -19,41 +18,50 @@ export interface ColumnHeaderProps {
1918
}
2019

2120
interface MenuItem {
22-
name: string;
2321
checked?: boolean;
24-
onPress?: () => void;
2522
children?: (MenuItem | string)[];
2623
disabled?: boolean;
24+
name: string;
25+
onPress?: () => void;
2726
}
2827

2928
const GridMenu = ({
29+
left: incomingLeft,
3030
menuItems,
31+
parentDimensions,
32+
subMenu,
3133
theme,
3234
top,
33-
left: incomingLeft,
34-
subMenu,
35-
parentDimensions,
3635
}: {
36+
left?: number;
3737
menuItems: (MenuItem | string)[];
38+
parentDimensions?: { left: number; width: number };
39+
subMenu?: boolean;
3840
theme: string;
3941
top: number;
40-
left?: number;
41-
subMenu?: boolean;
42-
parentDimensions?: { left: number; width: number };
4342
}) => {
4443
const menuRef = useRef<HTMLDivElement>(undefined);
44+
const [activeIndex, setActiveIndex] = useState(-1);
4545
const [subMenuItems, setSubMenuItems] = useState<(MenuItem | string)[]>([]);
4646
const className = subMenu
4747
? `ag-menu ag-ltr ag-popup-child ${theme}`
4848
: `ag-menu ag-column-menu ag-ltr ag-popup-child ag-popup-positioned-under ${theme}`;
49-
const [activeIndex, setActiveIndex] = useState(-1);
5049

50+
// The following useEffect positions our column header menu. There are three general
51+
// ways of laying things out.
52+
// - option 1. If there is enough room for the parent menu and child menu to the right, the
53+
//. menus are displayed left to right.
54+
// - option 2. If the parent menu has enough room, we don't shift it. If the child menu doesn't
55+
//. fit to the right, we move it to the left side.
56+
// - option 3. The parent menu doesn't fit on the screen, so we shift it to the left and
57+
// put the child menu on the left side.
5158
const [left, setLeft] = useState(parentDimensions?.left ?? incomingLeft);
5259
const [displayed, setDisplayed] = useState(false);
5360
useEffect(() => {
5461
const clientWidth = menuRef.current.closest("body").clientWidth;
5562
const width = menuRef.current.getBoundingClientRect().width;
5663

64+
setDisplayed(true);
5765
if (parentDimensions) {
5866
// First, lets put the child menu to the right
5967
let adjustedLeft = parentDimensions.left + parentDimensions.width;
@@ -62,17 +70,15 @@ const GridMenu = ({
6270
adjustedLeft = parentDimensions.left - width;
6371
}
6472
setLeft(adjustedLeft);
65-
setDisplayed(true);
6673
return;
6774
}
6875
if (left + width > clientWidth) {
6976
setLeft(left - (left + width - clientWidth + 15));
7077
}
71-
setDisplayed(true);
72-
}, []);
78+
}, []); // eslint-disable-line react-hooks/exhaustive-deps
7379

7480
return (
75-
<Fragment>
81+
<>
7682
{subMenuItems.length > 0 && (
7783
<GridMenu
7884
menuItems={subMenuItems}
@@ -106,19 +112,7 @@ const GridMenu = ({
106112
></div>
107113
{menuItems.map((menuItem, index) => {
108114
if (typeof menuItem === "string") {
109-
return (
110-
<div
111-
className="ag-menu-separator"
112-
aria-hidden="true"
113-
key={index}
114-
>
115-
{" "}
116-
<div className="ag-menu-separator-part"></div>{" "}
117-
<div className="ag-menu-separator-part"></div>{" "}
118-
<div className="ag-menu-separator-part"></div>{" "}
119-
<div className="ag-menu-separator-part"></div>{" "}
120-
</div>
121-
);
115+
return <Separator key={index} />;
122116
}
123117
return (
124118
<div
@@ -146,6 +140,7 @@ const GridMenu = ({
146140
setActiveIndex(-1);
147141
const targetInPopup = Array.from(
148142
document.querySelectorAll(".ag-popup"),
143+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
149144
).some((t) => t.contains(e.target as HTMLElement));
150145
if (!targetInPopup) {
151146
setSubMenuItems([]);
@@ -154,20 +149,17 @@ const GridMenu = ({
154149
>
155150
<span
156151
className="ag-menu-option-part ag-menu-option-icon"
157-
data-ref="eIcon"
158152
role="presentation"
159153
>
160154
{menuItem.checked && (
161155
<span
162156
className="ag-icon ag-icon-tick"
163157
role="presentation"
164-
unselectable="on"
165-
></span>
158+
/>
166159
)}
167160
</span>
168161
<span
169162
className="ag-menu-option-part ag-menu-option-text"
170-
data-ref="eName"
171163
onClick={() => {
172164
if (menuItem.disabled) {
173165
return;
@@ -182,20 +174,13 @@ const GridMenu = ({
182174
>
183175
{menuItem.name}
184176
</span>
185-
<span
186-
className="ag-menu-option-part ag-menu-option-shortcut"
187-
data-ref="eShortcut"
188-
></span>
177+
<span className="ag-menu-option-part ag-menu-option-shortcut"></span>
189178
{menuItem.children && menuItem.children.length > 0 && (
190-
<span
191-
className="ag-menu-option-part ag-menu-option-popup-pointer"
192-
data-ref="ePopupPointer"
193-
>
179+
<span className="ag-menu-option-part ag-menu-option-popup-pointer">
194180
<span
195181
className="ag-icon ag-icon-small-right"
196182
role="presentation"
197-
unselectable="on"
198-
></span>
183+
/>
199184
</span>
200185
)}
201186
</div>
@@ -204,11 +189,11 @@ const GridMenu = ({
204189
<div
205190
className="ag-tab-guard ag-tab-guard-bottom"
206191
role="presentation"
207-
></div>
192+
/>
208193
</div>
209194
</div>
210195
</div>
211-
</Fragment>
196+
</>
212197
);
213198
};
214199

@@ -226,13 +211,13 @@ const ColumnHeaderMenu = ({
226211
}: ColumnHeaderProps) => {
227212
const menuItems = [
228213
{
229-
name: t["Sort"],
214+
name: t.Sort,
230215
children: [
231216
{
232217
name:
233218
hasSort && !column.sort
234219
? t["Ascending (add to sorting)"]
235-
: t["Ascending"],
220+
: t.Ascending,
236221
checked: column.sort === "asc",
237222
onPress: () => {
238223
sortColumn("asc");
@@ -243,7 +228,7 @@ const ColumnHeaderMenu = ({
243228
name:
244229
hasSort && !column.sort
245230
? t["Descending (add to sorting)"]
246-
: t["Descending"],
231+
: t.Descending,
247232
checked: column.sort === "desc",
248233
onPress: () => {
249234
sortColumn("desc");
@@ -274,4 +259,14 @@ const ColumnHeaderMenu = ({
274259
return <GridMenu menuItems={menuItems} top={top} left={left} theme={theme} />;
275260
};
276261

262+
const Separator = () => (
263+
<div className="ag-menu-separator" aria-hidden="true">
264+
{" "}
265+
<div className="ag-menu-separator-part"></div>{" "}
266+
<div className="ag-menu-separator-part"></div>{" "}
267+
<div className="ag-menu-separator-part"></div>{" "}
268+
<div className="ag-menu-separator-part"></div>{" "}
269+
</div>
270+
);
271+
277272
export default ColumnHeaderMenu;

client/src/webview/DataViewer.css

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -126,30 +126,30 @@ button,
126126
margin-left: auto;
127127
}
128128

129-
.sort-icon-wrapper .sort-icon,
130-
.sort-icon-wrapper .sort-number {
129+
.sort-icon-wrapper .icon,
130+
.sort-icon-wrapper .number {
131131
width: 16px;
132132
height: 16px;
133133
display: inline-block;
134134
vertical-align: middle;
135135
}
136136

137-
.sort-icon-wrapper .sort-icon.ascending {
137+
.sort-icon-wrapper .icon.asc {
138138
background: url(../../../icons/light/arrow-up.svg);
139139
background-size: 16px 16px;
140140
}
141141

142-
.vscode-dark .sort-icon-wrapper .sort-icon.ascending {
142+
.vscode-dark .sort-icon-wrapper .icon.asc {
143143
background: url(../../../icons/dark/arrow-up.svg);
144144
background-size: 16px 16px;
145145
}
146146

147-
.sort-icon-wrapper .sort-icon.descending {
147+
.sort-icon-wrapper .icon.desc {
148148
background: url(../../../icons/light/arrow-down.svg);
149149
background-size: 16px 16px;
150150
}
151151

152-
.vscode-dark .sort-icon-wrapper .sort-icon.descending {
152+
.vscode-dark .sort-icon-wrapper .icon.desc {
153153
background: url(../../../icons/dark/arrow-down.svg);
154154
background-size: 16px 16px;
155155
}

client/src/webview/useDataViewer.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ const useDataViewer = (theme: string) => {
183183

184184
setColumns(columns);
185185
});
186-
}, [columns.length]);
186+
}, [columns.length, theme]);
187187

188188
useEffect(() => {
189189
window.addEventListener("contextmenu", contextMenuHandler, true);

0 commit comments

Comments
 (0)