IKHSAN
EN Read in EnglishID

opendesk

Publik
Branch
main
Commit terakhir
08d9f3328 Oktober 2026

types.ts

Buka raw
import { Dayjs } from "dayjs";
import { Component, ComputedRef, InjectionKey, Ref } from "vue";
import type { AssignmentRule, ODCustomer, ODTicket } from "./types/doctypes";

interface ResourceOptions<T = any> {
  method?: string;
  url: string;
  initialData?: T;
  auto?: boolean;
  cache?: string | string[];
  debounce?: number;
  params?: any;
  makeParams?: (params: any) => any;
  onFetch?: (params: any) => void;
  beforeSubmit?: (params: any) => void;
  validate?: (params: any) => string | void;
  onError?: (error: Error) => void;
  onSuccess?: (data: T) => void;
  onData?: (data: T) => void;
  transform?: (data: any) => T;
  resourceFetcher?: (options: any) => Promise<any>;
}

export interface Resource<T = any> {
  method: string | undefined;
  url: string;
  data: T | null;
  previousData: T | null;
  loading: boolean;
  fetched: boolean;
  error: Error | null;
  promise: Promise<T> | null;
  auto: boolean;
  params: any;
  fetch: (
    params?: any,
    tempOptions?: Partial<ResourceOptions<T>>
  ) => Promise<T>;
  reload: (
    params?: any,
    tempOptions?: Partial<ResourceOptions<T>>
  ) => Promise<T>;
  submit: (
    params?: any,
    tempOptions?: Partial<ResourceOptions<T>>
  ) => Promise<T>;
  reset: () => void;
  update: (options: {
    method?: string;
    url?: string;
    params?: any;
    auto?: boolean;
  }) => void;
  setData: (data: T | ((currentData: T) => T)) => void;
}

export interface ListResourceOptions {
  doctype: string;
  fields?: string[];
  filters?: Record<string, any>;
  orFilters?: Record<string, any>;
  orderBy?: string;
  start?: number;
  pageLength?: number;
  groupBy?: string;
  parent?: string;
  debug?: number;
  auto?: boolean;
  url?: string;
  cache?: any;
  realtime?: boolean;
  onSuccess?: (data: any) => void;
  onError?: (error: any) => void;
  onData?: (data: any) => void;
  transform?: (data: any) => any;
  fetchOne?: {
    onSuccess?: (data: any) => void;
    onError?: (error: any) => void;
  };
  insert?: {
    onSuccess?: (data: any) => void;
    onError?: (error: any) => void;
  };
  setValue?: {
    onSuccess?: (data: any) => void;
    onError?: (error: any) => void;
  };
  delete?: {
    onSuccess?: (data: any) => void;
    onError?: (error: any) => void;
  };
  runDocMethod?: {
    onSuccess?: (data: any) => void;
    onError?: (error: any) => void;
  };
}

export interface ListResource<T = any> {
  doctype: string;
  fields?: string[];
  filters?: Record<string, any>;
  orFilters?: Record<string, any>;
  orderBy?: string;
  start: number;
  pageLength: number;
  groupBy?: string;
  parent?: string;
  debug: number;
  originalData: T[] | null;
  dataMap: Record<string, T>;
  data: T[] | null;
  hasPreviousPage: boolean;
  hasNextPage: boolean;
  auto?: boolean;
  list: Resource<T[]>;
  fetchOne: Resource<T>;
  insert: Resource<T>;
  setValue: Resource<T>;
  delete: Resource<T>;
  runDocMethod: Resource<T>;
  loading: boolean;
  update: (updatedOptions: Partial<ListResourceOptions>) => void;
  fetch: () => void;
  reload: () => Promise<T[]>;
  setData: (data: T[] | ((data: T[]) => T[])) => void;
  transform: (data: T[]) => T[];
  getRow: (name: string) => T;
  previous: () => void;
  next: () => void;
}

export interface Error {
  exc_type: string;
  exc: string;
  response: string;
  status: string;
  messages: string;
  stack: string;
  message: string;
}

export interface Comment {
  commented_by: string;
  content: string;
  is_pinned: boolean;
  name: string;
  creation: string;
}

export interface Communication {
  creation: string;
  content: string;
  name: string;
  sender: string;
  bcc?: string;
  cc?: string;
  sent_or_received?: "Sent" | "Received";
  email_account?: string;
  sender_full_name?: string;
  sender_mail_id?: string;
}

export interface Activity {
  action: string;
  name: string;
  owner: string;
  creation: string;
}

export interface Contact {
  full_name: string;
  name: string;
  company_name?: string;
  email_id?: string;
  image?: string;
  mobile_no?: string;
  phone?: string;
}

export interface CustomField {
  fieldname: string;
  label: string;
  value: string;
  route: string;
}

export interface ViewLog {
  name: string;
  viewed_by: string;
  creation: string;
}

export interface Ticket {
  _assign: string;
  assignee: UserInfo;
  agent_group: string;
  customer: string;
  modified: string;
  name: string;
  priority: string;
  raised_by: string;
  resolution_by: string;
  response_by: string;
  first_responded_on: string;
  resolution_date: string;
  resolution_time: number;
  status: string;
  subject: string;
  ticket_type: string;
  via_customer_portal: string;
  agreement_status: string;
  creation: string;
  feedback_rating?: number;
  feedback_extra?: string;
  contact: Contact;
  comments: Comment[];
  communications: Communication[];
  history: Activity[];
  template: Template;
  views: ViewLog[];
  _customActions: Function[];
  is_merged?: boolean;
  status_category: "Open" | "Paused" | "Resolved";
}

export interface DocField {
  fieldname: string;
  fieldtype: string;
  label: string;
  name: string;
  options: string;
}

export interface Filter {
  field?: DocField;
  fieldname: string;
  operator: string;
  label: string;
  value: boolean | number | string;
}

export interface AutoCompleteItem {
  label: string;
  value: string;
}

export interface Field {
  fieldname: string;
  fieldtype: string;
  label: string;
  options: string;
  required: 0 | 1;
  description?: null;
  url_method?: string;
  link_filters?: string;
  filters?: string;
  display_via_depends_on?: string;
  mandatory_via_depends_on?: string;
  disabled?: boolean;
  placeholder?: string | null;
  readonly?: boolean;
}

export type FieldValue = string | number | boolean | null | undefined | Dayjs;

export interface Template {
  about: string;
  fields: Field[];
}

export type Column = {
  key: string;
  label: string;
  icon?: string;
  align?: string;
  width?: string;
  text?: string;
};

export type File = {
  file_name: string;
  name: string;
  file_url: string;
  is_private: boolean;
  attached_to_doctype?: string;
  attached_to_field?: string;
  attached_to_name?: string;
};

export type UserInfo = {
  email: string;
  image: string;
  name: string;
};

export interface RenderField {
  label: string;
  name: string;
  type: string;
  placeholder?: string;
  description?: string;
}

export interface EmailService {
  name: string;
  icon: string;
  info: string;
  link: string;
  custom: boolean;
}

export type EmailStep = "email-list" | "email-add" | "email-edit";

export interface EmailAccount {
  email_account_name: string;
  email_id: string;
  service: string;
  api_key?: string;
  api_secret?: string;
  password?: string;
  frappe_mail_site?: string;
  enable_outgoing?: boolean;
  enable_incoming?: boolean;
  default_outgoing?: boolean;
  default_incoming?: boolean;
}

export type TicketTab =
  | "activity"
  | "email"
  | "comment"
  | "details"
  | "call"
  | "analytics";

export interface TabObject {
  value: TicketTab;
  label: string;
  iconLeft: Component;
  condition?: () => boolean;
}

export interface RootCategory {
  category_id: string;
  category_name: string;
}

export interface Article {
  name: string;
  title: string;
  title_slug: string;
  category_name: string;
  category: string;
  published_on: string;
  author: Author;
  subtitle: string;
  article_image: string | null;
  _user_tags: string | null;
  status: string;
  visibility: string;
  creation: string;
  content: string;
  modified: string;
}

export interface Author {
  name: string;
  image: string | null;
  email: string;
}

export interface Category {
  categoryName: string;
  articles: Article[];
  authors?: {
    [key: string]: Author;
  };
  children?: Article[];
}

export interface View {
  filters: string;
  order_by: string;
  columns: string;
  rows: string;
  dt?: string;
  type?: string;
  route_name?: string;
  user?: string;
  icon?: string;
  label?: string;
  is_default?: boolean;
  pinned?: boolean;
  public?: boolean;
  group_by_field?: string;
  list_group_by?: string;
  name: string;
  is_customer_portal?: boolean;
}

export interface ViewType {
  view_type: string;
  group_by_field: string;
  name: string;
}

export interface Breadcrumb {
  label: string;
  route?: {
    name: string;
    params?: Record<string, string>;
  };
}


export interface FieldCriteriaState {
  selectedParentField: string;
  selectedChildField: string;
  childFields: any[];
  parentFieldValues: any[];
  childFieldValues: any[];
  currentParentSelection: string;
  childSelections: any;
  initialChildSelections: any;
  parentSearch: string;
  childSearch: string;
  enabled: boolean;
}

interface ResourceBase {
  data: any;
  error: any;
  fetched: boolean;
  loading: boolean;
  params: any;
  previousData: any;
  promise: Promise<any> | null;
  submit: (params?: any) => void;
}

interface DocumentResourceOptions<T = unknown> {
  doctype: string;
  name: string;
  auto?: boolean;
  whitelistedMethods?: Record<string, string>;
  onError?: (error: any) => void;
  onSuccess?: (data: T) => void;
  transform?: (doc: T) => T;
  delete?: {
    onSuccess?: () => void;
    onError?: (error: any) => void;
  };
  setValue?: {
    onSuccess?: () => void;
    onError?: (error: any) => void;
  };
}

export interface DocumentResource<T = unknown> {
  // Configuration
  auto: boolean;
  doctype: string;
  name: string;
  isDirty: boolean;
  promise: Promise<void> | null;

  // Main document data
  doc: T;
  originalDoc: T;

  // Core methods
  reload(): void;
  update(options: Partial<DocumentResourceOptions<T>>): void;

  // Sub-resources
  get: ResourceBase & {
    data: T;
    params: {
      doctype: string;
      name: string;
    };
  };

  setValue: ResourceBase & {
    submit: (
      values: Partial<T>,
      options?: { onSuccess?: () => void; onError?: (error: any) => void }
    ) => void;
  };

  setValueDebounced: ResourceBase & {
    submit: (values: Partial<T>) => void;
  };

  save: ResourceBase;
  delete: ResourceBase;

  // Dynamic whitelisted methods
  [methodName: string]: any;
}

export interface Customizations {
  fields: {
    fieldname: string;
    required?: number;
    placeholder?: string;
    url_method?: string;
  }[];
  _form_script: string[];
  _customActions?: any;
  _customOnChange?: any;
}

export interface TicketContact {
  name: string;
  email_id: string;
  phone: string;
  mobile_no: string;
  image: string;
}

// A ticket assignee enriched with their agent status by get_ticket_assignees.
// Non-agent assignees only carry `name`.
export interface TicketAssignee {
  name: string;
  agent_name?: string;
  user_image?: string;
  availability?: string;
  availability_changed_on?: string;
}

// A TicketAssignee plus the option fields AssignTo keeps when an agent is
// picked from the dropdown (image/label come from AgentOption).
export interface LocalAssignee extends TicketAssignee {
  image?: string;
  label?: string;
}

export type RecentTicket = Record<
  "subject" | "status" | "priority" | "name" | "creation",
  string
>;
export type SimilarTicket = Record<
  "subject" | "status" | "priority" | "name" | "creation",
  string
>;
export interface RecentSimilarTicket {
  recent_tickets: RecentTicket[];
  similar_tickets: SimilarTicket[];
}

export interface ODSettings {
  brandName: string;
  brandLogo: string;
  favicon: string;
  autoCloseAfterDays: string;
  autoCloseStatus: string;
  autoCloseTickets: string;
  assignWithinTeam: boolean;
  doNotRestrictTicketsWithoutAnAgentGroup: boolean;
  restrictTicketsByAgentGroup: boolean;
  updateStatusTo: string;
  autoUpdateStatus: boolean;
  isFeedbackMandatory: boolean;
  allowAnyoneToCreateTickets: boolean;
  defaultTicketType: string;
  skipEmailWorkflow: boolean;
  disableSavedRepliesGlobalScope: boolean;
  enableOutsideHoursBanner: boolean;
  outsideWorkingHoursBannerMessage: string;
}

export interface HolidayList {
  name: string;
  description: string;
}

export interface SlaPolicy {
  name: string;
  description: string;
  default_sla: boolean;
  enabled: boolean;
  rank: number;
  creation: string;
}

export interface Team {
  name: string;
  team: string;
  disabled: boolean;
}

export interface SavedReply {
  name: string;
  title: string;
  message: string;
  scope: string;
  teams: Team[];
  /** JSON-encoded SavedReplyAction[] */
  actions: string;
  owner: string;
}

export type SavedReplyActionType =
  | "Set Status"
  | "Set Priority"
  | "Set Team"
  | "Set Ticket Type"
  | "Assign Agent"
  | "Assign to Me"
  | "Add Tag"
  | "Remove Tag"
  | "Add Comment";

export interface SavedReplyAction {
  action_type: SavedReplyActionType;
  value: string;
  label?: string;
  /** Title of the saved reply that staged this action */
  source?: string;
  /** Value the saved reply shipped, so an edited comment can be restored */
  original_value?: string;
}

export interface RenderedSavedReply {
  title: string;
  message: string;
  actions: SavedReplyAction[];
}

export type APIOptions = DropdownOption[] | string[] | [];

export type DropdownOption = {
  label: string;
  value: string | number;
};

export interface AgentOption {
  value: string;
  label: string;
  image?: string;
  availability?: string;
  availability_changed_on?: string;
}

// symbols
export const TicketSymbol: InjectionKey<
  ComputedRef<DocumentResource<ODTicket>>
> = Symbol("ticket");
export const AssigneeSymbol: InjectionKey<
  ComputedRef<Resource<Record<"name", string>[]>>
> = Symbol("assignees");

export const CustomizationSymbol: InjectionKey<
  ComputedRef<Resource<Customizations>>
> = Symbol("customizations");

export const TicketContactSymbol: InjectionKey<
  ComputedRef<Resource<TicketContact>>
> = Symbol("ticketContact");

export const RecentSimilarTicketsSymbol: InjectionKey<
  ComputedRef<Resource<RecentSimilarTicket>>
> = Symbol("recentSimilarTickets");

export const AssignmentRuleListResourceSymbol: InjectionKey<
  Resource<AssignmentRule[]>
> = Symbol("assignmentRuleListResource");

export const ODSettingsSymbol: InjectionKey<Ref<ODSettings>> =
  Symbol("odSettings");

export const HolidayListResourceSymbol: InjectionKey<
  ListResource<HolidayList>
> = Symbol("holidayListResource");

export const SlaPolicyListResourceSymbol: InjectionKey<
  ListResource<SlaPolicy>
> = Symbol("slaPolicyListResource");

export const TeamListResourceSymbol: InjectionKey<ListResource<Team>> =
  Symbol("teamListResource");

export const SavedReplyListResourceSymbol: InjectionKey<
  ListResource<SavedReply>
> = Symbol("savedReplyListResource");

export const CustomerResourceSymbol: InjectionKey<
  DocumentResource<ODCustomer>
> = Symbol("customerResource");

declare global {
  interface Window {
    is_fc_site: boolean;
    date_format: string;
    time_format: string;
    session_user: string;
    timezone: Record<"user" | "system", string>;
    agent: string | null;
    default_country: string;
    apps: string[];
    telemetry: { enabled: boolean };
    customer_home_page: string;
  }
}

export interface CustomerContact {
  contact_name: string;
  is_primary: 0 | 1;
  is_manager: 0 | 1;
  email_id: string | null;
  mobile_no: string | null;
  image: string | null;
  last_active: string;
  modified?: string;
  ticket_count: number;
}
export interface NewContactState {
  firstName: string;
  lastName: string;
  image: string;
  email: string;
  phone: string;
  timezone: string;
  customer: string;
  invite: boolean;
}

export interface ContactEmailEntry {
  email_id: string;
  isPrimary: boolean;
  key: number;
}

export interface ContactPhoneEntry {
  phone: string;
  isPrimary: boolean;
  key: number;
}

export interface EditContactState {
  firstName: string;
  lastName: string;
  image: string;
  emails: ContactEmailEntry[];
  phones: ContactPhoneEntry[];
  customers: string[];
  customer: string;
  timezone: string;
}

export interface LineChart {
  percentage_change: number;
  total: number;
  data: { date: string; count: number }[];
}
byte
16.044
baris
757
Jenis
ts
Commit terakhir
28 Oktober 2026