Skip to content

Commit 2db004b

Browse files
authored
Connections: Support for custom icons (#6282)
Addresses #6187 Add support for custom icons in the new connections pane. The [connections contract](https://rstudio.github.io/rstudio-extensions/connections-contract.html#examples) allows connections to provide a custom icon, which should be a full path to a squared png file.
1 parent 1a7e5db commit 2db004b

File tree

4 files changed

+61
-30
lines changed

4 files changed

+61
-30
lines changed

src/vs/workbench/contrib/positronConnections/browser/components/listConnections.css

+10
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
.connections-list-container .col-icon {
5050
flex-shrink: 0;
5151
height: 100%;
52+
width: 26px;
5253
}
5354

5455
.connections-list-container .col-name {
@@ -67,6 +68,15 @@
6768
color: var(--vscode-positronSideActionBar-disabledForeground);
6869
}
6970

71+
.connections-list-item .col-icon {
72+
width: 26px;
73+
}
74+
75+
.connections-list-item .col-icon > img {
76+
width: 26px;
77+
height: 26px;
78+
}
79+
7080
.connections-list-container .col-language {
7181
padding-left: 5px;
7282
flex-basis: 20%;

src/vs/workbench/contrib/positronConnections/browser/components/listConnections.tsx

+5-3
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ export const ListConnections = (props: React.PropsWithChildren<ListConnnectionsP
7070

7171
const ItemEntry = (props: { index: number; style: CSSProperties }) => {
7272
const itemProps = instances[props.index];
73-
const { language_id, name } = itemProps.metadata;
73+
const { language_id, name, icon } = itemProps.metadata;
7474

7575
return (
7676
<div
@@ -81,7 +81,9 @@ export const ListConnections = (props: React.PropsWithChildren<ListConnnectionsP
8181
)}
8282
onMouseDown={() => setSelectedInstanceId(itemProps.id)}
8383
>
84-
<div className='col-icon' style={{ width: `${26}px` }}></div>
84+
<div className='col-icon'>
85+
{icon ? <img src={icon}></img> : <></>}
86+
</div>
8587
<div className='col-name'>{name}</div>
8688
<div className='col-language'>
8789
{language_id ? languageIdToName(language_id) : ''}
@@ -134,7 +136,7 @@ export const ListConnections = (props: React.PropsWithChildren<ListConnnectionsP
134136
</ActionBar>
135137
<div className='connections-list-container'>
136138
<div className='connections-list-header' style={{ height: `${TABLE_HEADER_HEIGHT}px` }}>
137-
<div className='col-icon' style={{ width: `${26}px` }}></div>
139+
<div className='col-icon'></div>
138140
<VerticalSplitter />
139141
<div className='col-name'>
140142
{localize('positron.listConnections.connection', 'Connection')}

src/vs/workbench/contrib/positronConnections/browser/components/schemaNavigation.css

+7
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
cursor: pointer;
1515
align-items: center;
1616
height: 26px;
17+
scrollbar-gutter: stable;
1718
}
1819

1920
.connections-details {
@@ -88,6 +89,7 @@
8889
text-overflow: ellipsis;
8990
white-space: nowrap;
9091
width: calc(100% - 2px);
92+
scrollbar-gutter: stable;
9193
}
9294

9395
.connections-instance-details .connection-name {
@@ -104,7 +106,12 @@
104106
flex-grow: 0;
105107
flex-shrink: 0;
106108
width: 26px;
109+
height: 26px;
107110
display: flex;
108111
align-items: center;
109112
justify-content: center;
110113
}
114+
115+
.connections-items-list {
116+
scrollbar-gutter: stable;
117+
}

src/vs/workbench/contrib/positronConnections/browser/components/schemaNavigation.tsx

+39-27
Original file line numberDiff line numberDiff line change
@@ -126,18 +126,21 @@ export const SchemaNavigation = (props: React.PropsWithChildren<SchemaNavigation
126126
<div className={'connections-instance-details'} style={{ height: DETAILS_BAR_HEIGHT }}>
127127
<div className='connection-name'>{name}</div>
128128
<div className='connection-language'>{languageIdToName(language_id)}</div>
129-
<div className={'connection-icon'}>
130-
{
131-
icon || <div className='codicon codicon-positron-database-connection'></div>
132-
}
133-
</div>
129+
{
130+
icon ?
131+
<img className='connection-icon' src={icon}></img> :
132+
<div className='connection-icon'>
133+
<div className='codicon codicon-positron-database-connection'></div>
134+
</div>
135+
}
134136
</div>
135137
<List
136138
itemCount={entries.length}
137139
itemSize={26}
138140
/* size if the actionbar and the secondary side bar combined) */
139141
height={height - ACTION_BAR_HEIGHT - DETAILS_BAR_HEIGHT}
140-
width={'calc(100% - 2px)'}
142+
className='connections-items-list'
143+
width={'100%'}
141144
itemKey={index => entries[index].id}
142145
innerRef={innerRef}
143146
>
@@ -177,16 +180,9 @@ const PositronConnectionsItem = (props: React.PropsWithChildren<PositronConnecti
177180
props.onToggleExpand(props.item.id);
178181
};
179182

180-
const icon = (() => {
181-
182-
if (props.item.icon) {
183-
return props.item.icon;
184-
}
185-
186-
if (props.item.kind) {
187-
// TODO: we'll probably want backends to implement the casting to a set of known
188-
// types or provide their own icon.
189-
switch (props.item.kind) {
183+
const iconClass = (kind?: string) => {
184+
if (kind) {
185+
switch (kind.toLowerCase()) {
190186
case 'table':
191187
return 'positron-table-connection';
192188
case 'view':
@@ -198,11 +194,13 @@ const PositronConnectionsItem = (props: React.PropsWithChildren<PositronConnecti
198194
case 'catalog':
199195
return 'positron-catalog-connection';
200196
case 'field':
201-
switch (props.item.dtype) {
197+
switch (props.item.dtype?.toLowerCase()) {
202198
case 'character':
199+
case 'string':
203200
return 'positron-data-type-string';
204201
case 'integer':
205202
case 'numeric':
203+
case 'float':
206204
return 'positron-data-type-number';
207205
case 'boolean':
208206
case 'bool':
@@ -212,8 +210,26 @@ const PositronConnectionsItem = (props: React.PropsWithChildren<PositronConnecti
212210
}
213211
}
214212
}
215-
// If kind is not known, then no icon is dplsayed by default.
213+
216214
return '';
215+
}
216+
217+
const icon = (() => {
218+
// icon is a base64 encoded png
219+
if (props.item.icon) {
220+
return <img
221+
src={props.item.icon}
222+
>
223+
</img>;
224+
}
225+
226+
return <div
227+
className={positronClassNames(
228+
'codicon',
229+
`codicon-${iconClass(props.item.kind)}`,
230+
)}
231+
>
232+
</div>
217233
})();
218234

219235
const rowMouseDownHandler = (e: MouseEvent<HTMLElement>) => {
@@ -268,17 +284,13 @@ const PositronConnectionsItem = (props: React.PropsWithChildren<PositronConnecti
268284
{props.item.error && <span className='connections-error codicon codicon-error' title={props.item.error}></span>}
269285
</div>
270286
<div
271-
className='connections-icon'
287+
className={positronClassNames(
288+
'connections-icon',
289+
{ 'disabled': props.item.preview === undefined }
290+
)}
272291
onClick={() => props.item.preview?.()}
273292
>
274-
<div
275-
className={positronClassNames(
276-
'codicon',
277-
`codicon-${icon}`,
278-
{ 'disabled': props.item.preview === undefined }
279-
)}
280-
>
281-
</div>
293+
{icon}
282294
</div>
283295
</div>
284296
);

0 commit comments

Comments
 (0)