Compare commits

...

7 Commits

Author SHA1 Message Date
David B.M.
f539713e10 feat: add set to null edit button 2025-03-16 23:46:07 +01:00
David B.M.
9b150c786e fix: correct types when there is no actual default value 2025-03-16 23:46:07 +01:00
David B.M.
3d917b6e12 chore: asd 2025-03-16 23:46:07 +01:00
David B.M.
7574504cd5 chore: add changeset 2025-03-16 23:46:07 +01:00
David B.M.
be9f6b6967 feat: create rows with default empty string value 2025-03-16 23:46:07 +01:00
David B.M.
affe9db42a feat: add empty string default in table creation 2025-03-16 23:46:07 +01:00
David BM
15421321f4 fix (ci): update PNPM dependencies to fix audit security vulnerabilities (#3236)
### **PR Type**
Enhancement, Bug fix


___

### **Description**
- Update Babel dependencies to latest versions

- Add overrides for Babel runtime and helpers

- Address security vulnerabilities in dependencies

- Improve CI/CD pipeline security and stability


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Dependencies</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>package.json</strong><dd><code>Update Babel and address
dependency vulnerabilities</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>

package.json

<li>Updated Babel core and plugin dependencies<br> <li> Added overrides
for @babel/runtime and @babel/helpers<br> <li> Updated various
dependency version constraints<br> <li> Addressed multiple security
vulnerabilities in dependencies


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3236/files#diff-7ae45ad102eab3b6d7e7896acd08c427a9b25b346470d7bc6507b6481575d519">+6/-4</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></td></tr></tr></tbody></table>

___

> <details> <summary> Need help?</summary><li>Type <code>/help how to
...</code> in the comments thread for any questions about PR-Agent
usage.</li><li>Check out the <a
href="https://qodo-merge-docs.qodo.ai/usage-guide/">documentation</a>
for more information.</li></details>
2025-03-14 15:31:18 +01:00
10 changed files with 1827 additions and 460 deletions

View File

@@ -0,0 +1,5 @@
---
'@nhost/dashboard': minor
---
feat: add empty string as default value for text in databases

View File

@@ -0,0 +1,5 @@
---
'@nhost/dashboard': minor
---
fix: update babel dependencies to address security audit vulnerabilities

View File

@@ -44,7 +44,10 @@ export default function BaseRecordForm({
(accumulator, column) => {
if (
column.isPrimary ||
(!column.isNullable && !column.defaultValue && !column.isIdentity)
(!column.isNullable &&
!column.defaultValue &&
!column.isDefaultValueCustom &&
!column.isIdentity)
) {
return {
...accumulator,
@@ -96,7 +99,12 @@ export default function BaseRecordForm({
const gridColumn = gridColumnMap.get(columnId);
const value = columnValues[columnId];
if (!value && (gridColumn?.defaultValue || gridColumn?.isIdentity)) {
if (
!value &&
(gridColumn?.defaultValue ||
gridColumn?.defaultValue === '' ||
gridColumn?.isIdentity)
) {
return {
...options,
[columnId]: {
@@ -147,7 +155,7 @@ export default function BaseRecordForm({
{optionalColumns.length > 0 && (
<DatabaseRecordInputGroup
title="Optional columns"
description="These columns are nullable and don't require a value."
description="These columns are nullable or have a default value."
columns={optionalColumns}
autoFocusFirstInput={requiredColumns.length === 0}
sx={{ borderTopWidth: requiredColumns.length > 0 ? 1 : 0 }}

View File

@@ -18,7 +18,7 @@ import {
} from '@/features/orgs/projects/database/dataGrid/utils/postgresqlConstants';
import clsx from 'clsx';
import type { PropsWithoutRef } from 'react';
import { memo, useEffect, useState } from 'react';
import { memo, useEffect, useMemo, useState } from 'react';
import type { FieldError } from 'react-hook-form';
import { useFormContext, useFormState, useWatch } from 'react-hook-form';
@@ -150,6 +150,13 @@ function DefaultValueAutocomplete({ index }: FieldArrayInputProps) {
}),
);
const formattedInputValue = useMemo(() => {
if (defaultValue?.value === '') {
return "''::text";
}
return isIdentity ? '' : inputValue;
}, [isIdentity, defaultValue?.value, inputValue]);
useEffect(() => {
if (!defaultValue) {
setInputValue('');
@@ -176,7 +183,7 @@ function DefaultValueAutocomplete({ index }: FieldArrayInputProps) {
placeholder="NULL"
error={Boolean(errors?.columns?.[index]?.defaultValue)}
helperText={errors?.columns?.[index]?.defaultValue?.message}
inputValue={isIdentity ? '' : inputValue}
inputValue={formattedInputValue}
onInputChange={(_event, value) => setInputValue(value)}
onBlur={(event) => {
if (event.target instanceof HTMLInputElement && !event.target.value) {

View File

@@ -53,10 +53,10 @@ export default function CreateRecordForm({
return (
<FormProvider {...form}>
{error && error instanceof Error && (
<div className="-mt-3 mb-4 px-6">
<div className="px-6 mb-4 -mt-3">
<Alert
severity="error"
className="grid grid-flow-col items-center justify-between px-4 py-3"
className="grid items-center justify-between grid-flow-col px-4 py-3"
>
<span className="text-left">
<strong>Error:</strong> {error.message}

View File

@@ -34,6 +34,7 @@ export interface DatabaseRecordInputGroupProps extends BoxProps {
function getPlaceholder(
defaultValue?: string,
isDefaultValueCustom?: boolean,
isIdentity?: boolean,
isNullable?: boolean,
) {
@@ -45,6 +46,10 @@ function getPlaceholder(
return 'NULL';
}
if (defaultValue === '' && isDefaultValueCustom) {
return `Automatically generated value: ''`;
}
if (!defaultValue) {
return '';
}
@@ -102,6 +107,7 @@ export default function DatabaseRecordInputGroup({
specificType,
maxLength,
defaultValue,
isDefaultValueCustom,
isPrimary,
isNullable,
isIdentity,
@@ -118,6 +124,7 @@ export default function DatabaseRecordInputGroup({
const placeholder = getPlaceholder(
defaultValue,
isDefaultValueCustom,
isIdentity,
isNullable,
);

View File

@@ -186,7 +186,7 @@ export const dateFunctions = [
* Relevant functions for PostgreSQL types.
*/
export const postgresFunctions = {
text: ['version()', 'timeofday()'],
text: ['version()', 'timeofday()', "''::text"],
json: ['json_build_object()', 'json_build_array()'],
jsonb: ['jsonb_build_object()', 'jsonb_build_array()'],
date: dateFunctions,

View File

@@ -1,3 +1,4 @@
import { Box } from '@/components/ui/v2/Box';
import { Button } from '@/components/ui/v2/Button';
import { CopyIcon } from '@/components/ui/v2/icons/CopyIcon';
import { Input, inputClasses } from '@/components/ui/v2/Input';
@@ -57,6 +58,14 @@ export default function DataGridTextCell<TData extends object>({
}
}
async function handleSetToNull() {
if (onSave) {
await onSave(null);
// Unfocus the cell
cancelEditCell();
}
}
async function handleInputKeyDown(event: KeyboardEvent<HTMLInputElement>) {
if (
event.key === 'ArrowLeft' ||
@@ -122,36 +131,58 @@ export default function DataGridTextCell<TData extends object>({
if (isEditing && isMultiline) {
return (
<Input
multiline
ref={inputRef as Ref<HTMLInputElement>}
value={(normalizedTemporaryValue || '').replace(/\\n/gi, `\n`)}
onChange={handleChange}
onKeyDown={handleTextAreaKeyDown}
fullWidth
className="absolute top-0 z-10 -mx-0.5 h-full min-h-38"
rows={5}
<Box
className="absolute top-0 z-10 -mx-0.5 h-full min-h-36 w-full"
sx={{
[`&.${inputClasses.focused}`]: {
boxShadow: `inset 0 0 0 1.5px rgba(0, 82, 205, 1)`,
borderColor: 'transparent !important',
borderRadius: 0,
backgroundColor: (theme) =>
theme.palette.mode === 'dark'
? `${theme.palette.secondary[100]} !important`
: `${theme.palette.common.white} !important`,
},
[`& .${inputClasses.input}`]: {
backgroundColor: 'transparent',
},
backgroundColor: (theme) =>
theme.palette.mode === 'dark'
? `${theme.palette.secondary[100]} !important`
: `${theme.palette.common.white} !important`,
}}
slotProps={{
inputRoot: {
className:
'resize-none outline-none focus:outline-none !text-xs focus:ring-0',
},
}}
/>
>
<Input
multiline
ref={inputRef as Ref<HTMLInputElement>}
value={(normalizedTemporaryValue || '').replace(/\\n/gi, `\n`)}
onChange={handleChange}
onKeyDown={handleTextAreaKeyDown}
fullWidth
autoFocus
className="z-10"
rows={5}
sx={{
[`&.${inputClasses.focused}`]: {
boxShadow: `inset 0 0 0 1.5px rgba(0, 82, 205, 1)`,
borderColor: 'transparent !important',
borderRadius: 0,
backgroundColor: (theme) =>
theme.palette.mode === 'dark'
? `${theme.palette.secondary[100]} !important`
: `${theme.palette.common.white} !important`,
},
[`& .${inputClasses.input}`]: {
backgroundColor: 'transparent',
},
}}
slotProps={{
inputRoot: {
className:
'resize-none outline-none focus:outline-none !text-xs focus:ring-0',
},
}}
/>
<div className="my-0 flex flex-1 items-center justify-end p-2">
<Button
className="z-10"
size="small"
variant="outlined"
color="secondary"
onClick={handleSetToNull}
>
Set to NULL
</Button>
</div>
</Box>
);
}
@@ -174,9 +205,6 @@ export default function DataGridTextCell<TData extends object>({
? `${theme.palette.secondary[100]} !important`
: `${theme.palette.common.white} !important`,
},
[`& .${inputClasses.input}`]: {
backgroundColor: 'transparent',
},
}}
slotProps={{
inputWrapper: { className: 'h-full' },

View File

@@ -56,10 +56,10 @@
"dashboard"
],
"devDependencies": {
"@babel/core": "^7.24.7",
"@babel/eslint-parser": "^7.24.7",
"@babel/plugin-syntax-flow": "^7.24.7",
"@babel/plugin-transform-react-jsx": "^7.24.7",
"@babel/core": "^7.26.10",
"@babel/eslint-parser": "^7.26.10",
"@babel/plugin-syntax-flow": "^7.26.0",
"@babel/plugin-transform-react-jsx": "^7.25.9",
"@changesets/cli": "^2.27.5",
"@faker-js/faker": "^7.6.0",
"@rollup/plugin-replace": "^5.0.7",
@@ -137,6 +137,8 @@
"tough-cookie@<4.1.3": ">=4.1.3",
"protobufjs@>=7.0.0 <7.2.4": ">=7.2.4",
"vite@=4.5.0": ">=4.5.1",
"@babel/runtime@<7.26.10": ">=7.26.10",
"@babel/helpers@<7.26.10": ">=7.26.10",
"@babel/traverse@<7.23.2": ">=7.23.2",
"@adobe/css-tools@<4.3.2": ">=4.3.2",
"semver@<5.7.2": ">=5.7.2",

2139
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff