feat: add buttplug device recording feature (Phase 1 & 2)
Implemented complete infrastructure for recording, saving, and managing
buttplug device patterns with precise event timing.
**Phase 1: Backend & Infrastructure**
- Added Directus schema for sexy_recordings collection with all fields
(id, status, user_created, title, description, slug, duration, events,
device_info, tags, linked_video, featured, public)
- Created REST API endpoints in bundle extension:
* GET /sexy/recordings - list user recordings with filtering
* GET /sexy/recordings/:id - get single recording
* POST /sexy/recordings - create new recording with validation
* PATCH /sexy/recordings/:id - update recording (owner only)
* DELETE /sexy/recordings/:id - soft delete by archiving
- Added TypeScript types: RecordedEvent, DeviceInfo, Recording
- Created frontend services: getRecordings(), deleteRecording()
- Built RecordingCard component with stats, device info, and actions
- Added Recordings tab to /me dashboard page with grid layout
- Added i18n translations for recordings UI
**Phase 2: Recording Capture**
- Implemented recording state management in /play page
- Added Start/Stop Recording buttons with visual indicators
- Capture device events with precise timestamps during recording
- Normalize actuator values (0-100) for cross-device compatibility
- Created RecordingSaveDialog component with:
* Recording stats display (duration, events, devices)
* Form inputs (title, description, tags)
* Device information preview
- Integrated save recording API call from play page
- Added success/error toast notifications
- Automatic event filtering during recording
**Technical Details**
- Events stored as JSON array with timestamp, deviceIndex, deviceName,
actuatorIndex, actuatorType, and normalized value
- Device metadata includes name, index, and capability list
- Slug auto-generated from title for SEO-friendly URLs
- Status workflow: draft → published → archived
- Permission checks: users can only access own recordings or public ones
- Frontend uses performance.now() for millisecond precision timing
**User Flow**
1. User scans and connects devices on /play page
2. Clicks "Start Recording" to begin capturing events
3. Manipulates device sliders - all changes are recorded
4. Clicks "Stop Recording" to end capture
5. Save dialog appears with recording preview and form
6. User enters title, description, tags and saves
7. Recording appears in dashboard /me Recordings tab
8. Can play back, edit, or delete recordings
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-28 04:05:09 +01:00
|
|
|
version: 1
|
|
|
|
|
directus: 11.12.0
|
|
|
|
|
vendor: postgres
|
|
|
|
|
collections:
|
|
|
|
|
- collection: junction_directus_users_files
|
|
|
|
|
meta:
|
|
|
|
|
accountability: all
|
|
|
|
|
archive_app_filter: true
|
|
|
|
|
archive_field: null
|
|
|
|
|
archive_value: null
|
|
|
|
|
collapse: open
|
|
|
|
|
collection: junction_directus_users_files
|
|
|
|
|
color: null
|
|
|
|
|
display_template: null
|
|
|
|
|
group: null
|
|
|
|
|
hidden: true
|
|
|
|
|
icon: import_export
|
|
|
|
|
item_duplication_fields: null
|
|
|
|
|
note: null
|
|
|
|
|
preview_url: null
|
|
|
|
|
singleton: false
|
|
|
|
|
sort: null
|
|
|
|
|
sort_field: null
|
|
|
|
|
translations: null
|
|
|
|
|
unarchive_value: null
|
|
|
|
|
versioning: false
|
|
|
|
|
schema:
|
|
|
|
|
name: junction_directus_users_files
|
|
|
|
|
- collection: sexy_articles
|
|
|
|
|
meta:
|
|
|
|
|
accountability: all
|
|
|
|
|
archive_app_filter: true
|
|
|
|
|
archive_field: status
|
|
|
|
|
archive_value: archived
|
|
|
|
|
collapse: open
|
|
|
|
|
collection: sexy_articles
|
|
|
|
|
color: null
|
|
|
|
|
display_template: null
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
icon: newsmode
|
|
|
|
|
item_duplication_fields: null
|
|
|
|
|
note: null
|
|
|
|
|
preview_url: null
|
|
|
|
|
singleton: false
|
|
|
|
|
sort: null
|
|
|
|
|
sort_field: null
|
|
|
|
|
translations:
|
|
|
|
|
- language: en-US
|
|
|
|
|
plural: Articles
|
|
|
|
|
singular: Article
|
|
|
|
|
translation: Sexy Articles
|
|
|
|
|
unarchive_value: draft
|
|
|
|
|
versioning: true
|
|
|
|
|
schema:
|
|
|
|
|
name: sexy_articles
|
|
|
|
|
- collection: sexy_videos
|
|
|
|
|
meta:
|
|
|
|
|
accountability: all
|
|
|
|
|
archive_app_filter: true
|
|
|
|
|
archive_field: status
|
|
|
|
|
archive_value: archived
|
|
|
|
|
collapse: open
|
|
|
|
|
collection: sexy_videos
|
|
|
|
|
color: null
|
|
|
|
|
display_template: null
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
icon: videocam
|
|
|
|
|
item_duplication_fields: null
|
|
|
|
|
note: null
|
|
|
|
|
preview_url: null
|
|
|
|
|
singleton: false
|
|
|
|
|
sort: null
|
|
|
|
|
sort_field: null
|
|
|
|
|
translations: null
|
|
|
|
|
unarchive_value: draft
|
|
|
|
|
versioning: false
|
|
|
|
|
schema:
|
|
|
|
|
name: sexy_videos
|
|
|
|
|
- collection: sexy_videos_directus_users
|
|
|
|
|
meta:
|
|
|
|
|
accountability: all
|
|
|
|
|
archive_app_filter: true
|
|
|
|
|
archive_field: null
|
|
|
|
|
archive_value: null
|
|
|
|
|
collapse: open
|
|
|
|
|
collection: sexy_videos_directus_users
|
|
|
|
|
color: null
|
|
|
|
|
display_template: null
|
|
|
|
|
group: null
|
|
|
|
|
hidden: true
|
|
|
|
|
icon: import_export
|
|
|
|
|
item_duplication_fields: null
|
|
|
|
|
note: null
|
|
|
|
|
preview_url: null
|
|
|
|
|
singleton: false
|
|
|
|
|
sort: null
|
|
|
|
|
sort_field: null
|
|
|
|
|
translations: null
|
|
|
|
|
unarchive_value: null
|
|
|
|
|
versioning: false
|
|
|
|
|
schema:
|
|
|
|
|
name: sexy_videos_directus_users
|
|
|
|
|
- collection: sexy_recordings
|
|
|
|
|
meta:
|
|
|
|
|
accountability: all
|
|
|
|
|
archive_app_filter: true
|
|
|
|
|
archive_field: status
|
|
|
|
|
archive_value: archived
|
|
|
|
|
collapse: open
|
|
|
|
|
collection: sexy_recordings
|
|
|
|
|
color: null
|
|
|
|
|
display_template: null
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
icon: fiber_manual_record
|
|
|
|
|
item_duplication_fields: null
|
|
|
|
|
note: null
|
|
|
|
|
preview_url: null
|
|
|
|
|
singleton: false
|
|
|
|
|
sort: null
|
|
|
|
|
sort_field: null
|
|
|
|
|
translations:
|
|
|
|
|
- language: en-US
|
|
|
|
|
plural: Recordings
|
|
|
|
|
singular: Recording
|
|
|
|
|
translation: Sexy Recordings
|
|
|
|
|
unarchive_value: draft
|
|
|
|
|
versioning: false
|
|
|
|
|
schema:
|
|
|
|
|
name: sexy_recordings
|
|
|
|
|
fields:
|
|
|
|
|
- collection: directus_users
|
|
|
|
|
field: website
|
|
|
|
|
type: string
|
|
|
|
|
meta:
|
|
|
|
|
collection: directus_users
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: website
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: input
|
|
|
|
|
note: null
|
|
|
|
|
options: null
|
|
|
|
|
readonly: false
|
|
|
|
|
required: false
|
|
|
|
|
sort: 2
|
|
|
|
|
special: null
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: website
|
|
|
|
|
table: directus_users
|
|
|
|
|
data_type: character varying
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: 255
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: directus_users
|
|
|
|
|
field: slug
|
|
|
|
|
type: string
|
|
|
|
|
meta:
|
|
|
|
|
collection: directus_users
|
|
|
|
|
conditions:
|
|
|
|
|
- name: Enable for role "Administrator"
|
|
|
|
|
readonly: false
|
|
|
|
|
rule:
|
|
|
|
|
_and:
|
|
|
|
|
- role:
|
|
|
|
|
_eq: ea3a9127-2b65-462c-85a8-dbafe9b4fe24
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: slug
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: input
|
|
|
|
|
note: null
|
|
|
|
|
options: null
|
|
|
|
|
readonly: false
|
|
|
|
|
required: true
|
|
|
|
|
sort: 3
|
|
|
|
|
special: null
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: slug
|
|
|
|
|
table: directus_users
|
|
|
|
|
data_type: character varying
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: 255
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
2025-10-28 04:38:48 +01:00
|
|
|
is_nullable: true
|
feat: add buttplug device recording feature (Phase 1 & 2)
Implemented complete infrastructure for recording, saving, and managing
buttplug device patterns with precise event timing.
**Phase 1: Backend & Infrastructure**
- Added Directus schema for sexy_recordings collection with all fields
(id, status, user_created, title, description, slug, duration, events,
device_info, tags, linked_video, featured, public)
- Created REST API endpoints in bundle extension:
* GET /sexy/recordings - list user recordings with filtering
* GET /sexy/recordings/:id - get single recording
* POST /sexy/recordings - create new recording with validation
* PATCH /sexy/recordings/:id - update recording (owner only)
* DELETE /sexy/recordings/:id - soft delete by archiving
- Added TypeScript types: RecordedEvent, DeviceInfo, Recording
- Created frontend services: getRecordings(), deleteRecording()
- Built RecordingCard component with stats, device info, and actions
- Added Recordings tab to /me dashboard page with grid layout
- Added i18n translations for recordings UI
**Phase 2: Recording Capture**
- Implemented recording state management in /play page
- Added Start/Stop Recording buttons with visual indicators
- Capture device events with precise timestamps during recording
- Normalize actuator values (0-100) for cross-device compatibility
- Created RecordingSaveDialog component with:
* Recording stats display (duration, events, devices)
* Form inputs (title, description, tags)
* Device information preview
- Integrated save recording API call from play page
- Added success/error toast notifications
- Automatic event filtering during recording
**Technical Details**
- Events stored as JSON array with timestamp, deviceIndex, deviceName,
actuatorIndex, actuatorType, and normalized value
- Device metadata includes name, index, and capability list
- Slug auto-generated from title for SEO-friendly URLs
- Status workflow: draft → published → archived
- Permission checks: users can only access own recordings or public ones
- Frontend uses performance.now() for millisecond precision timing
**User Flow**
1. User scans and connects devices on /play page
2. Clicks "Start Recording" to begin capturing events
3. Manipulates device sliders - all changes are recorded
4. Clicks "Stop Recording" to end capture
5. Save dialog appears with recording preview and form
6. User enters title, description, tags and saves
7. Recording appears in dashboard /me Recordings tab
8. Can play back, edit, or delete recordings
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-28 04:05:09 +01:00
|
|
|
is_unique: true
|
|
|
|
|
is_indexed: true
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: directus_users
|
|
|
|
|
field: join_date
|
|
|
|
|
type: dateTime
|
|
|
|
|
meta:
|
|
|
|
|
collection: directus_users
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: join_date
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: datetime
|
|
|
|
|
note: null
|
|
|
|
|
options:
|
|
|
|
|
format: short
|
|
|
|
|
readonly: false
|
|
|
|
|
required: true
|
|
|
|
|
sort: 4
|
|
|
|
|
special: null
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: join_date
|
|
|
|
|
table: directus_users
|
|
|
|
|
data_type: timestamp without time zone
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: false
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: directus_users
|
|
|
|
|
field: featured
|
|
|
|
|
type: boolean
|
|
|
|
|
meta:
|
|
|
|
|
collection: directus_users
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: featured
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: boolean
|
|
|
|
|
note: null
|
|
|
|
|
options:
|
|
|
|
|
label: Featured
|
|
|
|
|
readonly: false
|
|
|
|
|
required: false
|
|
|
|
|
sort: 5
|
|
|
|
|
special:
|
|
|
|
|
- cast-boolean
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: featured
|
|
|
|
|
table: directus_users
|
|
|
|
|
data_type: boolean
|
|
|
|
|
default_value: false
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: directus_users
|
|
|
|
|
field: artist_name
|
|
|
|
|
type: string
|
|
|
|
|
meta:
|
|
|
|
|
collection: directus_users
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: artist_name
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: input
|
|
|
|
|
note: null
|
|
|
|
|
options: null
|
|
|
|
|
readonly: false
|
|
|
|
|
required: true
|
|
|
|
|
sort: 1
|
|
|
|
|
special: null
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: artist_name
|
|
|
|
|
table: directus_users
|
|
|
|
|
data_type: character varying
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: 255
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: directus_users
|
|
|
|
|
field: photos
|
|
|
|
|
type: alias
|
|
|
|
|
meta:
|
|
|
|
|
collection: directus_users
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: photos
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: files
|
|
|
|
|
note: null
|
|
|
|
|
options:
|
|
|
|
|
filter:
|
|
|
|
|
_and:
|
|
|
|
|
- type:
|
|
|
|
|
_starts_with: image
|
|
|
|
|
folder: 4cb93083-f3f7-4a61-a80f-d56fd9e6ee62
|
|
|
|
|
readonly: false
|
|
|
|
|
required: false
|
|
|
|
|
sort: 6
|
|
|
|
|
special:
|
|
|
|
|
- files
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
- collection: directus_users
|
|
|
|
|
field: banner
|
|
|
|
|
type: uuid
|
|
|
|
|
meta:
|
|
|
|
|
collection: directus_users
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: banner
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: file-image
|
|
|
|
|
note: null
|
|
|
|
|
options:
|
|
|
|
|
folder: 9fd092ff-9e7b-48f0-b26c-bcead509ba9e
|
|
|
|
|
readonly: false
|
|
|
|
|
required: false
|
|
|
|
|
sort: 7
|
|
|
|
|
special:
|
|
|
|
|
- file
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: banner
|
|
|
|
|
table: directus_users
|
|
|
|
|
data_type: uuid
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: directus_files
|
|
|
|
|
foreign_key_column: id
|
|
|
|
|
- collection: junction_directus_users_files
|
|
|
|
|
field: id
|
|
|
|
|
type: integer
|
|
|
|
|
meta:
|
|
|
|
|
collection: junction_directus_users_files
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: id
|
|
|
|
|
group: null
|
|
|
|
|
hidden: true
|
|
|
|
|
interface: null
|
|
|
|
|
note: null
|
|
|
|
|
options: null
|
|
|
|
|
readonly: false
|
|
|
|
|
required: false
|
|
|
|
|
sort: 1
|
|
|
|
|
special: null
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: id
|
|
|
|
|
table: junction_directus_users_files
|
|
|
|
|
data_type: integer
|
|
|
|
|
default_value: nextval('junction_directus_users_files_id_seq'::regclass)
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: 32
|
|
|
|
|
numeric_scale: 0
|
|
|
|
|
is_nullable: false
|
|
|
|
|
is_unique: true
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: true
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: true
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: junction_directus_users_files
|
|
|
|
|
field: directus_users_id
|
|
|
|
|
type: uuid
|
|
|
|
|
meta:
|
|
|
|
|
collection: junction_directus_users_files
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: directus_users_id
|
|
|
|
|
group: null
|
|
|
|
|
hidden: true
|
|
|
|
|
interface: null
|
|
|
|
|
note: null
|
|
|
|
|
options: null
|
|
|
|
|
readonly: false
|
|
|
|
|
required: false
|
|
|
|
|
sort: 2
|
|
|
|
|
special: null
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: directus_users_id
|
|
|
|
|
table: junction_directus_users_files
|
|
|
|
|
data_type: uuid
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: directus_users
|
|
|
|
|
foreign_key_column: id
|
|
|
|
|
- collection: junction_directus_users_files
|
|
|
|
|
field: directus_files_id
|
|
|
|
|
type: uuid
|
|
|
|
|
meta:
|
|
|
|
|
collection: junction_directus_users_files
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: directus_files_id
|
|
|
|
|
group: null
|
|
|
|
|
hidden: true
|
|
|
|
|
interface: null
|
|
|
|
|
note: null
|
|
|
|
|
options: null
|
|
|
|
|
readonly: false
|
|
|
|
|
required: false
|
|
|
|
|
sort: 3
|
|
|
|
|
special: null
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: directus_files_id
|
|
|
|
|
table: junction_directus_users_files
|
|
|
|
|
data_type: uuid
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: directus_files
|
|
|
|
|
foreign_key_column: id
|
|
|
|
|
- collection: sexy_articles
|
|
|
|
|
field: id
|
|
|
|
|
type: uuid
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_articles
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: id
|
|
|
|
|
group: null
|
|
|
|
|
hidden: true
|
|
|
|
|
interface: input
|
|
|
|
|
note: null
|
|
|
|
|
options: null
|
|
|
|
|
readonly: true
|
|
|
|
|
required: false
|
|
|
|
|
sort: 1
|
|
|
|
|
special:
|
|
|
|
|
- uuid
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: id
|
|
|
|
|
table: sexy_articles
|
|
|
|
|
data_type: uuid
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: false
|
|
|
|
|
is_unique: true
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: true
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_articles
|
|
|
|
|
field: status
|
|
|
|
|
type: string
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_articles
|
|
|
|
|
conditions: null
|
|
|
|
|
display: labels
|
|
|
|
|
display_options:
|
|
|
|
|
choices:
|
|
|
|
|
- background: var(--theme--primary-background)
|
|
|
|
|
color: var(--theme--primary)
|
|
|
|
|
foreground: var(--theme--primary)
|
|
|
|
|
text: $t:published
|
|
|
|
|
value: published
|
|
|
|
|
- background: var(--theme--background-normal)
|
|
|
|
|
color: var(--theme--foreground)
|
|
|
|
|
foreground: var(--theme--foreground)
|
|
|
|
|
text: $t:draft
|
|
|
|
|
value: draft
|
|
|
|
|
- background: var(--theme--warning-background)
|
|
|
|
|
color: var(--theme--warning)
|
|
|
|
|
foreground: var(--theme--warning)
|
|
|
|
|
text: $t:archived
|
|
|
|
|
value: archived
|
|
|
|
|
showAsDot: true
|
|
|
|
|
field: status
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: select-dropdown
|
|
|
|
|
note: null
|
|
|
|
|
options:
|
|
|
|
|
choices:
|
|
|
|
|
- color: var(--theme--primary)
|
|
|
|
|
text: $t:published
|
|
|
|
|
value: published
|
|
|
|
|
- color: var(--theme--foreground)
|
|
|
|
|
text: $t:draft
|
|
|
|
|
value: draft
|
|
|
|
|
- color: var(--theme--warning)
|
|
|
|
|
text: $t:archived
|
|
|
|
|
value: archived
|
|
|
|
|
readonly: false
|
|
|
|
|
required: false
|
|
|
|
|
sort: 2
|
|
|
|
|
special: null
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: status
|
|
|
|
|
table: sexy_articles
|
|
|
|
|
data_type: character varying
|
|
|
|
|
default_value: draft
|
|
|
|
|
max_length: 255
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: false
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_articles
|
|
|
|
|
field: user_created
|
|
|
|
|
type: uuid
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_articles
|
|
|
|
|
conditions: null
|
|
|
|
|
display: user
|
|
|
|
|
display_options: null
|
|
|
|
|
field: user_created
|
|
|
|
|
group: null
|
|
|
|
|
hidden: true
|
|
|
|
|
interface: select-dropdown-m2o
|
|
|
|
|
note: null
|
|
|
|
|
options:
|
|
|
|
|
template: '{{avatar}} {{first_name}} {{last_name}}'
|
|
|
|
|
readonly: true
|
|
|
|
|
required: false
|
|
|
|
|
sort: 3
|
|
|
|
|
special:
|
|
|
|
|
- user-created
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: half
|
|
|
|
|
schema:
|
|
|
|
|
name: user_created
|
|
|
|
|
table: sexy_articles
|
|
|
|
|
data_type: uuid
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: directus_users
|
|
|
|
|
foreign_key_column: id
|
|
|
|
|
- collection: sexy_articles
|
|
|
|
|
field: date_created
|
|
|
|
|
type: timestamp
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_articles
|
|
|
|
|
conditions: null
|
|
|
|
|
display: datetime
|
|
|
|
|
display_options:
|
|
|
|
|
relative: true
|
|
|
|
|
field: date_created
|
|
|
|
|
group: null
|
|
|
|
|
hidden: true
|
|
|
|
|
interface: datetime
|
|
|
|
|
note: null
|
|
|
|
|
options: null
|
|
|
|
|
readonly: true
|
|
|
|
|
required: false
|
|
|
|
|
sort: 4
|
|
|
|
|
special:
|
|
|
|
|
- date-created
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: half
|
|
|
|
|
schema:
|
|
|
|
|
name: date_created
|
|
|
|
|
table: sexy_articles
|
|
|
|
|
data_type: timestamp with time zone
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_articles
|
|
|
|
|
field: date_updated
|
|
|
|
|
type: timestamp
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_articles
|
|
|
|
|
conditions: null
|
|
|
|
|
display: datetime
|
|
|
|
|
display_options:
|
|
|
|
|
relative: true
|
|
|
|
|
field: date_updated
|
|
|
|
|
group: null
|
|
|
|
|
hidden: true
|
|
|
|
|
interface: datetime
|
|
|
|
|
note: null
|
|
|
|
|
options: null
|
|
|
|
|
readonly: true
|
|
|
|
|
required: false
|
|
|
|
|
sort: 5
|
|
|
|
|
special:
|
|
|
|
|
- date-updated
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: half
|
|
|
|
|
schema:
|
|
|
|
|
name: date_updated
|
|
|
|
|
table: sexy_articles
|
|
|
|
|
data_type: timestamp with time zone
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_articles
|
|
|
|
|
field: slug
|
|
|
|
|
type: string
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_articles
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: slug
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: input
|
|
|
|
|
note: null
|
|
|
|
|
options:
|
|
|
|
|
slug: true
|
|
|
|
|
readonly: false
|
|
|
|
|
required: true
|
|
|
|
|
sort: 6
|
|
|
|
|
special: null
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: slug
|
|
|
|
|
table: sexy_articles
|
|
|
|
|
data_type: character varying
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: 255
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: true
|
|
|
|
|
is_indexed: true
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_articles
|
|
|
|
|
field: title
|
|
|
|
|
type: string
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_articles
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: title
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: input
|
|
|
|
|
note: null
|
|
|
|
|
options: null
|
|
|
|
|
readonly: false
|
|
|
|
|
required: true
|
|
|
|
|
sort: 7
|
|
|
|
|
special: null
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: title
|
|
|
|
|
table: sexy_articles
|
|
|
|
|
data_type: character varying
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: 255
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_articles
|
|
|
|
|
field: excerpt
|
|
|
|
|
type: text
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_articles
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: excerpt
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: input-multiline
|
|
|
|
|
note: null
|
|
|
|
|
options:
|
|
|
|
|
trim: true
|
|
|
|
|
readonly: false
|
|
|
|
|
required: true
|
|
|
|
|
sort: 9
|
|
|
|
|
special: null
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: excerpt
|
|
|
|
|
table: sexy_articles
|
|
|
|
|
data_type: text
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_articles
|
|
|
|
|
field: content
|
|
|
|
|
type: text
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_articles
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: content
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: input-rich-text-html
|
|
|
|
|
note: null
|
|
|
|
|
options:
|
|
|
|
|
folder: c214c905-885b-4d66-a6a1-6527b0606200
|
|
|
|
|
toolbar:
|
|
|
|
|
- bold
|
|
|
|
|
- italic
|
|
|
|
|
- underline
|
|
|
|
|
- h2
|
|
|
|
|
- h3
|
|
|
|
|
- numlist
|
|
|
|
|
- bullist
|
|
|
|
|
- removeformat
|
|
|
|
|
- blockquote
|
|
|
|
|
- customLink
|
|
|
|
|
- hr
|
|
|
|
|
- fullscreen
|
|
|
|
|
- code
|
|
|
|
|
readonly: false
|
|
|
|
|
required: true
|
|
|
|
|
sort: 10
|
|
|
|
|
special: null
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: content
|
|
|
|
|
table: sexy_articles
|
|
|
|
|
data_type: text
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_articles
|
|
|
|
|
field: image
|
|
|
|
|
type: uuid
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_articles
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: image
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: file-image
|
|
|
|
|
note: null
|
|
|
|
|
options:
|
|
|
|
|
folder: 452680cc-8e19-4352-a943-21520d3f3621
|
|
|
|
|
readonly: false
|
|
|
|
|
required: true
|
|
|
|
|
sort: 11
|
|
|
|
|
special:
|
|
|
|
|
- file
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: image
|
|
|
|
|
table: sexy_articles
|
|
|
|
|
data_type: uuid
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: false
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: directus_files
|
|
|
|
|
foreign_key_column: id
|
|
|
|
|
- collection: sexy_articles
|
|
|
|
|
field: tags
|
|
|
|
|
type: json
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_articles
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: tags
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: tags
|
|
|
|
|
note: null
|
|
|
|
|
options:
|
|
|
|
|
capitalization: auto-format
|
|
|
|
|
whitespace: _
|
|
|
|
|
readonly: false
|
|
|
|
|
required: false
|
|
|
|
|
sort: 12
|
|
|
|
|
special:
|
|
|
|
|
- cast-json
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: tags
|
|
|
|
|
table: sexy_articles
|
|
|
|
|
data_type: json
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_articles
|
|
|
|
|
field: publish_date
|
|
|
|
|
type: dateTime
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_articles
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: publish_date
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: datetime
|
|
|
|
|
note: null
|
|
|
|
|
options: null
|
|
|
|
|
readonly: false
|
|
|
|
|
required: true
|
|
|
|
|
sort: 13
|
|
|
|
|
special: null
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: publish_date
|
|
|
|
|
table: sexy_articles
|
|
|
|
|
data_type: timestamp without time zone
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_articles
|
|
|
|
|
field: category
|
|
|
|
|
type: string
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_articles
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: category
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: input
|
|
|
|
|
note: null
|
|
|
|
|
options: null
|
|
|
|
|
readonly: false
|
|
|
|
|
required: true
|
|
|
|
|
sort: 14
|
|
|
|
|
special: null
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: category
|
|
|
|
|
table: sexy_articles
|
|
|
|
|
data_type: character varying
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: 255
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_articles
|
|
|
|
|
field: featured
|
|
|
|
|
type: boolean
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_articles
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: featured
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: boolean
|
|
|
|
|
note: null
|
|
|
|
|
options:
|
|
|
|
|
label: Featured
|
|
|
|
|
readonly: false
|
|
|
|
|
required: false
|
|
|
|
|
sort: 15
|
|
|
|
|
special:
|
|
|
|
|
- cast-boolean
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: featured
|
|
|
|
|
table: sexy_articles
|
|
|
|
|
data_type: boolean
|
|
|
|
|
default_value: false
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_articles
|
|
|
|
|
field: author
|
|
|
|
|
type: uuid
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_articles
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: author
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: select-dropdown-m2o
|
|
|
|
|
note: null
|
|
|
|
|
options:
|
|
|
|
|
enableLink: true
|
|
|
|
|
filter:
|
|
|
|
|
_and:
|
|
|
|
|
- policies:
|
|
|
|
|
policy:
|
|
|
|
|
name:
|
|
|
|
|
_eq: Editor
|
|
|
|
|
readonly: false
|
|
|
|
|
required: true
|
|
|
|
|
sort: 8
|
|
|
|
|
special:
|
|
|
|
|
- m2o
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: author
|
|
|
|
|
table: sexy_articles
|
|
|
|
|
data_type: uuid
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: directus_users
|
|
|
|
|
foreign_key_column: id
|
|
|
|
|
- collection: sexy_videos
|
|
|
|
|
field: id
|
|
|
|
|
type: uuid
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_videos
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: id
|
|
|
|
|
group: null
|
|
|
|
|
hidden: true
|
|
|
|
|
interface: input
|
|
|
|
|
note: null
|
|
|
|
|
options: null
|
|
|
|
|
readonly: true
|
|
|
|
|
required: false
|
|
|
|
|
sort: 1
|
|
|
|
|
special:
|
|
|
|
|
- uuid
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: id
|
|
|
|
|
table: sexy_videos
|
|
|
|
|
data_type: uuid
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: false
|
|
|
|
|
is_unique: true
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: true
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_videos
|
|
|
|
|
field: status
|
|
|
|
|
type: string
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_videos
|
|
|
|
|
conditions: null
|
|
|
|
|
display: labels
|
|
|
|
|
display_options:
|
|
|
|
|
choices:
|
|
|
|
|
- background: var(--theme--primary-background)
|
|
|
|
|
color: var(--theme--primary)
|
|
|
|
|
foreground: var(--theme--primary)
|
|
|
|
|
text: $t:published
|
|
|
|
|
value: published
|
|
|
|
|
- background: var(--theme--background-normal)
|
|
|
|
|
color: var(--theme--foreground)
|
|
|
|
|
foreground: var(--theme--foreground)
|
|
|
|
|
text: $t:draft
|
|
|
|
|
value: draft
|
|
|
|
|
- background: var(--theme--warning-background)
|
|
|
|
|
color: var(--theme--warning)
|
|
|
|
|
foreground: var(--theme--warning)
|
|
|
|
|
text: $t:archived
|
|
|
|
|
value: archived
|
|
|
|
|
showAsDot: true
|
|
|
|
|
field: status
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: select-dropdown
|
|
|
|
|
note: null
|
|
|
|
|
options:
|
|
|
|
|
choices:
|
|
|
|
|
- color: var(--theme--primary)
|
|
|
|
|
text: $t:published
|
|
|
|
|
value: published
|
|
|
|
|
- color: var(--theme--foreground)
|
|
|
|
|
text: $t:draft
|
|
|
|
|
value: draft
|
|
|
|
|
- color: var(--theme--warning)
|
|
|
|
|
text: $t:archived
|
|
|
|
|
value: archived
|
|
|
|
|
readonly: false
|
|
|
|
|
required: false
|
|
|
|
|
sort: 2
|
|
|
|
|
special: null
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: status
|
|
|
|
|
table: sexy_videos
|
|
|
|
|
data_type: character varying
|
|
|
|
|
default_value: draft
|
|
|
|
|
max_length: 255
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: false
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_videos
|
|
|
|
|
field: user_created
|
|
|
|
|
type: uuid
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_videos
|
|
|
|
|
conditions: null
|
|
|
|
|
display: user
|
|
|
|
|
display_options: null
|
|
|
|
|
field: user_created
|
|
|
|
|
group: null
|
|
|
|
|
hidden: true
|
|
|
|
|
interface: select-dropdown-m2o
|
|
|
|
|
note: null
|
|
|
|
|
options:
|
|
|
|
|
template: '{{avatar}} {{first_name}} {{last_name}}'
|
|
|
|
|
readonly: true
|
|
|
|
|
required: false
|
|
|
|
|
sort: 3
|
|
|
|
|
special:
|
|
|
|
|
- user-created
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: half
|
|
|
|
|
schema:
|
|
|
|
|
name: user_created
|
|
|
|
|
table: sexy_videos
|
|
|
|
|
data_type: uuid
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: directus_users
|
|
|
|
|
foreign_key_column: id
|
|
|
|
|
- collection: sexy_videos
|
|
|
|
|
field: date_created
|
|
|
|
|
type: timestamp
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_videos
|
|
|
|
|
conditions: null
|
|
|
|
|
display: datetime
|
|
|
|
|
display_options:
|
|
|
|
|
relative: true
|
|
|
|
|
field: date_created
|
|
|
|
|
group: null
|
|
|
|
|
hidden: true
|
|
|
|
|
interface: datetime
|
|
|
|
|
note: null
|
|
|
|
|
options: null
|
|
|
|
|
readonly: true
|
|
|
|
|
required: false
|
|
|
|
|
sort: 4
|
|
|
|
|
special:
|
|
|
|
|
- date-created
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: half
|
|
|
|
|
schema:
|
|
|
|
|
name: date_created
|
|
|
|
|
table: sexy_videos
|
|
|
|
|
data_type: timestamp with time zone
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_videos
|
|
|
|
|
field: date_updated
|
|
|
|
|
type: timestamp
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_videos
|
|
|
|
|
conditions: null
|
|
|
|
|
display: datetime
|
|
|
|
|
display_options:
|
|
|
|
|
relative: true
|
|
|
|
|
field: date_updated
|
|
|
|
|
group: null
|
|
|
|
|
hidden: true
|
|
|
|
|
interface: datetime
|
|
|
|
|
note: null
|
|
|
|
|
options: null
|
|
|
|
|
readonly: true
|
|
|
|
|
required: false
|
|
|
|
|
sort: 5
|
|
|
|
|
special:
|
|
|
|
|
- date-updated
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: half
|
|
|
|
|
schema:
|
|
|
|
|
name: date_updated
|
|
|
|
|
table: sexy_videos
|
|
|
|
|
data_type: timestamp with time zone
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_videos
|
|
|
|
|
field: slug
|
|
|
|
|
type: string
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_videos
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: slug
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: input
|
|
|
|
|
note: null
|
|
|
|
|
options:
|
|
|
|
|
slug: true
|
|
|
|
|
trim: true
|
|
|
|
|
readonly: false
|
|
|
|
|
required: true
|
|
|
|
|
sort: 6
|
|
|
|
|
special: null
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: slug
|
|
|
|
|
table: sexy_videos
|
|
|
|
|
data_type: character varying
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: 255
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_videos
|
|
|
|
|
field: title
|
|
|
|
|
type: string
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_videos
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: title
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: input
|
|
|
|
|
note: null
|
|
|
|
|
options: null
|
|
|
|
|
readonly: false
|
|
|
|
|
required: true
|
|
|
|
|
sort: 7
|
|
|
|
|
special: null
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: title
|
|
|
|
|
table: sexy_videos
|
|
|
|
|
data_type: character varying
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: 255
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_videos
|
|
|
|
|
field: image
|
|
|
|
|
type: uuid
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_videos
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: image
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: file-image
|
|
|
|
|
note: null
|
|
|
|
|
options:
|
|
|
|
|
folder: 26657630-d9cd-47a3-9e45-9831f3674f97
|
|
|
|
|
readonly: false
|
|
|
|
|
required: true
|
|
|
|
|
sort: 9
|
|
|
|
|
special:
|
|
|
|
|
- file
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: image
|
|
|
|
|
table: sexy_videos
|
|
|
|
|
data_type: uuid
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: directus_files
|
|
|
|
|
foreign_key_column: id
|
|
|
|
|
- collection: sexy_videos
|
|
|
|
|
field: upload_date
|
|
|
|
|
type: dateTime
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_videos
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: upload_date
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: datetime
|
|
|
|
|
note: null
|
|
|
|
|
options: null
|
|
|
|
|
readonly: false
|
|
|
|
|
required: true
|
|
|
|
|
sort: 12
|
|
|
|
|
special: null
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: upload_date
|
|
|
|
|
table: sexy_videos
|
|
|
|
|
data_type: timestamp without time zone
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_videos
|
|
|
|
|
field: premium
|
|
|
|
|
type: boolean
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_videos
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: premium
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: boolean
|
|
|
|
|
note: null
|
|
|
|
|
options:
|
|
|
|
|
label: Premium
|
|
|
|
|
readonly: false
|
|
|
|
|
required: false
|
|
|
|
|
sort: 13
|
|
|
|
|
special:
|
|
|
|
|
- cast-boolean
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: premium
|
|
|
|
|
table: sexy_videos
|
|
|
|
|
data_type: boolean
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_videos
|
|
|
|
|
field: featured
|
|
|
|
|
type: boolean
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_videos
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: featured
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: boolean
|
|
|
|
|
note: null
|
|
|
|
|
options:
|
|
|
|
|
label: Featured
|
|
|
|
|
readonly: false
|
|
|
|
|
required: false
|
|
|
|
|
sort: 14
|
|
|
|
|
special:
|
|
|
|
|
- cast-boolean
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: featured
|
|
|
|
|
table: sexy_videos
|
|
|
|
|
data_type: boolean
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_videos
|
|
|
|
|
field: tags
|
|
|
|
|
type: json
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_videos
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: tags
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: tags
|
|
|
|
|
note: null
|
|
|
|
|
options: null
|
|
|
|
|
readonly: false
|
|
|
|
|
required: false
|
|
|
|
|
sort: 15
|
|
|
|
|
special:
|
|
|
|
|
- cast-json
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: tags
|
|
|
|
|
table: sexy_videos
|
|
|
|
|
data_type: json
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_videos
|
|
|
|
|
field: models
|
|
|
|
|
type: alias
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_videos
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: models
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: list-m2m
|
|
|
|
|
note: null
|
|
|
|
|
options: null
|
|
|
|
|
readonly: false
|
|
|
|
|
required: true
|
|
|
|
|
sort: 11
|
|
|
|
|
special:
|
|
|
|
|
- m2m
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
- collection: sexy_videos
|
|
|
|
|
field: movie
|
|
|
|
|
type: uuid
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_videos
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: movie
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: file
|
|
|
|
|
note: null
|
|
|
|
|
options:
|
|
|
|
|
filter:
|
|
|
|
|
_and:
|
|
|
|
|
- type:
|
|
|
|
|
_eq: video/mp4
|
|
|
|
|
folder: 3f83c727-9c90-4e0d-871f-ab81c295043a
|
|
|
|
|
readonly: false
|
|
|
|
|
required: true
|
|
|
|
|
sort: 10
|
|
|
|
|
special:
|
|
|
|
|
- file
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: movie
|
|
|
|
|
table: sexy_videos
|
|
|
|
|
data_type: uuid
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: directus_files
|
|
|
|
|
foreign_key_column: id
|
|
|
|
|
- collection: sexy_videos
|
|
|
|
|
field: description
|
|
|
|
|
type: text
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_videos
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: description
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: input-multiline
|
|
|
|
|
note: null
|
|
|
|
|
options:
|
|
|
|
|
trim: true
|
|
|
|
|
readonly: false
|
|
|
|
|
required: true
|
|
|
|
|
sort: 8
|
|
|
|
|
special: null
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: description
|
|
|
|
|
table: sexy_videos
|
|
|
|
|
data_type: text
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_videos_directus_users
|
|
|
|
|
field: id
|
|
|
|
|
type: integer
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_videos_directus_users
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: id
|
|
|
|
|
group: null
|
|
|
|
|
hidden: true
|
|
|
|
|
interface: null
|
|
|
|
|
note: null
|
|
|
|
|
options: null
|
|
|
|
|
readonly: false
|
|
|
|
|
required: false
|
|
|
|
|
sort: 1
|
|
|
|
|
special: null
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: id
|
|
|
|
|
table: sexy_videos_directus_users
|
|
|
|
|
data_type: integer
|
|
|
|
|
default_value: nextval('sexy_videos_directus_users_id_seq'::regclass)
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: 32
|
|
|
|
|
numeric_scale: 0
|
|
|
|
|
is_nullable: false
|
|
|
|
|
is_unique: true
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: true
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: true
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_videos_directus_users
|
|
|
|
|
field: sexy_videos_id
|
|
|
|
|
type: uuid
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_videos_directus_users
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: sexy_videos_id
|
|
|
|
|
group: null
|
|
|
|
|
hidden: true
|
|
|
|
|
interface: null
|
|
|
|
|
note: null
|
|
|
|
|
options: null
|
|
|
|
|
readonly: false
|
|
|
|
|
required: false
|
|
|
|
|
sort: 2
|
|
|
|
|
special: null
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: sexy_videos_id
|
|
|
|
|
table: sexy_videos_directus_users
|
|
|
|
|
data_type: uuid
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: sexy_videos
|
|
|
|
|
foreign_key_column: id
|
|
|
|
|
- collection: sexy_videos_directus_users
|
|
|
|
|
field: directus_users_id
|
|
|
|
|
type: uuid
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_videos_directus_users
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: directus_users_id
|
|
|
|
|
group: null
|
|
|
|
|
hidden: true
|
|
|
|
|
interface: null
|
|
|
|
|
note: null
|
|
|
|
|
options: null
|
|
|
|
|
readonly: false
|
|
|
|
|
required: false
|
|
|
|
|
sort: 3
|
|
|
|
|
special: null
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: directus_users_id
|
|
|
|
|
table: sexy_videos_directus_users
|
|
|
|
|
data_type: uuid
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: directus_users
|
|
|
|
|
foreign_key_column: id
|
|
|
|
|
- collection: sexy_recordings
|
|
|
|
|
field: id
|
|
|
|
|
type: uuid
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_recordings
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: id
|
|
|
|
|
group: null
|
|
|
|
|
hidden: true
|
|
|
|
|
interface: input
|
|
|
|
|
note: null
|
|
|
|
|
options: null
|
|
|
|
|
readonly: true
|
|
|
|
|
required: false
|
|
|
|
|
sort: 1
|
|
|
|
|
special:
|
|
|
|
|
- uuid
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: id
|
|
|
|
|
table: sexy_recordings
|
|
|
|
|
data_type: uuid
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: false
|
|
|
|
|
is_unique: true
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: true
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_recordings
|
|
|
|
|
field: status
|
|
|
|
|
type: string
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_recordings
|
|
|
|
|
conditions: null
|
|
|
|
|
display: labels
|
|
|
|
|
display_options:
|
|
|
|
|
choices:
|
|
|
|
|
- background: var(--theme--primary-background)
|
|
|
|
|
color: var(--theme--primary)
|
|
|
|
|
foreground: var(--theme--primary)
|
|
|
|
|
text: $t:published
|
|
|
|
|
value: published
|
|
|
|
|
- background: var(--theme--background-normal)
|
|
|
|
|
color: var(--theme--foreground)
|
|
|
|
|
foreground: var(--theme--foreground)
|
|
|
|
|
text: $t:draft
|
|
|
|
|
value: draft
|
|
|
|
|
- background: var(--theme--warning-background)
|
|
|
|
|
color: var(--theme--warning)
|
|
|
|
|
foreground: var(--theme--warning)
|
|
|
|
|
text: $t:archived
|
|
|
|
|
value: archived
|
|
|
|
|
showAsDot: true
|
|
|
|
|
field: status
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: select-dropdown
|
|
|
|
|
note: null
|
|
|
|
|
options:
|
|
|
|
|
choices:
|
|
|
|
|
- color: var(--theme--primary)
|
|
|
|
|
text: $t:published
|
|
|
|
|
value: published
|
|
|
|
|
- color: var(--theme--foreground)
|
|
|
|
|
text: $t:draft
|
|
|
|
|
value: draft
|
|
|
|
|
- color: var(--theme--warning)
|
|
|
|
|
text: $t:archived
|
|
|
|
|
value: archived
|
|
|
|
|
readonly: false
|
|
|
|
|
required: false
|
|
|
|
|
sort: 2
|
|
|
|
|
special: null
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: status
|
|
|
|
|
table: sexy_recordings
|
|
|
|
|
data_type: character varying
|
|
|
|
|
default_value: draft
|
|
|
|
|
max_length: 255
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: false
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_recordings
|
|
|
|
|
field: user_created
|
|
|
|
|
type: uuid
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_recordings
|
|
|
|
|
conditions: null
|
|
|
|
|
display: user
|
|
|
|
|
display_options: null
|
|
|
|
|
field: user_created
|
|
|
|
|
group: null
|
|
|
|
|
hidden: true
|
|
|
|
|
interface: select-dropdown-m2o
|
|
|
|
|
note: null
|
|
|
|
|
options:
|
|
|
|
|
template: '{{avatar}} {{first_name}} {{last_name}}'
|
|
|
|
|
readonly: true
|
|
|
|
|
required: false
|
|
|
|
|
sort: 3
|
|
|
|
|
special:
|
|
|
|
|
- user-created
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: half
|
|
|
|
|
schema:
|
|
|
|
|
name: user_created
|
|
|
|
|
table: sexy_recordings
|
|
|
|
|
data_type: uuid
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: directus_users
|
|
|
|
|
foreign_key_column: id
|
|
|
|
|
- collection: sexy_recordings
|
|
|
|
|
field: date_created
|
|
|
|
|
type: timestamp
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_recordings
|
|
|
|
|
conditions: null
|
|
|
|
|
display: datetime
|
|
|
|
|
display_options:
|
|
|
|
|
relative: true
|
|
|
|
|
field: date_created
|
|
|
|
|
group: null
|
|
|
|
|
hidden: true
|
|
|
|
|
interface: datetime
|
|
|
|
|
note: null
|
|
|
|
|
options: null
|
|
|
|
|
readonly: true
|
|
|
|
|
required: false
|
|
|
|
|
sort: 4
|
|
|
|
|
special:
|
|
|
|
|
- date-created
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: half
|
|
|
|
|
schema:
|
|
|
|
|
name: date_created
|
|
|
|
|
table: sexy_recordings
|
|
|
|
|
data_type: timestamp with time zone
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_recordings
|
|
|
|
|
field: date_updated
|
|
|
|
|
type: timestamp
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_recordings
|
|
|
|
|
conditions: null
|
|
|
|
|
display: datetime
|
|
|
|
|
display_options:
|
|
|
|
|
relative: true
|
|
|
|
|
field: date_updated
|
|
|
|
|
group: null
|
|
|
|
|
hidden: true
|
|
|
|
|
interface: datetime
|
|
|
|
|
note: null
|
|
|
|
|
options: null
|
|
|
|
|
readonly: true
|
|
|
|
|
required: false
|
|
|
|
|
sort: 5
|
|
|
|
|
special:
|
|
|
|
|
- date-updated
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: half
|
|
|
|
|
schema:
|
|
|
|
|
name: date_updated
|
|
|
|
|
table: sexy_recordings
|
|
|
|
|
data_type: timestamp with time zone
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_recordings
|
|
|
|
|
field: title
|
|
|
|
|
type: string
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_recordings
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: title
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: input
|
|
|
|
|
note: null
|
|
|
|
|
options: null
|
|
|
|
|
readonly: false
|
|
|
|
|
required: true
|
|
|
|
|
sort: 6
|
|
|
|
|
special: null
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: title
|
|
|
|
|
table: sexy_recordings
|
|
|
|
|
data_type: character varying
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: 255
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_recordings
|
|
|
|
|
field: description
|
|
|
|
|
type: text
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_recordings
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: description
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: input-multiline
|
|
|
|
|
note: null
|
|
|
|
|
options:
|
|
|
|
|
trim: true
|
|
|
|
|
readonly: false
|
|
|
|
|
required: false
|
|
|
|
|
sort: 7
|
|
|
|
|
special: null
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: description
|
|
|
|
|
table: sexy_recordings
|
|
|
|
|
data_type: text
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_recordings
|
|
|
|
|
field: slug
|
|
|
|
|
type: string
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_recordings
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: slug
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: input
|
|
|
|
|
note: null
|
|
|
|
|
options:
|
|
|
|
|
slug: true
|
|
|
|
|
trim: true
|
|
|
|
|
readonly: false
|
|
|
|
|
required: true
|
|
|
|
|
sort: 8
|
|
|
|
|
special: null
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: slug
|
|
|
|
|
table: sexy_recordings
|
|
|
|
|
data_type: character varying
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: 255
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: false
|
|
|
|
|
is_unique: true
|
|
|
|
|
is_indexed: true
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_recordings
|
|
|
|
|
field: duration
|
2025-10-28 05:16:36 +01:00
|
|
|
type: float
|
feat: add buttplug device recording feature (Phase 1 & 2)
Implemented complete infrastructure for recording, saving, and managing
buttplug device patterns with precise event timing.
**Phase 1: Backend & Infrastructure**
- Added Directus schema for sexy_recordings collection with all fields
(id, status, user_created, title, description, slug, duration, events,
device_info, tags, linked_video, featured, public)
- Created REST API endpoints in bundle extension:
* GET /sexy/recordings - list user recordings with filtering
* GET /sexy/recordings/:id - get single recording
* POST /sexy/recordings - create new recording with validation
* PATCH /sexy/recordings/:id - update recording (owner only)
* DELETE /sexy/recordings/:id - soft delete by archiving
- Added TypeScript types: RecordedEvent, DeviceInfo, Recording
- Created frontend services: getRecordings(), deleteRecording()
- Built RecordingCard component with stats, device info, and actions
- Added Recordings tab to /me dashboard page with grid layout
- Added i18n translations for recordings UI
**Phase 2: Recording Capture**
- Implemented recording state management in /play page
- Added Start/Stop Recording buttons with visual indicators
- Capture device events with precise timestamps during recording
- Normalize actuator values (0-100) for cross-device compatibility
- Created RecordingSaveDialog component with:
* Recording stats display (duration, events, devices)
* Form inputs (title, description, tags)
* Device information preview
- Integrated save recording API call from play page
- Added success/error toast notifications
- Automatic event filtering during recording
**Technical Details**
- Events stored as JSON array with timestamp, deviceIndex, deviceName,
actuatorIndex, actuatorType, and normalized value
- Device metadata includes name, index, and capability list
- Slug auto-generated from title for SEO-friendly URLs
- Status workflow: draft → published → archived
- Permission checks: users can only access own recordings or public ones
- Frontend uses performance.now() for millisecond precision timing
**User Flow**
1. User scans and connects devices on /play page
2. Clicks "Start Recording" to begin capturing events
3. Manipulates device sliders - all changes are recorded
4. Clicks "Stop Recording" to end capture
5. Save dialog appears with recording preview and form
6. User enters title, description, tags and saves
7. Recording appears in dashboard /me Recordings tab
8. Can play back, edit, or delete recordings
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-28 04:05:09 +01:00
|
|
|
meta:
|
|
|
|
|
collection: sexy_recordings
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: duration
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: input
|
|
|
|
|
note: Duration in milliseconds
|
|
|
|
|
options: null
|
|
|
|
|
readonly: false
|
|
|
|
|
required: true
|
|
|
|
|
sort: 9
|
|
|
|
|
special: null
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: duration
|
|
|
|
|
table: sexy_recordings
|
2025-10-28 05:16:36 +01:00
|
|
|
data_type: double precision
|
feat: add buttplug device recording feature (Phase 1 & 2)
Implemented complete infrastructure for recording, saving, and managing
buttplug device patterns with precise event timing.
**Phase 1: Backend & Infrastructure**
- Added Directus schema for sexy_recordings collection with all fields
(id, status, user_created, title, description, slug, duration, events,
device_info, tags, linked_video, featured, public)
- Created REST API endpoints in bundle extension:
* GET /sexy/recordings - list user recordings with filtering
* GET /sexy/recordings/:id - get single recording
* POST /sexy/recordings - create new recording with validation
* PATCH /sexy/recordings/:id - update recording (owner only)
* DELETE /sexy/recordings/:id - soft delete by archiving
- Added TypeScript types: RecordedEvent, DeviceInfo, Recording
- Created frontend services: getRecordings(), deleteRecording()
- Built RecordingCard component with stats, device info, and actions
- Added Recordings tab to /me dashboard page with grid layout
- Added i18n translations for recordings UI
**Phase 2: Recording Capture**
- Implemented recording state management in /play page
- Added Start/Stop Recording buttons with visual indicators
- Capture device events with precise timestamps during recording
- Normalize actuator values (0-100) for cross-device compatibility
- Created RecordingSaveDialog component with:
* Recording stats display (duration, events, devices)
* Form inputs (title, description, tags)
* Device information preview
- Integrated save recording API call from play page
- Added success/error toast notifications
- Automatic event filtering during recording
**Technical Details**
- Events stored as JSON array with timestamp, deviceIndex, deviceName,
actuatorIndex, actuatorType, and normalized value
- Device metadata includes name, index, and capability list
- Slug auto-generated from title for SEO-friendly URLs
- Status workflow: draft → published → archived
- Permission checks: users can only access own recordings or public ones
- Frontend uses performance.now() for millisecond precision timing
**User Flow**
1. User scans and connects devices on /play page
2. Clicks "Start Recording" to begin capturing events
3. Manipulates device sliders - all changes are recorded
4. Clicks "Stop Recording" to end capture
5. Save dialog appears with recording preview and form
6. User enters title, description, tags and saves
7. Recording appears in dashboard /me Recordings tab
8. Can play back, edit, or delete recordings
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-28 04:05:09 +01:00
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
2025-10-28 05:16:36 +01:00
|
|
|
numeric_precision: 53
|
|
|
|
|
numeric_scale: null
|
feat: add buttplug device recording feature (Phase 1 & 2)
Implemented complete infrastructure for recording, saving, and managing
buttplug device patterns with precise event timing.
**Phase 1: Backend & Infrastructure**
- Added Directus schema for sexy_recordings collection with all fields
(id, status, user_created, title, description, slug, duration, events,
device_info, tags, linked_video, featured, public)
- Created REST API endpoints in bundle extension:
* GET /sexy/recordings - list user recordings with filtering
* GET /sexy/recordings/:id - get single recording
* POST /sexy/recordings - create new recording with validation
* PATCH /sexy/recordings/:id - update recording (owner only)
* DELETE /sexy/recordings/:id - soft delete by archiving
- Added TypeScript types: RecordedEvent, DeviceInfo, Recording
- Created frontend services: getRecordings(), deleteRecording()
- Built RecordingCard component with stats, device info, and actions
- Added Recordings tab to /me dashboard page with grid layout
- Added i18n translations for recordings UI
**Phase 2: Recording Capture**
- Implemented recording state management in /play page
- Added Start/Stop Recording buttons with visual indicators
- Capture device events with precise timestamps during recording
- Normalize actuator values (0-100) for cross-device compatibility
- Created RecordingSaveDialog component with:
* Recording stats display (duration, events, devices)
* Form inputs (title, description, tags)
* Device information preview
- Integrated save recording API call from play page
- Added success/error toast notifications
- Automatic event filtering during recording
**Technical Details**
- Events stored as JSON array with timestamp, deviceIndex, deviceName,
actuatorIndex, actuatorType, and normalized value
- Device metadata includes name, index, and capability list
- Slug auto-generated from title for SEO-friendly URLs
- Status workflow: draft → published → archived
- Permission checks: users can only access own recordings or public ones
- Frontend uses performance.now() for millisecond precision timing
**User Flow**
1. User scans and connects devices on /play page
2. Clicks "Start Recording" to begin capturing events
3. Manipulates device sliders - all changes are recorded
4. Clicks "Stop Recording" to end capture
5. Save dialog appears with recording preview and form
6. User enters title, description, tags and saves
7. Recording appears in dashboard /me Recordings tab
8. Can play back, edit, or delete recordings
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-28 04:05:09 +01:00
|
|
|
is_nullable: false
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_recordings
|
|
|
|
|
field: events
|
|
|
|
|
type: json
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_recordings
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: events
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: input-code
|
|
|
|
|
note: Array of recorded events with timestamps
|
|
|
|
|
options:
|
|
|
|
|
language: json
|
|
|
|
|
readonly: false
|
|
|
|
|
required: true
|
|
|
|
|
sort: 10
|
|
|
|
|
special:
|
|
|
|
|
- cast-json
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: events
|
|
|
|
|
table: sexy_recordings
|
|
|
|
|
data_type: json
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: false
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_recordings
|
|
|
|
|
field: device_info
|
|
|
|
|
type: json
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_recordings
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: device_info
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: input-code
|
|
|
|
|
note: Array of device metadata
|
|
|
|
|
options:
|
|
|
|
|
language: json
|
|
|
|
|
readonly: false
|
|
|
|
|
required: true
|
|
|
|
|
sort: 11
|
|
|
|
|
special:
|
|
|
|
|
- cast-json
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: device_info
|
|
|
|
|
table: sexy_recordings
|
|
|
|
|
data_type: json
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: false
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_recordings
|
|
|
|
|
field: tags
|
|
|
|
|
type: json
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_recordings
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: tags
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: tags
|
|
|
|
|
note: null
|
|
|
|
|
options: null
|
|
|
|
|
readonly: false
|
|
|
|
|
required: false
|
|
|
|
|
sort: 12
|
|
|
|
|
special:
|
|
|
|
|
- cast-json
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: tags
|
|
|
|
|
table: sexy_recordings
|
|
|
|
|
data_type: json
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_recordings
|
|
|
|
|
field: linked_video
|
|
|
|
|
type: uuid
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_recordings
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: linked_video
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: select-dropdown-m2o
|
|
|
|
|
note: null
|
|
|
|
|
options:
|
|
|
|
|
enableLink: true
|
|
|
|
|
readonly: false
|
|
|
|
|
required: false
|
|
|
|
|
sort: 13
|
|
|
|
|
special:
|
|
|
|
|
- m2o
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: linked_video
|
|
|
|
|
table: sexy_recordings
|
|
|
|
|
data_type: uuid
|
|
|
|
|
default_value: null
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: sexy_videos
|
|
|
|
|
foreign_key_column: id
|
|
|
|
|
- collection: sexy_recordings
|
|
|
|
|
field: featured
|
|
|
|
|
type: boolean
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_recordings
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: featured
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: boolean
|
|
|
|
|
note: null
|
|
|
|
|
options:
|
|
|
|
|
label: Featured
|
|
|
|
|
readonly: false
|
|
|
|
|
required: false
|
|
|
|
|
sort: 14
|
|
|
|
|
special:
|
|
|
|
|
- cast-boolean
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: featured
|
|
|
|
|
table: sexy_recordings
|
|
|
|
|
data_type: boolean
|
|
|
|
|
default_value: false
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
- collection: sexy_recordings
|
|
|
|
|
field: public
|
|
|
|
|
type: boolean
|
|
|
|
|
meta:
|
|
|
|
|
collection: sexy_recordings
|
|
|
|
|
conditions: null
|
|
|
|
|
display: null
|
|
|
|
|
display_options: null
|
|
|
|
|
field: public
|
|
|
|
|
group: null
|
|
|
|
|
hidden: false
|
|
|
|
|
interface: boolean
|
|
|
|
|
note: null
|
|
|
|
|
options:
|
|
|
|
|
label: Public
|
|
|
|
|
readonly: false
|
|
|
|
|
required: false
|
|
|
|
|
sort: 15
|
|
|
|
|
special:
|
|
|
|
|
- cast-boolean
|
|
|
|
|
translations: null
|
|
|
|
|
validation: null
|
|
|
|
|
validation_message: null
|
|
|
|
|
width: full
|
|
|
|
|
schema:
|
|
|
|
|
name: public
|
|
|
|
|
table: sexy_recordings
|
|
|
|
|
data_type: boolean
|
|
|
|
|
default_value: false
|
|
|
|
|
max_length: null
|
|
|
|
|
numeric_precision: null
|
|
|
|
|
numeric_scale: null
|
|
|
|
|
is_nullable: true
|
|
|
|
|
is_unique: false
|
|
|
|
|
is_indexed: false
|
|
|
|
|
is_primary_key: false
|
|
|
|
|
is_generated: false
|
|
|
|
|
generation_expression: null
|
|
|
|
|
has_auto_increment: false
|
|
|
|
|
foreign_key_table: null
|
|
|
|
|
foreign_key_column: null
|
|
|
|
|
relations:
|
|
|
|
|
- collection: directus_users
|
|
|
|
|
field: banner
|
|
|
|
|
related_collection: directus_files
|
|
|
|
|
meta:
|
|
|
|
|
junction_field: null
|
|
|
|
|
many_collection: directus_users
|
|
|
|
|
many_field: banner
|
|
|
|
|
one_allowed_collections: null
|
|
|
|
|
one_collection: directus_files
|
|
|
|
|
one_collection_field: null
|
|
|
|
|
one_deselect_action: nullify
|
|
|
|
|
one_field: null
|
|
|
|
|
sort_field: null
|
|
|
|
|
schema:
|
|
|
|
|
table: directus_users
|
|
|
|
|
column: banner
|
|
|
|
|
foreign_key_table: directus_files
|
|
|
|
|
foreign_key_column: id
|
|
|
|
|
constraint_name: directus_users_banner_foreign
|
|
|
|
|
on_update: NO ACTION
|
|
|
|
|
on_delete: SET NULL
|
|
|
|
|
- collection: junction_directus_users_files
|
|
|
|
|
field: directus_files_id
|
|
|
|
|
related_collection: directus_files
|
|
|
|
|
meta:
|
|
|
|
|
junction_field: directus_users_id
|
|
|
|
|
many_collection: junction_directus_users_files
|
|
|
|
|
many_field: directus_files_id
|
|
|
|
|
one_allowed_collections: null
|
|
|
|
|
one_collection: directus_files
|
|
|
|
|
one_collection_field: null
|
|
|
|
|
one_deselect_action: nullify
|
|
|
|
|
one_field: null
|
|
|
|
|
sort_field: null
|
|
|
|
|
schema:
|
|
|
|
|
table: junction_directus_users_files
|
|
|
|
|
column: directus_files_id
|
|
|
|
|
foreign_key_table: directus_files
|
|
|
|
|
foreign_key_column: id
|
|
|
|
|
constraint_name: junction_directus_users_files_directus_files_id_foreign
|
|
|
|
|
on_update: NO ACTION
|
|
|
|
|
on_delete: SET NULL
|
|
|
|
|
- collection: junction_directus_users_files
|
|
|
|
|
field: directus_users_id
|
|
|
|
|
related_collection: directus_users
|
|
|
|
|
meta:
|
|
|
|
|
junction_field: directus_files_id
|
|
|
|
|
many_collection: junction_directus_users_files
|
|
|
|
|
many_field: directus_users_id
|
|
|
|
|
one_allowed_collections: null
|
|
|
|
|
one_collection: directus_users
|
|
|
|
|
one_collection_field: null
|
|
|
|
|
one_deselect_action: nullify
|
|
|
|
|
one_field: photos
|
|
|
|
|
sort_field: null
|
|
|
|
|
schema:
|
|
|
|
|
table: junction_directus_users_files
|
|
|
|
|
column: directus_users_id
|
|
|
|
|
foreign_key_table: directus_users
|
|
|
|
|
foreign_key_column: id
|
|
|
|
|
constraint_name: junction_directus_users_files_directus_users_id_foreign
|
|
|
|
|
on_update: NO ACTION
|
|
|
|
|
on_delete: SET NULL
|
|
|
|
|
- collection: sexy_articles
|
|
|
|
|
field: user_created
|
|
|
|
|
related_collection: directus_users
|
|
|
|
|
meta:
|
|
|
|
|
junction_field: null
|
|
|
|
|
many_collection: sexy_articles
|
|
|
|
|
many_field: user_created
|
|
|
|
|
one_allowed_collections: null
|
|
|
|
|
one_collection: directus_users
|
|
|
|
|
one_collection_field: null
|
|
|
|
|
one_deselect_action: nullify
|
|
|
|
|
one_field: null
|
|
|
|
|
sort_field: null
|
|
|
|
|
schema:
|
|
|
|
|
table: sexy_articles
|
|
|
|
|
column: user_created
|
|
|
|
|
foreign_key_table: directus_users
|
|
|
|
|
foreign_key_column: id
|
|
|
|
|
constraint_name: sexy_articles_user_created_foreign
|
|
|
|
|
on_update: NO ACTION
|
|
|
|
|
on_delete: NO ACTION
|
|
|
|
|
- collection: sexy_articles
|
|
|
|
|
field: image
|
|
|
|
|
related_collection: directus_files
|
|
|
|
|
meta:
|
|
|
|
|
junction_field: null
|
|
|
|
|
many_collection: sexy_articles
|
|
|
|
|
many_field: image
|
|
|
|
|
one_allowed_collections: null
|
|
|
|
|
one_collection: directus_files
|
|
|
|
|
one_collection_field: null
|
|
|
|
|
one_deselect_action: nullify
|
|
|
|
|
one_field: null
|
|
|
|
|
sort_field: null
|
|
|
|
|
schema:
|
|
|
|
|
table: sexy_articles
|
|
|
|
|
column: image
|
|
|
|
|
foreign_key_table: directus_files
|
|
|
|
|
foreign_key_column: id
|
|
|
|
|
constraint_name: sexy_articles_image_foreign
|
|
|
|
|
on_update: NO ACTION
|
|
|
|
|
on_delete: NO ACTION
|
|
|
|
|
- collection: sexy_articles
|
|
|
|
|
field: author
|
|
|
|
|
related_collection: directus_users
|
|
|
|
|
meta:
|
|
|
|
|
junction_field: null
|
|
|
|
|
many_collection: sexy_articles
|
|
|
|
|
many_field: author
|
|
|
|
|
one_allowed_collections: null
|
|
|
|
|
one_collection: directus_users
|
|
|
|
|
one_collection_field: null
|
|
|
|
|
one_deselect_action: nullify
|
|
|
|
|
one_field: null
|
|
|
|
|
sort_field: null
|
|
|
|
|
schema:
|
|
|
|
|
table: sexy_articles
|
|
|
|
|
column: author
|
|
|
|
|
foreign_key_table: directus_users
|
|
|
|
|
foreign_key_column: id
|
|
|
|
|
constraint_name: sexy_articles_author_foreign
|
|
|
|
|
on_update: NO ACTION
|
|
|
|
|
on_delete: SET NULL
|
|
|
|
|
- collection: sexy_videos
|
|
|
|
|
field: user_created
|
|
|
|
|
related_collection: directus_users
|
|
|
|
|
meta:
|
|
|
|
|
junction_field: null
|
|
|
|
|
many_collection: sexy_videos
|
|
|
|
|
many_field: user_created
|
|
|
|
|
one_allowed_collections: null
|
|
|
|
|
one_collection: directus_users
|
|
|
|
|
one_collection_field: null
|
|
|
|
|
one_deselect_action: nullify
|
|
|
|
|
one_field: null
|
|
|
|
|
sort_field: null
|
|
|
|
|
schema:
|
|
|
|
|
table: sexy_videos
|
|
|
|
|
column: user_created
|
|
|
|
|
foreign_key_table: directus_users
|
|
|
|
|
foreign_key_column: id
|
|
|
|
|
constraint_name: sexy_videos_user_created_foreign
|
|
|
|
|
on_update: NO ACTION
|
|
|
|
|
on_delete: NO ACTION
|
|
|
|
|
- collection: sexy_videos
|
|
|
|
|
field: image
|
|
|
|
|
related_collection: directus_files
|
|
|
|
|
meta:
|
|
|
|
|
junction_field: null
|
|
|
|
|
many_collection: sexy_videos
|
|
|
|
|
many_field: image
|
|
|
|
|
one_allowed_collections: null
|
|
|
|
|
one_collection: directus_files
|
|
|
|
|
one_collection_field: null
|
|
|
|
|
one_deselect_action: nullify
|
|
|
|
|
one_field: null
|
|
|
|
|
sort_field: null
|
|
|
|
|
schema:
|
|
|
|
|
table: sexy_videos
|
|
|
|
|
column: image
|
|
|
|
|
foreign_key_table: directus_files
|
|
|
|
|
foreign_key_column: id
|
|
|
|
|
constraint_name: sexy_videos_image_foreign
|
|
|
|
|
on_update: NO ACTION
|
|
|
|
|
on_delete: SET NULL
|
|
|
|
|
- collection: sexy_videos
|
|
|
|
|
field: movie
|
|
|
|
|
related_collection: directus_files
|
|
|
|
|
meta:
|
|
|
|
|
junction_field: null
|
|
|
|
|
many_collection: sexy_videos
|
|
|
|
|
many_field: movie
|
|
|
|
|
one_allowed_collections: null
|
|
|
|
|
one_collection: directus_files
|
|
|
|
|
one_collection_field: null
|
|
|
|
|
one_deselect_action: nullify
|
|
|
|
|
one_field: null
|
|
|
|
|
sort_field: null
|
|
|
|
|
schema:
|
|
|
|
|
table: sexy_videos
|
|
|
|
|
column: movie
|
|
|
|
|
foreign_key_table: directus_files
|
|
|
|
|
foreign_key_column: id
|
|
|
|
|
constraint_name: sexy_videos_movie_foreign
|
|
|
|
|
on_update: NO ACTION
|
|
|
|
|
on_delete: SET NULL
|
|
|
|
|
- collection: sexy_videos_directus_users
|
|
|
|
|
field: directus_users_id
|
|
|
|
|
related_collection: directus_users
|
|
|
|
|
meta:
|
|
|
|
|
junction_field: sexy_videos_id
|
|
|
|
|
many_collection: sexy_videos_directus_users
|
|
|
|
|
many_field: directus_users_id
|
|
|
|
|
one_allowed_collections: null
|
|
|
|
|
one_collection: directus_users
|
|
|
|
|
one_collection_field: null
|
|
|
|
|
one_deselect_action: nullify
|
|
|
|
|
one_field: null
|
|
|
|
|
sort_field: null
|
|
|
|
|
schema:
|
|
|
|
|
table: sexy_videos_directus_users
|
|
|
|
|
column: directus_users_id
|
|
|
|
|
foreign_key_table: directus_users
|
|
|
|
|
foreign_key_column: id
|
|
|
|
|
constraint_name: sexy_videos_directus_users_directus_users_id_foreign
|
|
|
|
|
on_update: NO ACTION
|
|
|
|
|
on_delete: SET NULL
|
|
|
|
|
- collection: sexy_videos_directus_users
|
|
|
|
|
field: sexy_videos_id
|
|
|
|
|
related_collection: sexy_videos
|
|
|
|
|
meta:
|
|
|
|
|
junction_field: directus_users_id
|
|
|
|
|
many_collection: sexy_videos_directus_users
|
|
|
|
|
many_field: sexy_videos_id
|
|
|
|
|
one_allowed_collections: null
|
|
|
|
|
one_collection: sexy_videos
|
|
|
|
|
one_collection_field: null
|
|
|
|
|
one_deselect_action: nullify
|
|
|
|
|
one_field: models
|
|
|
|
|
sort_field: null
|
|
|
|
|
schema:
|
|
|
|
|
table: sexy_videos_directus_users
|
|
|
|
|
column: sexy_videos_id
|
|
|
|
|
foreign_key_table: sexy_videos
|
|
|
|
|
foreign_key_column: id
|
|
|
|
|
constraint_name: sexy_videos_directus_users_sexy_videos_id_foreign
|
|
|
|
|
on_update: NO ACTION
|
|
|
|
|
on_delete: SET NULL
|
|
|
|
|
- collection: sexy_recordings
|
|
|
|
|
field: user_created
|
|
|
|
|
related_collection: directus_users
|
|
|
|
|
meta:
|
|
|
|
|
junction_field: null
|
|
|
|
|
many_collection: sexy_recordings
|
|
|
|
|
many_field: user_created
|
|
|
|
|
one_allowed_collections: null
|
|
|
|
|
one_collection: directus_users
|
|
|
|
|
one_collection_field: null
|
|
|
|
|
one_deselect_action: nullify
|
|
|
|
|
one_field: null
|
|
|
|
|
sort_field: null
|
|
|
|
|
schema:
|
|
|
|
|
table: sexy_recordings
|
|
|
|
|
column: user_created
|
|
|
|
|
foreign_key_table: directus_users
|
|
|
|
|
foreign_key_column: id
|
|
|
|
|
constraint_name: sexy_recordings_user_created_foreign
|
|
|
|
|
on_update: NO ACTION
|
|
|
|
|
on_delete: NO ACTION
|
|
|
|
|
- collection: sexy_recordings
|
|
|
|
|
field: linked_video
|
|
|
|
|
related_collection: sexy_videos
|
|
|
|
|
meta:
|
|
|
|
|
junction_field: null
|
|
|
|
|
many_collection: sexy_recordings
|
|
|
|
|
many_field: linked_video
|
|
|
|
|
one_allowed_collections: null
|
|
|
|
|
one_collection: sexy_videos
|
|
|
|
|
one_collection_field: null
|
|
|
|
|
one_deselect_action: nullify
|
|
|
|
|
one_field: null
|
|
|
|
|
sort_field: null
|
|
|
|
|
schema:
|
|
|
|
|
table: sexy_recordings
|
|
|
|
|
column: linked_video
|
|
|
|
|
foreign_key_table: sexy_videos
|
|
|
|
|
foreign_key_column: id
|
|
|
|
|
constraint_name: sexy_recordings_linked_video_foreign
|
|
|
|
|
on_update: NO ACTION
|
|
|
|
|
on_delete: SET NULL
|