Skip to content

Commit

Permalink
Merge pull request #3987 from mathesar-foundation/record_summaries_ui
Browse files Browse the repository at this point in the history
Frontend support for configurable record summaries
  • Loading branch information
pavish authored Nov 12, 2024
2 parents fd4090a + f317e04 commit 20b9906
Show file tree
Hide file tree
Showing 67 changed files with 1,108 additions and 895 deletions.
12 changes: 12 additions & 0 deletions mathesar_ui/src/api/rpc/records.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { rpcMethodTypeContainer } from '@mathesar/packages/json-rpc-client-builder';

import type { RecordSummaryTemplate } from './tables';

export type ResultValue = string | number | boolean | null;

export type SortDirection = 'asc' | 'desc';
Expand Down Expand Up @@ -130,6 +132,16 @@ export const records = {
table_oid: number;
record_id: ResultValue;
return_record_summaries?: boolean;
/**
* Keys are stringified table OIDs. Values are record summary templates
* that will override the templates stored in table metadata. These
* overrides can be used to render a of a record summary using an
* ephemeral template before any template is stored.
* */
table_record_summary_templates?: Record<
string,
RecordSummaryTemplate | null
> | null;
},
RecordsResponse
>(),
Expand Down
14 changes: 12 additions & 2 deletions mathesar_ui/src/api/rpc/tables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@ export interface RawTablePrivilegesForRole {
direct: TablePrivilege[];
}

/**
* A string is static text to be displayed in the summary.
*
* An array of numbers indicates a reference to a column in the table. Each
* number is a column attnum. A sequence of multiple numbers indicates a chain
* of FK references, column-by-column.
*
*/
export type RecordSummaryTemplatePart = string | number[];
export type RecordSummaryTemplate = RecordSummaryTemplatePart[];

interface TableMetadata {
/** The id of the data file used during import while creating the table */
data_file_id: number | null;
Expand All @@ -45,8 +56,7 @@ interface TableMetadata {
*/
import_verified: boolean | null;
column_order: number[] | null;
record_summary_customized: boolean | null;
record_summary_template: string | null;
record_summary_template: RecordSummaryTemplate | null;
}

export interface RawTableWithMetadata extends RawTable {
Expand Down
52 changes: 18 additions & 34 deletions mathesar_ui/src/component-library/fieldset-group/FieldsetGroup.scss
Original file line number Diff line number Diff line change
@@ -1,48 +1,32 @@
.fieldset-group {
padding: 0;
margin: 0;
.fieldset-group-options {
--spacing-y-default: 0.5em;
--spacing-x-default: 1em;
padding-left: 0;
list-style-type: none;
margin-top: 0.25em;
margin-bottom: 0;

legend {
padding: 0;
font-weight: var(--font-weight-medium);
margin-bottom: 0.5rem;
}
.options {
padding-left: 0;
list-style-type: none;
margin-top: 0.25em;
margin-bottom: 0;
}
&.has-label .options {
&.has-fieldset-label {
margin-top: 1em;
}
&:not(.inline) .option:not(:first-child) {
margin-top: var(--spacing-y, var(--spacing-y-default));
}
&:not(.inline) .option:not(:last-child) {
margin-bottom: var(--spacing-y, var(--spacing-y-default));
}
&:not(.inline) .option.has-help:not(:last-child) {
margin-bottom: calc(2 * var(--spacing-y, var(--spacing-y-default)));

&:not(.inline) {
.option:not(:first-child) {
margin-top: var(--spacing-y, var(--spacing-y-default));
}
.option:not(:last-child) {
margin-bottom: var(--spacing-y, var(--spacing-y-default));
}
.option.has-help:not(:last-child) {
margin-bottom: calc(2 * var(--spacing-y, var(--spacing-y-default)));
}
}

&.inline .options {
&.inline {
display: flex;
flex-wrap: wrap;
.option:not(:last-child) {
margin-right: var(--spacing-x, var(--spacing-x-default));
}
}

&:not(.boxed) {
border: 0;
}
&.boxed {
border: 1px solid var(--slate-300);
border-radius: var(--border-radius-m);
padding: 1em;
padding-top: 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,40 +9,33 @@
import Render from '@mathesar-component-library-dir/render/Render.svelte';
import StringOrComponent from '@mathesar-component-library-dir/string-or-component/StringOrComponent.svelte';
import Fieldset from '../fieldset/Fieldset.svelte';
import type { ComponentWithProps } from '../types';
type Option = $$Generic;
export let isInline = false;
export let isInline: boolean | undefined = undefined;
export let options: readonly Option[] = [];
export let label: string | undefined = undefined;
export let ariaLabel: string | undefined = undefined;
export let disabled = false;
export let labelKey = 'label';
export let getLabel: LabelGetter<Option> = (o: Option) =>
defaultGetLabel(o, labelKey);
export let boxed = false;
export let boxed: boolean | undefined = undefined;
export let getDisabled: (value: Option | undefined) => boolean = () => false;
export let getHelp: <C extends SvelteComponent>(
value: Option,
) => string | ComponentWithProps<C> | undefined = () => undefined;
</script>

<fieldset
class="fieldset-group"
class:inline={isInline}
class:boxed
class:has-label={!!label}
aria-label={ariaLabel}
on:change
>
{#if $$slots.label || label}
<legend>
{#if $$slots.label}<slot name="label" />{/if}
{#if label}{label}{/if}
</legend>
{/if}
<ul class="options">
<Fieldset {ariaLabel} {boxed}>
<slot name="label" slot="label">{label}</slot>
<ul
class="fieldset-group-options"
class:inline={isInline}
class:has-fieldset-label={!!label}
>
{#each options as option (option)}
{@const help = getHelp(option)}
<li class="option" class:has-help={!!help}>
Expand All @@ -55,4 +48,4 @@
{/each}
</ul>
<slot name="extra" />
</fieldset>
</Fieldset>
23 changes: 23 additions & 0 deletions mathesar_ui/src/component-library/fieldset/Fieldset.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.fieldset {
padding: 0;
margin: 0;

legend {
padding: 0;
font-weight: var(--font-weight-medium);
margin-bottom: 0.5rem;
}
legend:empty {
display: none;
}

&:not(.boxed) {
border: 0;
}
&.boxed {
border: 1px solid var(--slate-300);
border-radius: var(--border-radius-m);
padding: 1em;
padding-top: 0;
}
}
18 changes: 18 additions & 0 deletions mathesar_ui/src/component-library/fieldset/Fieldset.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<script lang="ts">
export let label: string | undefined = undefined;
export let ariaLabel: string | undefined = undefined;
export let boxed = false;
</script>

<fieldset
class="fieldset"
class:boxed
class:has-label={!!label}
aria-label={ariaLabel}
on:change
>
{#if $$slots.label || label}
<legend><slot name="label">{label}</slot></legend>
{/if}
<slot />
</fieldset>
1 change: 1 addition & 0 deletions mathesar_ui/src/component-library/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export { default as Chip } from './chip/Chip.svelte';
export { default as Collapsible } from './collapsible/Collapsible.svelte';
export { default as ContextMenu } from './context-menu/ContextMenu.svelte';
export { default as Debounce } from './debounce/Debounce.svelte';
export { default as Fieldset } from './fieldset/Fieldset.svelte';
export { default as Help } from './help/Help.svelte';
export { default as Icon } from './icon/Icon.svelte';
export { InputGroup, InputGroupText } from './input-group';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte';
import type { LabelGetter } from '@mathesar-component-library-dir/common/utils/formatUtils';
import FieldsetGroup from '@mathesar-component-library-dir/fieldset-group/FieldsetGroup.svelte';
import Radio from '@mathesar-component-library-dir/radio/Radio.svelte';
type Option = $$Generic;
const dispatch = createEventDispatcher<{ change: { value: Option } }>();
export let value: Option | undefined = undefined;
export let isInline = false;
export let options: readonly Option[] = [];
Expand Down Expand Up @@ -34,13 +38,11 @@
<FieldsetGroup
{isInline}
{options}
{label}
{ariaLabel}
{disabled}
{boxed}
let:option
let:disabled={innerDisabled}
on:change
labelKey={radioLabelKey}
getLabel={getRadioLabel}
>
Expand All @@ -51,8 +53,9 @@
if (checked) {
value = option;
}
dispatch('change', { value: option });
}}
/>
<slot slot="label" />
<slot slot="label" name="label">{label}</slot>
<slot slot="extra" name="extra" />
</FieldsetGroup>
1 change: 1 addition & 0 deletions mathesar_ui/src/component-library/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
@import 'checkbox/Checkbox.scss';
@import 'chip/Chip.scss';
@import 'collapsible/Collapsible.scss';
@import 'fieldset/Fieldset.scss';
@import 'fieldset-group/FieldsetGroup.scss';
@import 'icon/Icon.scss';
@import 'input-group/InputGroup.scss';
Expand Down
4 changes: 2 additions & 2 deletions mathesar_ui/src/components/LinkedRecord.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@
let isHoveringRecordPageLink = false;
$: label = (() => {
if (recordSummary) {
if (recordSummary && recordSummary.trim() !== '') {
return recordSummary;
}
if (recordId !== undefined) {
return String(recordId);
}
return '(Unknown)';
return '?';
})();
function handleDeleteButtonClick() {
Expand Down
15 changes: 13 additions & 2 deletions mathesar_ui/src/components/SelectProcessedColumn.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,29 @@
export let columns: ProcessedColumn[];
export let value: ProcessedColumn | undefined = undefined;
export let disabled = false;
export let onUpdate: ((v: ProcessedColumn | undefined) => void) | undefined =
undefined;
export let allowEmpty = false;
</script>

<Select
options={columns}
options={[...(allowEmpty ? [undefined] : []), ...columns]}
labelKey="name"
valuesAreEqual={(a, b) => a?.id === b?.id}
bind:value
{disabled}
on:change
on:change={({ detail: column }) => onUpdate?.(column)}
let:option
>
{#if option}
<ProcessedColumnName processedColumn={option} />
{:else}
<div class="empty"></div>
{/if}
</Select>

<style>
.empty {
min-width: 3rem;
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@
import { _ } from 'svelte-i18n';
import NameWithIcon from '@mathesar/components/NameWithIcon.svelte';
import {
abstractTypesMap,
getAllowedAbstractTypesForDbTypeAndItsTargetTypes,
} from '@mathesar/stores/abstract-types';
import { getAllowedAbstractTypesForDbTypeAndItsTargetTypes } from '@mathesar/stores/abstract-types';
import { typeCastMap } from '@mathesar/stores/abstract-types/typeCastMap';
import type { AbstractType } from '@mathesar/stores/abstract-types/types';
import { LabeledInput, Select } from '@mathesar-component-library';
Expand All @@ -28,7 +25,6 @@
$: allowedTypeConversions = getAllowedAbstractTypesForDbTypeAndItsTargetTypes(
column.type,
typeCastMap[column.type] ?? [],
abstractTypesMap,
).filter((item) => !['jsonlist', 'map'].includes(item.identifier));
function selectAbstractType(
Expand Down
10 changes: 2 additions & 8 deletions mathesar_ui/src/components/cell-fabric/data-types/utils.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
import type { DbType } from '@mathesar/AppTypes';
import {
abstractTypesMap,
getAbstractTypeForDbType,
} from '@mathesar/stores/abstract-types';
import { getAbstractTypeForDbType } from '@mathesar/stores/abstract-types';
import type { CellInfo } from '@mathesar/stores/abstract-types/types';

export function getCellInfo(dbType: DbType): CellInfo | undefined {
const abstractTypeOfColumn = getAbstractTypeForDbType(
dbType,
abstractTypesMap,
);
const abstractTypeOfColumn = getAbstractTypeForDbType(dbType);
return abstractTypeOfColumn?.cellInfo;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
import { _ } from 'svelte-i18n';
import CellFabric from '@mathesar/components/cell-fabric/CellFabric.svelte';
import type { SelectedCellData } from './cellInspectorUtils';
import type { SelectedCellData } from '@mathesar/components/sheet/selection';
export let selectedCellData: SelectedCellData;
Expand Down
16 changes: 0 additions & 16 deletions mathesar_ui/src/components/inspector/cell/cellInspectorUtils.ts

This file was deleted.

Loading

0 comments on commit 20b9906

Please sign in to comment.