includio-cms 0.5.1 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +35 -12
- package/ROADMAP.md +17 -0
- package/dist/admin/client/entry/entry-form.svelte +1 -0
- package/dist/admin/client/entry/entry.svelte +130 -123
- package/dist/admin/client/entry/hybrid/hybrid-preview.svelte +92 -9
- package/dist/admin/components/dashboard/changelog-dialog.svelte +16 -6
- package/dist/admin/components/fields/blocks-field.svelte +142 -112
- package/dist/admin/components/fields/blocks-field.svelte.d.ts +10 -30
- package/dist/admin/components/fields/boolean-field.svelte +28 -38
- package/dist/admin/components/fields/boolean-field.svelte.d.ts +5 -27
- package/dist/admin/components/fields/checkboxes-field.svelte +12 -24
- package/dist/admin/components/fields/checkboxes-field.svelte.d.ts +5 -27
- package/dist/admin/components/fields/content-field.svelte +4 -17
- package/dist/admin/components/fields/content-field.svelte.d.ts +5 -27
- package/dist/admin/components/fields/date-field.svelte +8 -21
- package/dist/admin/components/fields/date-field.svelte.d.ts +5 -27
- package/dist/admin/components/fields/datetime-field.svelte +8 -21
- package/dist/admin/components/fields/datetime-field.svelte.d.ts +5 -27
- package/dist/admin/components/fields/field-renderer.svelte +32 -19
- package/dist/admin/components/fields/field-renderer.svelte.d.ts +1 -1
- package/dist/admin/components/fields/field-value-bridge.svelte +21 -0
- package/dist/admin/components/fields/field-value-bridge.svelte.d.ts +31 -0
- package/dist/admin/components/fields/fields-form.svelte +13 -10
- package/dist/admin/components/fields/file-field.svelte +12 -27
- package/dist/admin/components/fields/file-field.svelte.d.ts +5 -27
- package/dist/admin/components/fields/image-field.svelte +13 -28
- package/dist/admin/components/fields/image-field.svelte.d.ts +5 -27
- package/dist/admin/components/fields/media-field.svelte +15 -30
- package/dist/admin/components/fields/media-field.svelte.d.ts +5 -27
- package/dist/admin/components/fields/number-field.svelte +6 -20
- package/dist/admin/components/fields/number-field.svelte.d.ts +5 -27
- package/dist/admin/components/fields/object-field.svelte +26 -29
- package/dist/admin/components/fields/object-field.svelte.d.ts +11 -31
- package/dist/admin/components/fields/radio-field.svelte +8 -20
- package/dist/admin/components/fields/radio-field.svelte.d.ts +5 -27
- package/dist/admin/components/fields/relation-field.svelte +15 -30
- package/dist/admin/components/fields/relation-field.svelte.d.ts +5 -27
- package/dist/admin/components/fields/richtext-field.svelte +4 -17
- package/dist/admin/components/fields/richtext-field.svelte.d.ts +5 -27
- package/dist/admin/components/fields/select-field.svelte +14 -28
- package/dist/admin/components/fields/select-field.svelte.d.ts +5 -27
- package/dist/admin/components/fields/seo-field.svelte +5 -12
- package/dist/admin/components/fields/seo-field.svelte.d.ts +8 -28
- package/dist/admin/components/fields/simple-array-field.svelte +29 -42
- package/dist/admin/components/fields/simple-array-field.svelte.d.ts +5 -27
- package/dist/admin/components/fields/slug-field.svelte +6 -11
- package/dist/admin/components/fields/slug-field.svelte.d.ts +6 -26
- package/dist/admin/components/fields/text-field-wrapper.svelte +22 -40
- package/dist/admin/components/fields/text-field.svelte +7 -19
- package/dist/admin/components/fields/text-field.svelte.d.ts +5 -27
- package/dist/admin/components/fields/url-field-wrapper.svelte +8 -3
- package/dist/admin/components/fields/url-field.svelte +294 -128
- package/dist/admin/components/fields/url-field.svelte.d.ts +5 -27
- package/dist/admin/components/layout/layout-renderer.svelte +8 -6
- package/dist/admin/components/tiptap/InlineBlockNodeView.svelte +221 -31
- package/dist/admin/components/tiptap/content-editor.svelte +13 -2
- package/dist/admin/components/tiptap/inline-block-node.d.ts +1 -0
- package/dist/admin/components/tiptap/inline-block-node.js +18 -1
- package/dist/admin/components/tiptap/slash-command.js +2 -3
- package/dist/admin/components/tiptap/standalone-form.d.ts +7 -0
- package/dist/admin/components/tiptap/standalone-form.js +31 -0
- package/dist/admin/components/tiptap/tiptap-editor.svelte +7 -0
- package/dist/admin/remote/entry.remote.js +16 -0
- package/dist/admin/styles/admin.css +10 -0
- package/dist/admin/utils/fieldCondition.d.ts +6 -0
- package/dist/admin/utils/fieldCondition.js +20 -0
- package/dist/components/ui/switch/index.d.ts +2 -0
- package/dist/components/ui/switch/index.js +4 -0
- package/dist/components/ui/switch/switch.svelte +26 -0
- package/dist/components/ui/switch/switch.svelte.d.ts +4 -0
- package/dist/core/fields/fieldSchemaToTs.js +15 -3
- package/dist/core/fields/formFieldSchemaToTs.js +22 -6
- package/dist/core/fields/urlUtils.d.ts +14 -0
- package/dist/core/fields/urlUtils.js +21 -0
- package/dist/core/server/fields/populateEntry.js +43 -0
- package/dist/core/server/fields/resolveImageFields.js +33 -1
- package/dist/core/server/fields/resolveRelationFields.js +46 -0
- package/dist/core/server/fields/resolveRichtextLinks.js +15 -1
- package/dist/core/server/fields/resolveUrlFields.js +65 -0
- package/dist/core/server/generator/formFieldSchemaToString.js +40 -9
- package/dist/core/server/generator/formFields.js +2 -0
- package/dist/core/server/generator/generator.js +25 -1
- package/dist/schemas/field/url.d.ts +2 -0
- package/dist/schemas/field/url.js +4 -2
- package/dist/types/fields.d.ts +9 -0
- package/dist/types/formFields.d.ts +15 -2
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -0
- package/dist/updates/0.0.65/index.js +1 -1
- package/dist/updates/0.0.67/index.js +1 -1
- package/dist/updates/0.1.2/index.js +1 -1
- package/dist/updates/0.1.5/index.js +1 -1
- package/dist/updates/0.2.0/index.js +1 -1
- package/dist/updates/0.2.2/index.js +1 -1
- package/dist/updates/0.5.0/index.js +1 -1
- package/dist/updates/0.5.2/index.d.ts +2 -0
- package/dist/updates/0.5.2/index.js +14 -0
- package/dist/updates/0.5.3/index.d.ts +2 -0
- package/dist/updates/0.5.3/index.js +19 -0
- package/dist/updates/index.d.ts +2 -1
- package/dist/updates/index.js +3 -1
- package/package.json +2 -1
- package/dist/admin/components/fields/standalone-field-renderer.svelte +0 -148
- package/dist/admin/components/fields/standalone-field-renderer.svelte.d.ts +0 -9
- package/dist/updates/0.0.65/migration.sql +0 -55
- package/dist/updates/0.0.67/migration.sql +0 -9
package/dist/types/index.js
CHANGED
|
@@ -10,7 +10,7 @@ export const update = {
|
|
|
10
10
|
],
|
|
11
11
|
fixes: [],
|
|
12
12
|
breakingChanges: ['Media folders replaced with tags — existing folder assignments will be lost'],
|
|
13
|
-
|
|
13
|
+
sql: `-- Move publish logic from entry_version to entry
|
|
14
14
|
|
|
15
15
|
ALTER TABLE entry ADD COLUMN published_at TIMESTAMP;
|
|
16
16
|
ALTER TABLE entry ADD COLUMN published_version_id UUID
|
|
@@ -33,7 +33,7 @@ export const update = {
|
|
|
33
33
|
breakingChanges: [
|
|
34
34
|
'getImageStyles() now returns { styles, blurDataUrl } instead of plain styles record'
|
|
35
35
|
],
|
|
36
|
-
|
|
36
|
+
sql: `ALTER TABLE image_styles ADD COLUMN IF NOT EXISTS quality INTEGER;
|
|
37
37
|
ALTER TABLE media_file ADD COLUMN IF NOT EXISTS blur_data_url TEXT;
|
|
38
38
|
ALTER TABLE media_file ADD COLUMN IF NOT EXISTS focal_x REAL;
|
|
39
39
|
ALTER TABLE media_file ADD COLUMN IF NOT EXISTS focal_y REAL;`
|
|
@@ -14,5 +14,5 @@ export const update = {
|
|
|
14
14
|
'Pruning no longer deletes important versions to make room for empty ones'
|
|
15
15
|
],
|
|
16
16
|
breakingChanges: [],
|
|
17
|
-
|
|
17
|
+
notes: 'Removes duplicate entry versions where data is identical to the previous version. Preserves published, scheduled, and latest draft versions.'
|
|
18
18
|
};
|
|
@@ -7,5 +7,5 @@ export const update = {
|
|
|
7
7
|
breakingChanges: [
|
|
8
8
|
'type:"array" with objects renamed to type:"blocks". Update collection/single configs.'
|
|
9
9
|
],
|
|
10
|
-
|
|
10
|
+
notes: 'Config-only: rename type:"array" to type:"blocks" in field definitions. Stored data unchanged.'
|
|
11
11
|
};
|
|
@@ -9,5 +9,5 @@ export const update = {
|
|
|
9
9
|
],
|
|
10
10
|
fixes: [],
|
|
11
11
|
breakingChanges: [],
|
|
12
|
-
|
|
12
|
+
notes: 'No migration needed. Add type:"content" fields to collection/single configs. Existing richtext fields unchanged.'
|
|
13
13
|
};
|
|
@@ -10,5 +10,5 @@ export const update = {
|
|
|
10
10
|
],
|
|
11
11
|
fixes: [],
|
|
12
12
|
breakingChanges: [],
|
|
13
|
-
|
|
13
|
+
notes: 'No migration needed. Import `StructuredContent` from `includio/sveltekit` to render content fields.'
|
|
14
14
|
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const update = {
|
|
2
|
+
version: '0.5.2',
|
|
3
|
+
date: '2026-02-25',
|
|
4
|
+
description: 'Update system: split migration into sql + notes',
|
|
5
|
+
features: [],
|
|
6
|
+
fixes: [
|
|
7
|
+
'CmsUpdate.migration split into sql (executable SQL) and notes (manual steps) — fixes CLI crash on text descriptions',
|
|
8
|
+
'Changelog dialog: SQL accordion hidden when no SQL, notes shown as inline text',
|
|
9
|
+
'Changelog script: SQL in ```sql blocks, notes as plain text'
|
|
10
|
+
],
|
|
11
|
+
breakingChanges: [
|
|
12
|
+
'CmsUpdate interface: migration field replaced by sql + notes fields'
|
|
13
|
+
]
|
|
14
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export const update = {
|
|
2
|
+
version: '0.5.3',
|
|
3
|
+
date: '2026-03-04',
|
|
4
|
+
description: 'Form fields, inline blocks, hybrid preview, field components refactor',
|
|
5
|
+
features: [
|
|
6
|
+
'Form fields: select type, minLength/maxLength, errorMessage, remote commands',
|
|
7
|
+
'Conditional field visibility (showWhen)',
|
|
8
|
+
'Hybrid preview: device frames, container queries',
|
|
9
|
+
'TipTap placeholder extension + Notion-style styles',
|
|
10
|
+
'Server-side field resolution for inline blocks',
|
|
11
|
+
'Inline blocks: standalone form, full field rendering, collapse UI',
|
|
12
|
+
'URL field: rel attribute, external auto-detect, UI redesign',
|
|
13
|
+
'Switch UI component (bits-ui)',
|
|
14
|
+
'Boolean field: Switch toggle zamiast checkbox',
|
|
15
|
+
'Storybook stories for all field types'
|
|
16
|
+
],
|
|
17
|
+
fixes: ['Hybrid preview layout fix'],
|
|
18
|
+
breakingChanges: []
|
|
19
|
+
};
|
package/dist/updates/index.d.ts
CHANGED
|
@@ -5,7 +5,8 @@ export interface CmsUpdate {
|
|
|
5
5
|
features: string[];
|
|
6
6
|
fixes: string[];
|
|
7
7
|
breakingChanges: string[];
|
|
8
|
-
|
|
8
|
+
sql?: string;
|
|
9
|
+
notes?: string;
|
|
9
10
|
}
|
|
10
11
|
export declare const updates: CmsUpdate[];
|
|
11
12
|
export declare const getUpdatesFrom: (fromVersion: string) => CmsUpdate[];
|
package/dist/updates/index.js
CHANGED
|
@@ -13,7 +13,9 @@ import { update as update020 } from './0.2.0/index.js';
|
|
|
13
13
|
import { update as update022 } from './0.2.2/index.js';
|
|
14
14
|
import { update as update050 } from './0.5.0/index.js';
|
|
15
15
|
import { update as update051 } from './0.5.1/index.js';
|
|
16
|
-
|
|
16
|
+
import { update as update052 } from './0.5.2/index.js';
|
|
17
|
+
import { update as update053 } from './0.5.3/index.js';
|
|
18
|
+
export const updates = [update0065, update0066, update0067, update0068, update0069, update010, update011, update012, update013, update014, update015, update020, update022, update050, update051, update052, update053];
|
|
17
19
|
export const getUpdatesFrom = (fromVersion) => {
|
|
18
20
|
const fromParts = fromVersion.split('.').map(Number);
|
|
19
21
|
return updates.filter((update) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "includio-cms",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.3",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "vite dev",
|
|
6
6
|
"build": "vite build && npm run prepack",
|
|
@@ -199,6 +199,7 @@
|
|
|
199
199
|
"@tiptap/extension-highlight": "^3.17.1",
|
|
200
200
|
"@tiptap/extension-image": "^3.17.1",
|
|
201
201
|
"@tiptap/extension-link": "^3.17.1",
|
|
202
|
+
"@tiptap/extension-placeholder": "^3.20.0",
|
|
202
203
|
"@tiptap/extension-table": "^3.17.1",
|
|
203
204
|
"@tiptap/extension-table-cell": "^3.17.1",
|
|
204
205
|
"@tiptap/extension-table-header": "^3.17.1",
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { Field } from '../../../types/fields.js';
|
|
3
|
-
import Input from '../../../components/ui/input/input.svelte';
|
|
4
|
-
import { Checkbox } from '../../../components/ui/checkbox/index.js';
|
|
5
|
-
import * as Select from '../../../components/ui/select/index.js';
|
|
6
|
-
import Label from '../../../components/ui/label/label.svelte';
|
|
7
|
-
import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
|
|
8
|
-
import { getLocalizedLabel } from '../../utils/collectionLabel.js';
|
|
9
|
-
|
|
10
|
-
type Props = {
|
|
11
|
-
fields: Field[];
|
|
12
|
-
data: Record<string, unknown>;
|
|
13
|
-
onchange: (slug: string, value: unknown) => void;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
let { fields, data, onchange }: Props = $props();
|
|
17
|
-
|
|
18
|
-
const interfaceLanguage = useInterfaceLanguage();
|
|
19
|
-
|
|
20
|
-
const SUPPORTED_TYPES = new Set([
|
|
21
|
-
'text',
|
|
22
|
-
'number',
|
|
23
|
-
'boolean',
|
|
24
|
-
'select',
|
|
25
|
-
'radio',
|
|
26
|
-
'url'
|
|
27
|
-
]);
|
|
28
|
-
|
|
29
|
-
function handleInput(slug: string, e: Event) {
|
|
30
|
-
const target = e.target as HTMLInputElement;
|
|
31
|
-
onchange(slug, target.value);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function handleNumberInput(slug: string, e: Event) {
|
|
35
|
-
const target = e.target as HTMLInputElement;
|
|
36
|
-
const num = parseFloat(target.value);
|
|
37
|
-
onchange(slug, isNaN(num) ? 0 : num);
|
|
38
|
-
}
|
|
39
|
-
</script>
|
|
40
|
-
|
|
41
|
-
<div class="grid gap-3">
|
|
42
|
-
{#each fields as field}
|
|
43
|
-
{#if SUPPORTED_TYPES.has(field.type)}
|
|
44
|
-
<div class="space-y-1.5">
|
|
45
|
-
{#if field.type !== 'boolean'}
|
|
46
|
-
<Label class="text-xs font-medium">
|
|
47
|
-
{getLocalizedLabel(field.label, interfaceLanguage.current)}
|
|
48
|
-
{#if field.required}<span class="text-destructive">*</span>{/if}
|
|
49
|
-
</Label>
|
|
50
|
-
{/if}
|
|
51
|
-
|
|
52
|
-
{#if field.type === 'text'}
|
|
53
|
-
<Input
|
|
54
|
-
type="text"
|
|
55
|
-
value={String(data[field.slug] ?? '')}
|
|
56
|
-
oninput={(e) => handleInput(field.slug, e)}
|
|
57
|
-
placeholder={field.placeholder ? getLocalizedLabel(field.placeholder, interfaceLanguage.current) : ''}
|
|
58
|
-
class="h-8 text-sm"
|
|
59
|
-
/>
|
|
60
|
-
{:else if field.type === 'number'}
|
|
61
|
-
<Input
|
|
62
|
-
type="number"
|
|
63
|
-
value={String(data[field.slug] ?? 0)}
|
|
64
|
-
oninput={(e) => handleNumberInput(field.slug, e)}
|
|
65
|
-
min={field.min}
|
|
66
|
-
max={field.max}
|
|
67
|
-
step={field.step}
|
|
68
|
-
class="h-8 text-sm"
|
|
69
|
-
/>
|
|
70
|
-
{:else if field.type === 'boolean'}
|
|
71
|
-
<div class="flex items-center gap-2">
|
|
72
|
-
<Checkbox
|
|
73
|
-
checked={Boolean(data[field.slug])}
|
|
74
|
-
onCheckedChange={(checked) => onchange(field.slug, checked)}
|
|
75
|
-
/>
|
|
76
|
-
<Label class="text-xs font-medium">
|
|
77
|
-
{getLocalizedLabel(field.label, interfaceLanguage.current)}
|
|
78
|
-
</Label>
|
|
79
|
-
</div>
|
|
80
|
-
{:else if field.type === 'select' || field.type === 'radio'}
|
|
81
|
-
{@const currentValue = String(data[field.slug] ?? '')}
|
|
82
|
-
{@const currentLabel = field.options.find((o) => o.value === currentValue)}
|
|
83
|
-
<Select.Root
|
|
84
|
-
type="single"
|
|
85
|
-
value={currentValue}
|
|
86
|
-
onValueChange={(v) => onchange(field.slug, v)}
|
|
87
|
-
>
|
|
88
|
-
<Select.Trigger size="sm" class="w-full">
|
|
89
|
-
{#if currentLabel}
|
|
90
|
-
{getLocalizedLabel(currentLabel.label, interfaceLanguage.current)}
|
|
91
|
-
{:else}
|
|
92
|
-
<span class="text-muted-foreground">Wybierz...</span>
|
|
93
|
-
{/if}
|
|
94
|
-
</Select.Trigger>
|
|
95
|
-
<Select.Content>
|
|
96
|
-
{#each field.options as option}
|
|
97
|
-
<Select.Item value={option.value} label={getLocalizedLabel(option.label, interfaceLanguage.current)} />
|
|
98
|
-
{/each}
|
|
99
|
-
</Select.Content>
|
|
100
|
-
</Select.Root>
|
|
101
|
-
{:else if field.type === 'url'}
|
|
102
|
-
{@const urlData = (data[field.slug] as { url?: string; id?: string; text?: string; newTab?: boolean } | undefined) ?? { url: '' }}
|
|
103
|
-
<Input
|
|
104
|
-
type="url"
|
|
105
|
-
value={urlData.url ?? ''}
|
|
106
|
-
oninput={(e) => {
|
|
107
|
-
const target = e.target as HTMLInputElement;
|
|
108
|
-
onchange(field.slug, { ...urlData, url: target.value });
|
|
109
|
-
}}
|
|
110
|
-
placeholder={field.placeholder ? getLocalizedLabel(field.placeholder, interfaceLanguage.current) : 'https://...'}
|
|
111
|
-
class="h-8 text-sm"
|
|
112
|
-
/>
|
|
113
|
-
{#if field.text}
|
|
114
|
-
<Input
|
|
115
|
-
type="text"
|
|
116
|
-
value={urlData.text ?? ''}
|
|
117
|
-
oninput={(e) => {
|
|
118
|
-
const target = e.target as HTMLInputElement;
|
|
119
|
-
onchange(field.slug, { ...urlData, text: target.value });
|
|
120
|
-
}}
|
|
121
|
-
placeholder="Tekst linku"
|
|
122
|
-
class="h-8 text-sm mt-1"
|
|
123
|
-
/>
|
|
124
|
-
{/if}
|
|
125
|
-
{#if field.newTab}
|
|
126
|
-
<div class="flex items-center gap-2 mt-1">
|
|
127
|
-
<Checkbox
|
|
128
|
-
checked={urlData.newTab ?? false}
|
|
129
|
-
onCheckedChange={(checked) => onchange(field.slug, { ...urlData, newTab: checked })}
|
|
130
|
-
/>
|
|
131
|
-
<Label class="text-xs font-medium">Otwórz w nowej karcie</Label>
|
|
132
|
-
</div>
|
|
133
|
-
{/if}
|
|
134
|
-
{/if}
|
|
135
|
-
|
|
136
|
-
{#if field.description}
|
|
137
|
-
<p class="text-muted-foreground text-xs">
|
|
138
|
-
{getLocalizedLabel(field.description, interfaceLanguage.current)}
|
|
139
|
-
</p>
|
|
140
|
-
{/if}
|
|
141
|
-
</div>
|
|
142
|
-
{:else}
|
|
143
|
-
<div class="text-muted-foreground rounded-md border border-dashed p-2 text-center text-xs">
|
|
144
|
-
Pole „{getLocalizedLabel(field.label, interfaceLanguage.current)}" ({field.type}) nie jest obsługiwane w blokach inline
|
|
145
|
-
</div>
|
|
146
|
-
{/if}
|
|
147
|
-
{/each}
|
|
148
|
-
</div>
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { Field } from '../../../types/fields.js';
|
|
2
|
-
type Props = {
|
|
3
|
-
fields: Field[];
|
|
4
|
-
data: Record<string, unknown>;
|
|
5
|
-
onchange: (slug: string, value: unknown) => void;
|
|
6
|
-
};
|
|
7
|
-
declare const StandaloneFieldRenderer: import("svelte").Component<Props, {}, "">;
|
|
8
|
-
type StandaloneFieldRenderer = ReturnType<typeof StandaloneFieldRenderer>;
|
|
9
|
-
export default StandaloneFieldRenderer;
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
-- Move publish logic from entry_version to entry
|
|
2
|
-
|
|
3
|
-
ALTER TABLE entry ADD COLUMN published_at TIMESTAMP;
|
|
4
|
-
ALTER TABLE entry ADD COLUMN published_version_id UUID
|
|
5
|
-
REFERENCES entry_version(id) ON DELETE SET NULL;
|
|
6
|
-
ALTER TABLE entry ADD COLUMN published_by TEXT;
|
|
7
|
-
|
|
8
|
-
UPDATE entry e SET
|
|
9
|
-
published_version_id = latest.id,
|
|
10
|
-
published_at = first_pub.first_published_at,
|
|
11
|
-
published_by = latest.published_by
|
|
12
|
-
FROM (
|
|
13
|
-
SELECT DISTINCT ON (entry_id) id, entry_id, published_by
|
|
14
|
-
FROM entry_version
|
|
15
|
-
WHERE published_at IS NOT NULL AND published_at <= NOW()
|
|
16
|
-
ORDER BY entry_id, version_number DESC
|
|
17
|
-
) latest
|
|
18
|
-
JOIN (
|
|
19
|
-
SELECT entry_id, MIN(published_at) as first_published_at
|
|
20
|
-
FROM entry_version
|
|
21
|
-
WHERE published_at IS NOT NULL AND published_at <= NOW()
|
|
22
|
-
GROUP BY entry_id
|
|
23
|
-
) first_pub ON first_pub.entry_id = latest.entry_id
|
|
24
|
-
WHERE e.id = latest.entry_id;
|
|
25
|
-
|
|
26
|
-
UPDATE entry e SET
|
|
27
|
-
published_version_id = COALESCE(e.published_version_id, sub.id),
|
|
28
|
-
published_at = CASE WHEN e.published_at IS NULL THEN sub.published_at ELSE e.published_at END,
|
|
29
|
-
published_by = COALESCE(e.published_by, sub.published_by)
|
|
30
|
-
FROM (
|
|
31
|
-
SELECT DISTINCT ON (entry_id) id, entry_id, published_at, published_by
|
|
32
|
-
FROM entry_version
|
|
33
|
-
WHERE published_at IS NOT NULL AND published_at > NOW()
|
|
34
|
-
ORDER BY entry_id, published_at ASC
|
|
35
|
-
) sub
|
|
36
|
-
WHERE e.id = sub.entry_id AND e.published_version_id IS NULL;
|
|
37
|
-
|
|
38
|
-
-- Replace folder-based media with tag-based media
|
|
39
|
-
|
|
40
|
-
CREATE TABLE IF NOT EXISTS media_tag (
|
|
41
|
-
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
42
|
-
name TEXT NOT NULL UNIQUE,
|
|
43
|
-
color TEXT NOT NULL DEFAULT '#3b82f6',
|
|
44
|
-
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
CREATE TABLE IF NOT EXISTS media_file_tag (
|
|
48
|
-
file_id UUID NOT NULL REFERENCES media_file(id) ON DELETE CASCADE,
|
|
49
|
-
tag_id UUID NOT NULL REFERENCES media_tag(id) ON DELETE CASCADE,
|
|
50
|
-
PRIMARY KEY (file_id, tag_id)
|
|
51
|
-
);
|
|
52
|
-
|
|
53
|
-
ALTER TABLE media_file DROP COLUMN IF EXISTS folder_id;
|
|
54
|
-
|
|
55
|
-
DROP TABLE IF EXISTS media_folder;
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
-- Add quality control to image styles
|
|
2
|
-
ALTER TABLE image_styles ADD COLUMN IF NOT EXISTS quality INTEGER;
|
|
3
|
-
|
|
4
|
-
-- Add LQIP blur placeholder to media files
|
|
5
|
-
ALTER TABLE media_file ADD COLUMN IF NOT EXISTS blur_data_url TEXT;
|
|
6
|
-
|
|
7
|
-
-- Add focal point columns to media files
|
|
8
|
-
ALTER TABLE media_file ADD COLUMN IF NOT EXISTS focal_x REAL;
|
|
9
|
-
ALTER TABLE media_file ADD COLUMN IF NOT EXISTS focal_y REAL;
|