import { Acl } from './acl'; import { LimeType } from './limetype'; import { LimeObjectValue } from '../limeobject/limeobject'; /** * Represents a property definition on a {@link LimeType}. * * A {@link LimeProperty} describes a single field on a business object, including * its data type, display metadata, and optionally its relationship to other types. * Properties can be simple values (strings, numbers) or complex relations to other objects. * * @example Reading property metadata * ```ts * import { PlatformServiceName } from '@limetech/lime-web-components'; * * const repository = platform.get(PlatformServiceName.LimeTypeRepository); * const nameProperty = repository.getLimeType('person')?.getProperty('name'); * * console.log(nameProperty?.type); // 'string' * console.log(nameProperty?.required); // true * console.log(nameProperty?.localname); // 'Name' * * if (nameProperty?.acl.update) { * console.log('User can edit this property'); * } * ``` * * @public * @group Lime types */ export interface LimeProperty { /** * Access control list for this property. * Determines what operations (read, write, delete, update) are allowed on * this property. See {@link Acl} for details on permission structure. */ acl: Acl; /** * The schema-defined default value for this property when creating a new * limeobject. The runtime type matches the property's {@link PropertyType} * (see {@link LimeObjectValue}). * * An `option` property is the exception: its default is the full * {@link Option}, not the key string a stored option value holds. */ defaultvalue?: LimeObjectValue | Option; fieldorder: number; has_sql?: boolean; /** * Label marking this property for a specific system usage. * * A property's `name` can be anything a schema defines, so `label` is how * the system recognizes a property's special-purpose role independent of * its name, e.g. a property named `email` might carry the label * `primaryemailaddress`. There are many such labels, defined by Lime CRM * or by the installation's configuration; most properties have none. * * Use `localname` for display purposes. */ label: string; /** * Maximum length for string-based properties. * Only applicable to string, text, phone, and link types. */ length?: number; /** * Localized display name of the property for the current user's language. * Use this value when displaying the property name in the UI. */ localname: string; /** * Internal name of the property (e.g., 'name', 'phone', 'company'). * This is the identifier used in API calls and code. */ name: string; /** * Indicates whether this property is required. * When true, objects cannot be saved without a value for this property. */ required: boolean; /** * The data type of this property. * Determines how values are stored, validated, and displayed. * See {@link PropertyType} for all available types. */ type: PropertyType; /** * List of predefined options for 'option' or 'set' type properties. * Represents dropdown/select values that users can choose from. * * @example Building the list of selectable options * ```ts * import { PlatformServiceName } from '@limetech/lime-web-components'; * * const repository = platform.get(PlatformServiceName.LimeTypeRepository); * const statusProperty = repository.getLimeType('deal')?.getProperty('status'); * * // Inactive options stay out of a dropdown for new selections * const activeOptions = * statusProperty?.options?.filter((option) => !option.inactive) ?? []; * * for (const option of activeOptions) { * // `key` is the stored value, `text` is what the user reads * console.log(option.key, option.text); * } * ``` */ options?: Option[]; /** * Relation metadata for property types that link to other {@link LimeType | LimeTypes}. * Only present when type is 'hasone', 'hasmany', 'belongsto', or 'hasandbelongstomany'. * * @example Getting the related limetype and the back-reference * ```ts * import { PlatformServiceName } from '@limetech/lime-web-components'; * * const repository = platform.get(PlatformServiceName.LimeTypeRepository); * const companyProperty = repository.getLimeType('deal')?.getProperty('company'); * * if (companyProperty?.relation) { * const companyType = companyProperty.relation.getLimetype(); * console.log('Deals relate to:', companyType.name); * * // The inverse relationship * const dealsProperty = companyProperty.relation.getBackreference(); * console.log('Back-reference:', dealsProperty.name); // e.g., 'deals' * } * ``` */ relation?: { /** * Get the {@link LimeType} that this property relates to. * @returns The related {@link LimeType} definition */ getLimetype: () => LimeType; /** * Get the property on the related {@link LimeType} that points back to this type. * For example, if a deal has a 'company' property, the back-reference would be * the 'deals' property on the company type. * @returns The back-reference {@link LimeProperty} on the related type */ getBackreference: () => LimeProperty; }; } /** * Represents a selectable option in an 'option' or 'set' type property. * * Options are used for dropdown lists, radio buttons, and multi-select fields. * Each option has a key (the stored value), text (the displayed text), and * an active/inactive state. * * @example Listing the options a user can still pick * ```ts * import { PlatformServiceName } from '@limetech/lime-web-components'; * * const repository = platform.get(PlatformServiceName.LimeTypeRepository); * const statusProperty = repository.getLimeType('deal')?.getProperty('status'); * * // Inactive options stay out of a dropdown for new selections * const activeOptions = * statusProperty?.options?.filter((option) => !option.inactive) ?? []; * * for (const option of activeOptions) { * // `key` is the stored value, `text` is what the user reads * console.log(option.key, option.text); * } * ``` * * @public * @group Lime types */ export interface Option { /** * The value that gets stored in the database. * This is the identifier used in code and API calls. */ key: string; /** * Whether this option is inactive/disabled. * Inactive options should not be shown in dropdowns for new selections, * but may still appear when displaying existing data. */ inactive: boolean; /** * The user-facing text displayed for this option. * This is localized based on the current user's language. */ text: string; /** * Display order of this option in lists. * Lower numbers appear first. */ order?: number; /** * Internal database ID of this option. * Usually not needed in application code. */ id?: number; } /** * The subset of {@link PropertyType} values that represent date or time values. * * IMPORTANT NAMING CAVEAT: * The naming of time-related types is counterintuitive for historical reasons: * - `time` = Date AND time (full datetime/timestamp) * - `timeofday` = A time of day. The value is still returned as a full ISO * 8601 datetime string, not a bare time string; only the time portion is * meaningful, the date portion should be ignored. * * Additional notes: * - There is no dedicated "week" type. Week properties use the `time` type * and are configured as "week" in the view configuration * - All date/time values are typically stored as ISO 8601 strings * * @example Telling the date and time types apart * ```ts * import { PlatformServiceName, isDate } from '@limetech/lime-web-components'; * * const repository = platform.get(PlatformServiceName.LimeTypeRepository); * const property = repository.getLimeType('deal')?.getProperty('created'); * * if (property && isDate(property)) { * if (property.type === 'time') { * // Full datetime, e.g. "2024-03-15T14:30:00Z" * console.log('This is a datetime field'); * } else if (property.type === 'timeofday') { * // Still a full ISO string, only the time part is meaningful * console.log('This is a time-only field'); * } else if (property.type === 'date') { * // Date only, e.g. "2024-03-15" * console.log('This is a date-only field'); * } * } * ``` * * @public * @group Lime types */ export type DateTimePropertyType = 'time' | 'timeofday' | 'date' | 'year' | 'quarter' | 'month'; /** * All available property types in the Lime CRM system. * * Property types determine how data is stored, validated, and displayed. * They fall into several categories: * * Simple Values: * - `string` - Short text (up to 255 characters typically) * - `text` - Long text (unlimited length) * - `phone` - Phone number * - `link` - URL/hyperlink * - `integer` - Whole number * - `decimal` - Decimal number with fractional part * - `percent` - Percentage value (stored as decimal) * - `yesno` - Boolean value (true/false) * * Selection Types: * - `option` - Single selection from predefined list (dropdown) * - `set` - Multiple selections from predefined list (multi-select) * - `user` - Reference to a Lime user * * Relation Types (link to other LimeTypes): * - `belongsto` - Many-to-one relationship (e.g., deal belongs to one company) * - `hasone` - One-to-one relationship (e.g., person has one main address) * - `hasmany` - One-to-many relationship (e.g., company has many deals) * - `hasandbelongstomany` - Many-to-many relationship (e.g., deal has many participants) * * Other Types: * - `file` - File attachment * - `xml` - XML data * - `system` - System-managed property (usually read-only) * * Date/Time Types: See DateTimePropertyType * * @example Checking what category a property belongs to * ```ts * import { * PlatformServiceName, * isDate, * isRelation, * isSingleRelation, * isString, * } from '@limetech/lime-web-components'; * * const repository = platform.get(PlatformServiceName.LimeTypeRepository); * const property = repository.getLimeType('deal')?.getProperty('company'); * * if (property && isRelation(property)) { * console.log('This property links to another type'); * const relatedType = property.relation?.getLimetype(); * * if (isSingleRelation(property)) { * console.log('This is a single-object relation (belongsto or hasone)'); * } else { * console.log('This is a multi-object relation (hasmany or habtm)'); * } * } * * if (property && isDate(property)) { * console.log('This property stores date/time information'); * } * * if (property && isString(property)) { * console.log('This property stores text'); * console.log('Max length:', property.length); * } * ``` * * @example Formatting a property value for display * ```ts * import type { * LimeObjectValue, * LimeProperty, * } from '@limetech/lime-web-components'; * * function formatPropertyValue( * property: LimeProperty, * value: LimeObjectValue * ): string { * switch (property.type) { * case 'string': * case 'text': * case 'phone': * case 'link': { * return String(value); * } * * case 'integer': * case 'decimal': { * return Number(value).toLocaleString(); * } * * case 'percent': { * return `${(Number(value) * 100).toFixed(2)}%`; * } * * case 'yesno': { * return value ? 'Yes' : 'No'; * } * * case 'option': { * const option = property.options?.find((opt) => opt.key === value); * * return option?.text ?? ''; * } * * case 'time': * case 'date': { * return new Date(String(value)).toLocaleString(); * } * * default: { * return JSON.stringify(value); * } * } * } * ``` * * @public * @group Lime types */ export type PropertyType = 'string' | 'text' | 'phone' | 'integer' | 'decimal' | 'percent' | 'yesno' | 'link' | 'user' | 'xml' | 'option' | 'set' | 'file' | 'hasone' | 'hasmany' | 'belongsto' | 'hasandbelongstomany' | 'system' | DateTimePropertyType; /** * Check if a property is a relation type that links to another {@link LimeType}. * * Relation types are: `hasone`, `hasmany`, `belongsto`, and `hasandbelongstomany`. * These properties establish relationships between different object types in the CRM. * * Use this helper to determine if a property value will be a {@link LimeObject} or array * of {@link LimeObject | LimeObjects} rather than a simple value. * * @param property - The property to check * @returns `true` if the property is a relation type, `false` otherwise * * @example Listing every property that links to another type * ```ts * import { PlatformServiceName, isRelation } from '@limetech/lime-web-components'; * * const repository = platform.get(PlatformServiceName.LimeTypeRepository); * const limetype = repository.getLimeType('deal'); * * const relationProps = Object.values(limetype?.properties ?? {}).filter( * isRelation * ); * * for (const property of relationProps) { * const relatedType = property.relation?.getLimetype(); * console.log('Links to:', relatedType?.name); * } * ``` * * @public * @group Lime types */ export declare function isRelation(property: LimeProperty): boolean; /** * Check if the property is a single relation type, i.e. it is a property * that relates to another {@link LimeType}, such as `hasone` or `belongsto`. * * @param property - the property to check * @returns true if the property is a single relation type, false otherwise * * @public * @group Lime types */ export declare function isSingleRelation(property: LimeProperty): boolean; /** * Check if the property is a date or time type, i.e. it is a property * that represents a date or time, such as `time`, `timeofday`, `date`, * `year`, `quarter`, or `month`. * * @param property - the property to check * @returns true if the property is a date or time type, false otherwise * * @public * @group Lime types */ export declare function isDate(property: LimeProperty): boolean; /** * Check if the property is a string type, i.e. it is a property * that represents a string, such as `string`, `text`, `phone`, or `link`. * * @param property - the property to check * @returns true if the property is a string type, false otherwise * * @public * @group Lime types */ export declare function isString(property: LimeProperty): boolean; /** * Check if the property is a float type, i.e. it is a property * that represents a decimal or percent value, such as `decimal` or `percent`. * * @param property - the property to check * @returns true if the property is a float type, false otherwise * * @public * @group Lime types */ export declare function isFloat(property: LimeProperty): boolean;