Skip to content
Merged
6 changes: 2 additions & 4 deletions backend/uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"type": "bug",
"message": "Set correct locale in application builder date picker.",
"issue_origin": "github",
"issue_number": null,
"domain": "builder",
"bullet_points": [],
"created_at": "2026-02-20"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"type": "bug",
"message": "Fixed prevent moving forward in scratch onboarding step validation bug.",
"issue_origin": "github",
"issue_number": null,
"domain": "core",
"bullet_points": [],
"created_at": "2026-02-20"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"type": "bug",
"message": "Fix table reorder bug with realtime event.",
"issue_origin": "github",
"issue_number": null,
"domain": "database",
"bullet_points": [],
"created_at": "2026-02-20"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"type": "bug",
"message": "Fix re-opening new data source modal bug.",
"issue_origin": "github",
"issue_number": null,
"domain": "builder",
"bullet_points": [],
"created_at": "2026-02-20"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"type": "bug",
"message": "Fix wrong date selection in the datepicker when editing values directly in the text input.",
"issue_origin": "github",
"issue_number": null,
"domain": "core",
"bullet_points": [],
"created_at": "2026-02-20"
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
<Button
size="large"
:loading="loading"
:disabled="loading || !changed || $refs.dataSourceForm.v$.$anyError"
:disabled="submitIsDisabled"
@click.prevent="$refs.dataSourceForm.submit()"
>
{{ create ? $t('action.create') : $t('action.save') }}
Expand Down Expand Up @@ -86,6 +86,11 @@ export default {
}
},
computed: {
submitIsDisabled() {
return (
this.loading || !this.changed || this.$refs.dataSourceForm.v$.$anyError
)
},
dataSources() {
return this.$store.getters['dataSource/getPageDataSources'](
this.currentPage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
:open-date="calendarValue || new Date()"
:inline="true"
:monday-first="true"
:language="datePickerLanguage"
class="ab-datetime-picker__calendar"
@update:model-value="updateDate"
/>
Expand Down Expand Up @@ -67,6 +68,7 @@

<script>
import { DATE_FORMATS, TIME_FORMATS } from '@baserow/modules/builder/enums'
import { useDatePickerLanguage } from '@baserow/modules/core/composables/useDatePickerLanguage'
import {
generateTimePickerTimes,
parseDateForCalendar,
Expand Down Expand Up @@ -136,6 +138,9 @@ export default {
immediate: true,
},
},
setup() {
return useDatePickerLanguage()
},
methods: {
refreshDate(value) {
if (!value) {
Expand Down
2 changes: 1 addition & 1 deletion web-frontend/modules/builder/date.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,6 @@ export function parseDateForCalendar(value, dateFormat) {
if (!value) {
return null
}
const parsedDate = moment.utc(value, dateFormat, true) // Strict parsing
const parsedDate = moment(value, dateFormat, true) // Strict parsing
return parsedDate.isValid() ? parsedDate.toDate() : null
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,33 @@ export const ZWSManagementExtension = Extension.create({
key: new PluginKey('zwsManagement'),
appendTransaction(transactions, oldState, newState) {
const tr = newState.tr
let modified = false

// Phase 1: Clean up consecutive ZWS
// Phase 1: Clean up consecutive ZWS.
// Collect replacements first, then apply in reverse order to avoid
// position drift: each insertText changes the document length, so
// positions calculated during iteration become invalid after the first
// modification. Applying in reverse (highest pos first) keeps earlier
// positions valid for subsequent operations.
const zwsReplacements = []
newState.doc.descendants((node, pos) => {
if (node.isText && node.text) {
// Check if the text contains multiple consecutive ZWS
const text = node.text
if (text.includes('\u200B\u200B')) {
// Replace multiple consecutive ZWS with a single one
const cleanedText = text.replace(/\u200B+/g, '\u200B')
if (cleanedText !== text) {
tr.insertText(cleanedText, pos, pos + node.nodeSize)
modified = true
zwsReplacements.push({
cleanedText,
pos,
end: pos + node.nodeSize,
})
}
}
}
})
let modified = Boolean(zwsReplacements.length)
for (const { cleanedText, pos, end } of zwsReplacements.reverse()) {
tr.insertText(cleanedText, pos, end)
}

// Apply cleanup changes before checking for missing ZWS
const docAfterCleanup = modified ? tr.doc : newState.doc
Expand Down
3 changes: 3 additions & 0 deletions web-frontend/modules/core/utils/hashing.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { sha256 } from 'js-sha256'

export function generateHash(value) {
if (Number.isInteger(value)) {
value = String(value)
}
// TODO MIG do we want to use browser async version
return sha256(value)
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,23 +43,17 @@
v-show="what !== ''"
:key="index"
class="margin-bottom-2"
:error="v$['row' + index]?.$error"
small-label
>
<template v-if="index === 0" #label>
{{ $t('databaseScratchTrackStep.thisIncludes') }}</template
>
<FormInput
v-model="v$['row' + index].$model"
v-model="$data['row' + index]"
:placeholder="$t('databaseScratchTrackStep.rowName') + '...'"
size="large"
:error="v$['row' + index]?.$error"
@input="updateValue"
@blur="v$['row' + index].$touch"
/>
<template #error>
{{ v$['row' + index].$errors[0].$message }}
</template>
</FormGroup>
</div>
</template>
Expand Down Expand Up @@ -126,14 +120,17 @@ export default {
this.what !== value &&
Object.prototype.hasOwnProperty.call(this.whatItems, value)
) {
this.v$.row0.$model = this.whatItems[value][0]
this.v$.row1.$model = this.whatItems[value][1]
this.v$.row2.$model = this.whatItems[value][2]
this.row0 = this.whatItems[value][0]
this.row1 = this.whatItems[value][1]
this.row2 = this.whatItems[value][2]
}

// this.v$.row0?.$touch()
this.what = value
this.updateValue()

this.$nextTick(() => {
this.v$.$touch()
this.updateValue()
})
},
updateValue() {
this.$nextTick(() => {
Expand All @@ -146,16 +143,6 @@ export default {
validations() {
const rules = {}

rules.row0 = {
required: helpers.withMessage(this.$t('error.requiredField'), required),
}
rules.row1 = {
required: helpers.withMessage(this.$t('error.requiredField'), required),
}
rules.row2 = {
required: helpers.withMessage(this.$t('error.requiredField'), required),
}

if (this.what === 'own') {
rules.tableName = {
required: helpers.withMessage(this.$t('error.requiredField'), required),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
:placeholder="getDatePlaceholder(field)"
@focus="$refs.dateContext.toggle($refs.date, 'bottom', 'left', 0)"
@blur="$refs.dateContext.hide()"
@input=";[setCopyFromDateString(dateString, 'dateString')]"
@input="setCopyFromDateString($event, 'dateString')"
@keydown.enter="delayedUpdate(copy, true)"
>
</FormInput>
Expand All @@ -26,7 +26,7 @@
:language="datePickerLanguage"
:open-date="dateObject || new Date()"
class="datepicker"
@updated:model-value="chooseDate($event)"
@update:model-value="chooseDate($event)"
></date-picker>
</client-only>
</Context>
Expand Down Expand Up @@ -78,6 +78,22 @@ export default {
this.setCopy(pickerDate.format('YYYY-MM-DD'), 'dateObject')
this.delayedUpdate(this.copy, true)
},
setDateObject(date) {
// Because of some bugs with parsing and localizing correctly dates
// in the vuejs3-datepicker component passed both as string and
// dates, we need to localize the date correctly and replace the
// timezone with the browser timezone. This is needed to be able to
// show the correct date in the datepicker.

if (date === null) {
this.dateObject = null
return
}

const pickerDate = date.clone()
pickerDate.tz(moment.tz.guess(), true)
this.dateObject = pickerDate.toDate()
},
setCopy(value, sender) {
const [timezone, filterValue] = this.splitCombinedValue(value)
this.timezoneValue = timezone
Expand All @@ -94,14 +110,7 @@ export default {
this.copy = newDate.format('YYYY-MM-DD')

if (sender !== 'dateObject') {
// Because of some bugs with parsing and localizing correctly dates in
// the vuejs3-datepicker component passed both as string and dates, we
// need to localize the date correctly and replace the timezone with
// the browser timezone. This is needed to be able to show the correct
// date in the datepicker.
const newPickerDate = newDate.clone()
newPickerDate.tz(moment.tz.guess(), true)
this.dateObject = newPickerDate.toDate()
this.setDateObject(newDate)
}

if (sender !== 'dateString') {
Expand All @@ -118,9 +127,9 @@ export default {

const dateFormat = getDateMomentFormat(this.field.date_format)
const timezone = this.getTimezone()
const newDate = moment.utc(value, dateFormat, true)
const newDate = moment(value, dateFormat, true)
if (timezone !== null) {
newDate.tz(timezone)
newDate.tz(timezone, true)
}

if (newDate.isValid()) {
Expand All @@ -145,7 +154,7 @@ export default {
dateString: {
isValidDate(value) {
const dateFormat = getDateMomentFormat(this.field.date_format)
return value === '' || moment.utc(value, dateFormat).isValid()
return value === '' || moment(value, dateFormat, true).isValid()
},
},
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
:placeholder="getDatePlaceholder(field)"
@focus="$refs.dateContext.toggle($refs.date, 'bottom', 'left', 0)"
@blur="$refs.dateContext.hide()"
@input="setCopyFromDateString(dateString, 'dateString')"
@input="setCopyFromDateString($event, 'dateString')"
@keydown.enter="delayedUpdate(copy, true)"
/>
</span>
Expand Down Expand Up @@ -124,6 +124,16 @@ export default {
operatorLabel(operator) {
return this.$t(`${operator.stringKey}`)
},
setDateObject(date) {
// Because of some bugs with parsing and localizing correctly dates
// in the vuejs3-datepicker component passed both as string and
// dates, we need to localize the date correctly and replace the
// timezone with the browser timezone. This is needed to be able to
// show the correct date in the datepicker.
const pickerDate = date.clone()
pickerDate.tz(moment.tz.guess(), true)
this.dateObject = pickerDate.toDate()
},
setCopy(combinedValue, sender) {
const [timezone, value, operator] = this.splitCombinedValue(combinedValue)
this.operatorValue = operator
Expand All @@ -143,14 +153,7 @@ export default {
this.copy = newDate.format('YYYY-MM-DD')

if (sender !== 'dateObject') {
// Because of some bugs with parsing and localizing correctly dates
// in the vuejs3-datepicker component passed both as string and
// dates, we need to localize the date correctly and replace the
// timezone with the browser timezone. This is needed to be able to
// show the correct date in the datepicker.
const pickerDate = newDate.clone()
pickerDate.tz(moment.tz.guess(), true)
this.dateObject = pickerDate.toDate()
this.setDateObject(newDate)
}

if (sender !== 'dateString') {
Expand Down Expand Up @@ -189,13 +192,14 @@ export default {

const dateFormat = getDateMomentFormat(this.field.date_format)
const timezone = this.getTimezone()
const newDate = moment.utc(value, dateFormat, true)
const newDate = moment(value, dateFormat, true)
if (timezone !== null) {
newDate.tz(timezone)
newDate.tz(timezone, true)
}

if (newDate.isValid()) {
const dateString = newDate.format('YYYY-MM-DD')
this.setDateObject(newDate)
this.setValue(dateString, sender)
} else {
this.copy = value
Expand Down
Loading
Loading