Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add icons for join_kind #12502

Merged
merged 23 commits into from
Mar 22, 2025
Merged
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -49,6 +49,7 @@
- [For some types, Component Browser display special "suggestions" group][12477]
- [Nested dropdowns are supported for Selection widget.][12548]
- [Native Image mode is now on by default][12515]
- [join_kind dropdown has icons to show how joins work][12502]

[11889]: https://github.com/enso-org/enso/pull/11889
[11836]: https://github.com/enso-org/enso/pull/11836
@@ -81,6 +82,7 @@
[12477]: https://github.com/enso-org/enso/pull/12477
[12548]: https://github.com/enso-org/enso/pull/12548
[12515]: https://github.com/enso-org/enso/pull/12515
[12502]: https://github.com/enso-org/enso/pull/12502

#### Enso Standard Library

Original file line number Diff line number Diff line change
@@ -98,6 +98,7 @@ const dynamicTags = computed<(ExpressionTag | NestedChoiceTag)[]>(() => {
projectNames,
choice.value,
choice.label,
choice.icon,
)
return tag
}
@@ -124,6 +125,7 @@ const entries = computed<Entry[]>(() => {
return filteredTags.value.map((tag) => ({
value: tag.label,
selected: tag instanceof ExpressionTag && selectedExpressions.value.has(tag.expression),
icon: tag instanceof ExpressionTag ? tag.icon : undefined,
tag,
}))
})
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@ import {
} from '@/stores/suggestionDatabase/entry'
import { Ast } from '@/util/ast'
import { Opt } from '@/util/data/opt'
import { Icon, isIconName } from '@/util/iconMetadata/iconName'
import { ProjectPath } from '@/util/projectPath'
import { qnLastSegment, tryQualifiedName } from '@/util/qualifiedName'
import { ToValue } from '@/util/reactivity'
@@ -24,11 +25,13 @@ export class ExpressionTag {
/**
* @param expression - The expression to insert when this item is clicked.
* @param explicitLabel - If provided, this label will be used instead of the stringified expression.
* @param explicitIcon - If provided, this icon will be displayed with the label
* @param requiredImports - The imports required by the expression, will be added to the code when the item is clicked.
*/
constructor(
readonly expression: string,
readonly explicitLabel?: Opt<string>,
private explicitIcon?: Opt<Icon>,
readonly requiredImports?: RequiredImport[],
) {}

@@ -53,6 +56,7 @@ export class ExpressionTag {
projectNames: ProjectNameStore,
expression: string,
label?: Opt<string>,
icon?: Opt<string>,
): ExpressionTag {
const qn = tryQualifiedName(expression)
if (qn.ok) {
@@ -61,9 +65,17 @@ export class ExpressionTag {
const fromProjPath = ExpressionTag.FromProjectPath(suggestions, projectPath.value, label)
if (fromProjPath) return fromProjPath
}
return new ExpressionTag(qn.value, label ?? qnLastSegment(qn.value))
return new ExpressionTag(
qn.value,
label ?? qnLastSegment(qn.value),
icon && isIconName(icon) ? (icon as Icon) : undefined,
)
}
return new ExpressionTag(expression, label)
return new ExpressionTag(
expression,
label,
icon && isIconName(icon) ? (icon as Icon) : undefined,
)
}

/**
@@ -81,6 +93,7 @@ export class ExpressionTag {
return new ExpressionTag(
expression,
label ?? entry.name,
undefined,
requiredImports(suggestions.entries, entry),
)
}
@@ -92,6 +105,13 @@ export class ExpressionTag {
return this.explicitLabel ?? this.expression
}

/**
* Get the displayed icon for this tag.
*/
get icon() {
return this.explicitIcon ?? undefined
}

/**
* Get the parsed expression AST for this tag.
*/
@@ -131,7 +151,9 @@ export class NestedChoiceTag {
for (const choice of this.choices) {
if (choice instanceof ExpressionTag) {
const newLabel = prefix + this.internalLabel + ' → ' + choice.label
result.push(new ExpressionTag(choice.expression, newLabel, choice.requiredImports))
result.push(
new ExpressionTag(choice.expression, newLabel, choice.icon, choice.requiredImports),
)
} else if (choice instanceof NestedChoiceTag) {
result.push(...choice.flatten(prefix + this.internalLabel + ' → '))
}
16 changes: 15 additions & 1 deletion app/gui/src/project-view/components/widgets/DropdownWidget.vue
Original file line number Diff line number Diff line change
@@ -76,6 +76,7 @@ function handleClick(entry: Entry, altKey: boolean, htmlElement: EventTarget | n
export interface DropdownEntry {
readonly value: string
readonly selected: boolean
readonly icon?: Icon | undefined
}
</script>

@@ -89,7 +90,10 @@ export interface DropdownEntry {
class="item clickable"
@click.stop="handleClick(entry, $event.altKey, $event.currentTarget)"
>
<div class="itemContent" v-text="entry.value"></div>
<div class="item-inner">
<SvgIcon v-if="entry.icon" :name="entry.icon" class="menu-icon" />
<div class="itemContent" v-text="entry.value"></div>
</div>
</li>
</ul>
<div v-if="enableSortButton" class="sort">
@@ -195,6 +199,16 @@ export interface DropdownEntry {
text-overflow: ellipsis;
}
.item-inner {
display: flex;
align-items: center;
}
.menu-icon {
margin-left: -4px;
margin-right: 6px;
}
@keyframes text-scroll {
0%,
80%,
Original file line number Diff line number Diff line change
@@ -47,16 +47,19 @@ const choiceSchema: z.ZodType<Choice> = z.object({
value: choiceValueSchema,
label: z.string().nullable(),
parameters: z.lazy(() => z.array(argumentSchema)),
icon: z.string().nullable(),
})
export type Choice = {
value: ChoiceValue
label: string | null
parameters: ArgsWidgetConfiguration
icon: string | null
}
export type FlattenedChoice = {
value: string
label: string | null
parameters: ArgsWidgetConfiguration
icon: string | null
}

/**
Original file line number Diff line number Diff line change
@@ -1601,6 +1601,7 @@ type DB_Table
the same name. So `table.join other on=["A", "B"]` is a shorthand for:
table.join other on=[Join_Condition.Equals "A" "A", Join_Condition.Equals "B" "B"]
@on Widget_Helpers.make_join_condition_selector
@join_kind Join_Kind.default_widget
join self (right : DB_Table = Missing_Argument.throw "right") join_kind:Join_Kind=..Left_Outer (on : Join_Condition | Text | Vector (Join_Condition | Text) = default_join_condition self join_kind) (right_prefix : Text = "Right ") on_problems:Problem_Behavior=..Report_Warning -> DB_Table =
Feature.Join.if_supported_else_throw self.connection.dialect "join" <|
self.join_or_cross_join right join_kind on right_prefix on_problems
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
from Standard.Base import all
from Standard.Base.Metadata import Display, make_single_choice, Widget, Choice

polyglot java import org.enso.table.data.table.join.JoinKind as Java_Join_Kind

type Join_Kind
@@ -39,6 +42,10 @@ type Join_Kind
returned, since all columns of the left table would be all null anyway.
Right_Exclusive

## PRIVATE
default_widget display:Display=..When_Modified -> Widget =
make_single_choice [Choice.Option "..Inner" "..Inner" icon="join-inner", Choice.Option "..Left_Outer" "..Left_Outer" icon="join-left-outer", Choice.Option "..Right_Outer" "..Right_Outer" icon="join-right-outer", Choice.Option "..Full" "..Full" icon="join-full", Choice.Option "..Left_Exclusive" "..Left_Exclusive" icon="join-left-exclusive", Choice.Option "..Right_Exclusive" "..Right_Exclusive" icon="join-right-exclusive"] display=display

## PRIVATE
to_java : Java_Join_Kind
to_java self = case self of
1 change: 1 addition & 0 deletions distribution/lib/Standard/Table/0.0.0-dev/src/Table.enso
Original file line number Diff line number Diff line change
@@ -2734,6 +2734,7 @@ type Table

`table.join other on=[..Equals "A" "A", ..Equals "B" "B"]`
@on Widget_Helpers.make_join_condition_selector
@join_kind Join_Kind.default_widget
join self (right : Table = Missing_Argument.throw "right") join_kind:Join_Kind=..Left_Outer (on : Vector (Join_Condition | Text) | Text | Join_Condition = [Join_Condition.Equals self.column_names.first]) (right_prefix : Text = "Right ") on_problems:Problem_Behavior=..Report_Warning -> Table = Out_Of_Memory.handle_java_exception "join" <|
columns_to_keep = case join_kind of
Join_Kind.Left_Exclusive -> [True, False]