Merge branch 'master' of github.com:Budibase/budibase into v3-ui

This commit is contained in:
Andrew Kingston 2024-10-11 16:33:42 +01:00
commit bae5640e90
No known key found for this signature in database
8 changed files with 192 additions and 92 deletions

View File

@ -14,15 +14,39 @@ jobs:
release:
if: |
(github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'Budibase/budibase') &&
contains(github.event.pull_request.labels.*.name, 'feature-branch')
(
contains(github.event.pull_request.labels.*.name, 'feature-branch') ||
contains(github.event.pull_request.labels.*.name, 'feature-branch-pro') ||
contains(github.event.pull_request.labels.*.name, 'feature-branch-team') ||
contains(github.event.pull_request.labels.*.name, 'feature-branch-business') ||
contains(github.event.pull_request.labels.*.name, 'feature-branch-enterprise')
)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set PAYLOAD_LICENSE_TYPE
id: set_license_type
run: |
if [[ "${{ contains(github.event.pull_request.labels.*.name, 'feature-branch') }}" == "true" ]]; then
echo "PAYLOAD_LICENSE_TYPE=free" >> $GITHUB_ENV
elif [[ "${{ contains(github.event.pull_request.labels.*.name, 'feature-branch-pro') }}" == "true" ]]; then
echo "PAYLOAD_LICENSE_TYPE=pro" >> $GITHUB_ENV
elif [[ "${{ contains(github.event.pull_request.labels.*.name, 'feature-branch-team') }}" == "true" ]]; then
echo "PAYLOAD_LICENSE_TYPE=team" >> $GITHUB_ENV
elif [[ "${{ contains(github.event.pull_request.labels.*.name, 'feature-branch-business') }}" == "true" ]]; then
echo "PAYLOAD_LICENSE_TYPE=business" >> $GITHUB_ENV
elif [[ "${{ contains(github.event.pull_request.labels.*.name, 'feature-branch-enterprise') }}" == "true" ]]; then
echo "PAYLOAD_LICENSE_TYPE=enterprise" >> $GITHUB_ENV
else
echo "PAYLOAD_LICENSE_TYPE=free" >> $GITHUB_ENV
fi
- uses: passeidireto/trigger-external-workflow-action@main
env:
PAYLOAD_BRANCH: ${{ github.head_ref }}
PAYLOAD_PR_NUMBER: ${{ github.event.pull_request.number }}
PAYLOAD_LICENSE_TYPE: "free"
PAYLOAD_LICENSE_TYPE: ${{ env.PAYLOAD_LICENSE_TYPE }}
with:
repository: budibase/budibase-deploys
event: featurebranch-qa-deploy

View File

@ -1,6 +1,6 @@
{
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
"version": "2.32.16",
"version": "2.32.17",
"npmClient": "yarn",
"packages": [
"packages/*",

View File

@ -273,6 +273,7 @@ class InternalBuilder {
const col = parts.pop()!
const schema = this.table.schema[col]
let identifier = this.quotedIdentifier(field)
if (
schema.type === FieldType.STRING ||
schema.type === FieldType.LONGFORM ||
@ -957,6 +958,13 @@ class InternalBuilder {
return query
}
isAggregateField(field: string): boolean {
const found = this.query.resource?.aggregations?.find(
aggregation => aggregation.name === field
)
return !!found
}
addSorting(query: Knex.QueryBuilder): Knex.QueryBuilder {
let { sort, resource } = this.query
const primaryKey = this.table.primary
@ -979,6 +987,9 @@ class InternalBuilder {
nulls = value.direction === SortOrder.ASCENDING ? "first" : "last"
}
if (this.isAggregateField(key)) {
query = query.orderBy(key, direction, nulls)
} else {
let composite = `${aliased}.${key}`
if (this.client === SqlClient.ORACLE) {
query = query.orderByRaw(
@ -989,6 +1000,7 @@ class InternalBuilder {
}
}
}
}
// add sorting by the primary key if the result isn't already sorted by it,
// to make sure result is deterministic

View File

@ -27,10 +27,7 @@
let candidateIndex
let lastSearchId
let searching = false
let container
let anchor
let relationshipAnchor
let relationshipFields
$: fieldValue = parseValue(value)
$: oneRowOnly = schema?.relationshipType === "one-to-many"
@ -57,13 +54,6 @@
return acc
}, {})
$: showRelationshipFields =
relationshipAnchor &&
relationshipFields &&
Object.keys(relationshipFields).length &&
focused &&
!isOpen
const parseValue = value => {
if (Array.isArray(value) && value.every(x => x?._id)) {
return value
@ -245,16 +235,6 @@
return value
}
const displayRelationshipFields = (e, relationship) => {
relationshipAnchor = e.target
relationshipFields = relationFields[relationship._id]
}
const hideRelationshipFields = () => {
relationshipAnchor = null
relationshipFields = undefined
}
onMount(() => {
api = {
focus: open,
@ -274,7 +254,7 @@
style="--color:{color};"
bind:this={anchor}
>
<div class="container" bind:this={container}>
<div class="container">
<div
class="values"
class:wrap={editable || contentLines > 1}
@ -286,9 +266,7 @@
<div
class="badge"
class:extra-info={!!relationFields[relationship._id]}
on:mouseenter={e => displayRelationshipFields(e, relationship)}
on:focus={() => {}}
on:mouseleave={() => hideRelationshipFields()}
>
<span>
{readable(
@ -363,26 +341,6 @@
</GridPopover>
{/if}
{#if showRelationshipFields}
<GridPopover
anchor={relationshipAnchor}
maxWidth={400}
offset={4}
clickOutsideOverride
>
<div class="relationship-fields">
{#each Object.entries(relationshipFields) as [fieldName, fieldValue]}
<div class="relationship-field-name">
{fieldName}
</div>
<div class="relationship-field-value">
{fieldValue}
</div>
{/each}
</div>
</GridPopover>
{/if}
<style>
.wrapper {
flex: 1 1 auto;
@ -547,29 +505,4 @@
.search :global(.spectrum-Form-item) {
flex: 1 1 auto;
}
.relationship-fields {
margin: var(--spacing-m) var(--spacing-l);
display: grid;
grid-template-columns: auto 1fr;
grid-row-gap: var(--spacing-m);
grid-column-gap: var(--spacing-xl);
}
.relationship-field-name {
text-transform: uppercase;
color: var(--spectrum-global-color-gray-600);
font-size: 12px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
max-width: 120px;
}
.relationship-field-value {
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
line-clamp: 3;
}
</style>

@ -1 +1 @@
Subproject commit aca9828117bb97f54f40ee359f1a3f6e259174e7
Subproject commit fc4c7f4925139af078480217965c3d6338dc0a7f

View File

@ -3381,6 +3381,124 @@ describe.each([
expect(rows).toHaveLength(1)
expect(rows[0].sum).toEqual(3)
})
it("should be able to sort by group by field", async () => {
const table = await config.api.table.save(
saveTableRequest({
schema: {
quantity: {
type: FieldType.NUMBER,
name: "quantity",
},
price: {
type: FieldType.NUMBER,
name: "price",
},
},
})
)
const view = await config.api.viewV2.create({
tableId: table._id!,
name: generator.guid(),
type: ViewV2Type.CALCULATION,
schema: {
quantity: { visible: true },
sum: {
visible: true,
calculationType: CalculationType.SUM,
field: "price",
},
},
})
await config.api.row.bulkImport(table._id!, {
rows: [
{
quantity: 1,
price: 1,
},
{
quantity: 1,
price: 2,
},
{
quantity: 2,
price: 10,
},
],
})
const { rows } = await config.api.viewV2.search(view.id, {
query: {},
sort: "quantity",
sortOrder: SortOrder.DESCENDING,
})
expect(rows).toEqual([
expect.objectContaining({ quantity: 2, sum: 10 }),
expect.objectContaining({ quantity: 1, sum: 3 }),
])
})
it("should be able to sort by a calculation", async () => {
const table = await config.api.table.save(
saveTableRequest({
schema: {
quantity: {
type: FieldType.NUMBER,
name: "quantity",
},
price: {
type: FieldType.NUMBER,
name: "price",
},
},
})
)
await config.api.row.bulkImport(table._id!, {
rows: [
{
quantity: 1,
price: 1,
},
{
quantity: 1,
price: 2,
},
{
quantity: 2,
price: 10,
},
],
})
const view = await config.api.viewV2.create({
tableId: table._id!,
name: generator.guid(),
type: ViewV2Type.CALCULATION,
schema: {
quantity: { visible: true },
sum: {
visible: true,
calculationType: CalculationType.SUM,
field: "price",
},
},
})
const { rows } = await config.api.viewV2.search(view.id, {
query: {},
sort: "sum",
sortOrder: SortOrder.DESCENDING,
})
expect(rows).toEqual([
expect.objectContaining({ quantity: 2, sum: 10 }),
expect.objectContaining({ quantity: 1, sum: 3 }),
])
})
})
!isLucene &&

View File

@ -418,6 +418,16 @@ export async function search(
if (params.sort) {
const sortField = table.schema[params.sort]
const isAggregateField = aggregations.some(agg => agg.name === params.sort)
if (isAggregateField) {
request.sort = {
[params.sort]: {
direction: params.sortOrder || SortOrder.ASCENDING,
type: SortType.NUMBER,
},
}
} else if (sortField) {
const sortType =
sortField.type === FieldType.NUMBER ? SortType.NUMBER : SortType.STRING
request.sort = {
@ -426,6 +436,9 @@ export async function search(
type: sortType as SortType,
},
}
} else {
throw new Error(`Unable to sort by ${params.sort}`)
}
}
if (params.bookmark && typeof params.bookmark !== "number") {

View File

@ -172,7 +172,7 @@ export const processSearchFilters = (
.sort((a, b) => {
return a.localeCompare(b)
})
.filter(key => key in filter)
.filter(key => filter[key])
if (filterPropertyKeys.length == 1) {
const key = filterPropertyKeys[0],