Browse Source

Feature: Mobile - Added form schema field improvements.

Dominik Klein 2 years ago
parent
commit
f566c47f2a

+ 1 - 0
app/frontend/apps/mobile/components/CommonSelect/CommonSelect.vue

@@ -30,6 +30,7 @@ const emit = defineEmits<{
 const dialogElement = ref<HTMLElement>()
 const localValue = useVModel(props, 'modelValue', emit)
 
+// TODO: do we really want this initial transfomring of the value, when it's null?
 if (localValue.value == null && props.multiple) {
   localValue.value = []
 }

+ 26 - 1
app/frontend/apps/mobile/components/Organization/OrganizationEditDialog.vue

@@ -6,7 +6,10 @@ import Form from '@shared/components/Form/Form.vue'
 import CommonDialog from '@mobile/components/CommonDialog/CommonDialog.vue'
 import { CheckboxVariant } from '@shared/components/Form/fields/FieldCheckbox'
 import type { ConfidentTake } from '@shared/types/utils'
-import { OrganizationInput } from '@shared/graphql/types'
+import {
+  // EnumObjectManagerObjects,
+  type OrganizationInput,
+} from '@shared/graphql/types'
 import type { OrganizationQuery } from '@shared/graphql/types'
 import { closeDialog } from '@shared/composables/useDialog'
 import { MutationHandler } from '@shared/server/apollo/handler'
@@ -80,6 +83,26 @@ const schema = defineFormSchema([
       },
     ],
   },
+  // {
+  //   isLayout: true,
+  //   component: 'FormGroup',
+  //   children: [
+  //     {
+  //       screen: 'edit',
+  //       object: EnumObjectManagerObjects.Organization,
+  //     },
+  //   ],
+  // },
+  // {
+  //   isLayout: true,
+  //   component: 'FormGroup',
+  //   children: [
+  //     {
+  //       name: 'active',
+  //       object: EnumObjectManagerObjects.Organization,
+  //     },
+  //   ],
+  // },
 ])
 
 const updateQuery = new MutationHandler(useOrganizationUpdateMutation({}))
@@ -121,7 +144,9 @@ const saveOrganization = async (input: OrganizationInput) => {
       id="edit-organization"
       ref="formElement"
       class="w-full p-4"
+      :initial-values="props.organization"
       :schema="schema"
+      use-object-attributes
       @submit="saveOrganization($event as OrganizationInput)"
     />
   </CommonDialog>

+ 146 - 79
app/frontend/apps/mobile/entities/organization/__tests__/mocks/organization-mocks.ts

@@ -1,6 +1,6 @@
 // Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
 
-import { ObjectManagerFrontendAttributesDocument } from '@shared/graphql/queries/objectManagerFrontendAttributes.api'
+import { ObjectManagerFrontendAttributesDocument } from '@shared/entities/object-attributes/graphql/queries/objectManagerFrontendAttributes.api'
 import type { OrganizationQuery } from '@shared/graphql/types'
 import type { ConfidentTake } from '@shared/types/utils'
 import { mockGraphQLApi } from '@tests/support/mock-graphql-api'
@@ -46,92 +46,159 @@ export const defaultOrganization = (): ConfidentTake<
     },
   })
 
-export const organizationObjectAttributes = () => [
-  {
-    name: 'name',
-    display: 'Name',
-    dataType: 'input',
-    dataOption: {
-      type: 'text',
-      maxlength: 150,
-      null: false,
-      item_class: 'formGroup--halfSize',
+export const organizationObjectAttributes = () => ({
+  attributes: [
+    {
+      __typename: 'ObjectManagerFrontendAttribute',
+      name: 'name',
+      display: 'Name',
+      dataType: 'input',
+      dataOption: {
+        type: 'text',
+        maxlength: 150,
+        null: false,
+        item_class: 'formGroup--halfSize',
+      },
+      screens: {},
+    },
+    {
+      __typename: 'ObjectManagerFrontendAttribute',
+      name: 'shared',
+      display: 'Shared organization',
+      dataType: 'boolean',
+      dataOption: {
+        null: true,
+        default: true,
+        note: "Customers in the organization can view each other's items.",
+        item_class: 'formGroup--halfSize',
+        options: {
+          true: 'yes',
+          false: 'no',
+        },
+        translate: true,
+        permission: ['admin.organization'],
+      },
+      screens: {},
+    },
+    {
+      __typename: 'ObjectManagerFrontendAttribute',
+      name: 'domain_assignment',
+      display: 'Domain based assignment',
+      dataType: 'boolean',
+      dataOption: {
+        null: true,
+        default: false,
+        note: 'Assign users based on user domain.',
+        item_class: 'formGroup--halfSize',
+        options: {
+          true: 'yes',
+          false: 'no',
+        },
+        translate: true,
+        permission: ['admin.organization'],
+      },
+      screens: {},
     },
-    __typename: 'ObjectManagerFrontendAttribute',
-  },
-  {
-    name: 'shared',
-    display: 'Shared organization',
-    dataType: 'boolean',
-    dataOption: {
-      null: true,
-      default: true,
-      note: "Customers in the organization can view each other's items.",
-      item_class: 'formGroup--halfSize',
-      options: {
-        true: 'yes',
-        false: 'no',
+    {
+      __typename: 'ObjectManagerFrontendAttribute',
+      name: 'domain',
+      display: 'Domain',
+      dataType: 'input',
+      dataOption: {
+        type: 'text',
+        maxlength: 150,
+        null: true,
+        item_class: 'formGroup--halfSize',
       },
-      translate: true,
-      permission: ['admin.organization'],
+      screens: {},
     },
-    __typename: 'ObjectManagerFrontendAttribute',
-  },
-  {
-    name: 'domain_assignment',
-    display: 'Domain based assignment',
-    dataType: 'boolean',
-    dataOption: {
-      null: true,
-      default: false,
-      note: 'Assign users based on user domain.',
-      item_class: 'formGroup--halfSize',
-      options: {
-        true: 'yes',
-        false: 'no',
+    {
+      __typename: 'ObjectManagerFrontendAttribute',
+      name: 'note',
+      display: 'Note',
+      dataType: 'richtext',
+      dataOption: {
+        type: 'text',
+        maxlength: 5000,
+        null: true,
+        note: 'Notes are visible to agents only, never to customers.',
+        no_images: true,
       },
-      translate: true,
-      permission: ['admin.organization'],
+      screens: {},
     },
-    __typename: 'ObjectManagerFrontendAttribute',
-  },
-  {
-    name: 'domain',
-    display: 'Domain',
-    dataType: 'input',
-    dataOption: {
-      type: 'text',
-      maxlength: 150,
-      null: true,
-      item_class: 'formGroup--halfSize',
+    {
+      __typename: 'ObjectManagerFrontendAttribute',
+      name: 'active',
+      display: 'Active',
+      dataType: 'active',
+      dataOption: {
+        null: true,
+        default: true,
+        permission: ['admin.organization'],
+      },
+      screens: {},
+    },
+    {
+      __typename: 'ObjectManagerFrontendAttribute',
+      name: 'test',
+      display: 'test',
+      dataType: 'input',
+      dataOption: {
+        default: '',
+        type: 'text',
+        maxlength: 120,
+        linktemplate: '',
+        null: true,
+        options: {},
+        relation: '',
+      },
+      screens: {},
     },
-    __typename: 'ObjectManagerFrontendAttribute',
-  },
-  {
-    name: 'note',
-    display: 'Note',
-    dataType: 'richtext',
-    dataOption: {
-      type: 'text',
-      maxlength: 5000,
-      null: true,
-      note: 'Notes are visible to agents only, never to customers.',
-      no_images: true,
+    {
+      __typename: 'ObjectManagerFrontendAttribute',
+      name: 'textarea',
+      display: 'textarea',
+      dataType: 'textarea',
+      dataOption: {
+        default: '',
+        maxlength: 500,
+        rows: 4,
+        null: true,
+        options: {},
+        relation: '',
+      },
+      screens: {},
     },
-    __typename: 'ObjectManagerFrontendAttribute',
-  },
-  {
-    name: 'active',
-    display: 'Active',
-    dataType: 'active',
-    dataOption: {
-      null: true,
-      default: true,
-      permission: ['admin.organization'],
+  ],
+  screens: [
+    {
+      name: 'view',
+      attributes: [
+        'name',
+        'shared',
+        'domain_assignment',
+        'domain',
+        'note',
+        'active',
+        'test',
+        'textarea',
+      ],
+    },
+    {
+      name: 'edit',
+      attributes: [
+        'name',
+        'shared',
+        'domain_assignment',
+        'domain',
+        'note',
+        'active',
+        'test',
+        'textarea',
+      ],
     },
-    __typename: 'ObjectManagerFrontendAttribute',
-  },
-]
+  ],
+})
 
 export const mockOrganizationObjectAttributes = () => {
   return mockGraphQLApi(ObjectManagerFrontendAttributesDocument).willResolve({

+ 0 - 19
app/frontend/apps/mobile/entities/organization/stores/objectManagerAttributes.ts

@@ -1,19 +0,0 @@
-// Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
-
-import { defineStore } from 'pinia'
-import { useObjectManagerAttributes } from '@shared/entities/object-manager/composables/useObjectManagerAttributes'
-import { EnumObjectManagerObjects } from '@shared/graphql/types'
-
-export const useOrganizationObjectManagerAttributesStore = defineStore(
-  'organizationObjectAttributes',
-  () => {
-    const attributes = useObjectManagerAttributes(
-      EnumObjectManagerObjects.Organization,
-      'view',
-    )
-
-    return {
-      ...attributes,
-    }
-  },
-)

+ 189 - 139
app/frontend/apps/mobile/entities/user/__tests__/mocks/managerAttributes.json

@@ -1,151 +1,201 @@
-[
-  {
-    "name": "firstname",
-    "display": "First name",
-    "dataType": "input",
-    "dataOption": {
-      "type": "text",
-      "maxlength": 150,
-      "null": true,
-      "item_class": "formGroup--halfSize"
+{
+  "attributes": [
+    {
+      "name": "firstname",
+      "display": "First name",
+      "dataType": "input",
+      "dataOption": {
+        "type": "text",
+        "maxlength": 150,
+        "null": true,
+        "item_class": "formGroup--halfSize"
+      },
+      "screens": {},
+      "__typename": "ObjectManagerFrontendAttribute"
     },
-    "__typename": "ObjectManagerFrontendAttribute"
-  },
-  {
-    "name": "lastname",
-    "display": "Last name",
-    "dataType": "input",
-    "dataOption": {
-      "type": "text",
-      "maxlength": 150,
-      "null": true,
-      "item_class": "formGroup--halfSize"
+    {
+      "name": "lastname",
+      "display": "Last name",
+      "dataType": "input",
+      "dataOption": {
+        "type": "text",
+        "maxlength": 150,
+        "null": true,
+        "item_class": "formGroup--halfSize"
+      },
+      "screens": {},
+      "__typename": "ObjectManagerFrontendAttribute"
     },
-    "__typename": "ObjectManagerFrontendAttribute"
-  },
-  {
-    "name": "email",
-    "display": "Email",
-    "dataType": "input",
-    "dataOption": {
-      "type": "email",
-      "maxlength": 150,
-      "null": true,
-      "item_class": "formGroup--halfSize"
+    {
+      "name": "email",
+      "display": "Email",
+      "dataType": "input",
+      "dataOption": {
+        "type": "email",
+        "maxlength": 150,
+        "null": true,
+        "item_class": "formGroup--halfSize"
+      },
+      "screens": {},
+      "__typename": "ObjectManagerFrontendAttribute"
     },
-    "__typename": "ObjectManagerFrontendAttribute"
-  },
-  {
-    "name": "web",
-    "display": "Web",
-    "dataType": "input",
-    "dataOption": {
-      "type": "url",
-      "maxlength": 250,
-      "null": true,
-      "item_class": "formGroup--halfSize"
+    {
+      "name": "web",
+      "display": "Web",
+      "dataType": "input",
+      "dataOption": {
+        "type": "url",
+        "maxlength": 250,
+        "null": true,
+        "item_class": "formGroup--halfSize"
+      },
+      "screens": {},
+      "__typename": "ObjectManagerFrontendAttribute"
     },
-    "__typename": "ObjectManagerFrontendAttribute"
-  },
-  {
-    "name": "phone",
-    "display": "Phone",
-    "dataType": "input",
-    "dataOption": {
-      "type": "tel",
-      "maxlength": 100,
-      "null": true,
-      "item_class": "formGroup--halfSize"
+    {
+      "name": "phone",
+      "display": "Phone",
+      "dataType": "input",
+      "dataOption": {
+        "type": "tel",
+        "maxlength": 100,
+        "null": true,
+        "item_class": "formGroup--halfSize"
+      },
+      "screens": {},
+      "__typename": "ObjectManagerFrontendAttribute"
     },
-    "__typename": "ObjectManagerFrontendAttribute"
-  },
-  {
-    "name": "mobile",
-    "display": "Mobile",
-    "dataType": "input",
-    "dataOption": {
-      "type": "tel",
-      "maxlength": 100,
-      "null": true,
-      "item_class": "formGroup--halfSize"
+    {
+      "name": "mobile",
+      "display": "Mobile",
+      "dataType": "input",
+      "dataOption": {
+        "type": "tel",
+        "maxlength": 100,
+        "null": true,
+        "item_class": "formGroup--halfSize"
+      },
+      "screens": {},
+      "__typename": "ObjectManagerFrontendAttribute"
     },
-    "__typename": "ObjectManagerFrontendAttribute"
-  },
-  {
-    "name": "fax",
-    "display": "Fax",
-    "dataType": "input",
-    "dataOption": {
-      "type": "tel",
-      "maxlength": 100,
-      "null": true,
-      "item_class": "formGroup--halfSize"
+    {
+      "name": "fax",
+      "display": "Fax",
+      "dataType": "input",
+      "dataOption": {
+        "type": "tel",
+        "maxlength": 100,
+        "null": true,
+        "item_class": "formGroup--halfSize"
+      },
+      "screens": {},
+      "__typename": "ObjectManagerFrontendAttribute"
     },
-    "__typename": "ObjectManagerFrontendAttribute"
-  },
-  {
-    "name": "organization_id",
-    "display": "Organization",
-    "dataType": "autocompletion_ajax",
-    "dataOption": {
-      "multiple": false,
-      "nulloption": true,
-      "null": true,
-      "relation": "Organization",
-      "item_class": "formGroup--halfSize"
+    {
+      "name": "organization_id",
+      "display": "Organization",
+      "dataType": "autocompletion_ajax",
+      "dataOption": {
+        "multiple": false,
+        "nulloption": true,
+        "null": true,
+        "relation": "Organization",
+        "item_class": "formGroup--halfSize"
+      },
+      "screens": {},
+      "__typename": "ObjectManagerFrontendAttribute"
     },
-    "__typename": "ObjectManagerFrontendAttribute"
-  },
-  {
-    "name": "organization_ids",
-    "display": "Secondary organizations",
-    "dataType": "autocompletion_ajax",
-    "dataOption": {
-      "multiple": true,
-      "nulloption": true,
-      "null": true,
-      "relation": "Organization",
-      "item_class": "formGroup--halfSize",
-      "display_limit": 3
+    {
+      "name": "organization_ids",
+      "display": "Secondary organizations",
+      "dataType": "autocompletion_ajax",
+      "dataOption": {
+        "multiple": true,
+        "nulloption": true,
+        "null": true,
+        "relation": "Organization",
+        "item_class": "formGroup--halfSize",
+        "display_limit": 3
+      },
+      "screens": {},
+      "__typename": "ObjectManagerFrontendAttribute"
     },
-    "__typename": "ObjectManagerFrontendAttribute"
-  },
-  {
-    "name": "department",
-    "display": "Department",
-    "dataType": "input",
-    "dataOption": {
-      "type": "text",
-      "maxlength": 200,
-      "null": true,
-      "item_class": "formGroup--halfSize"
+    {
+      "name": "department",
+      "display": "Department",
+      "dataType": "input",
+      "dataOption": {
+        "type": "text",
+        "maxlength": 200,
+        "null": true,
+        "item_class": "formGroup--halfSize"
+      },
+      "screens": {},
+      "__typename": "ObjectManagerFrontendAttribute"
     },
-    "__typename": "ObjectManagerFrontendAttribute"
-  },
-  {
-    "name": "address",
-    "display": "Address",
-    "dataType": "textarea",
-    "dataOption": {
-      "type": "text",
-      "maxlength": 500,
-      "rows": 4,
-      "null": true,
-      "item_class": "formGroup--halfSize"
+    {
+      "name": "address",
+      "display": "Address",
+      "dataType": "textarea",
+      "dataOption": {
+        "type": "text",
+        "maxlength": 500,
+        "rows": 4,
+        "null": true,
+        "item_class": "formGroup--halfSize"
+      },
+      "screens": {},
+      "__typename": "ObjectManagerFrontendAttribute"
     },
-    "__typename": "ObjectManagerFrontendAttribute"
-  },
-  {
-    "name": "note",
-    "display": "Note",
-    "dataType": "richtext",
-    "dataOption": {
-      "type": "text",
-      "maxlength": 5000,
-      "null": true,
-      "note": "Notes are visible to agents only, never to customers.",
-      "no_images": true
+    {
+      "name": "note",
+      "display": "Note",
+      "dataType": "richtext",
+      "dataOption": {
+        "type": "text",
+        "maxlength": 5000,
+        "null": true,
+        "note": "Notes are visible to agents only, never to customers.",
+        "no_images": true
+      },
+      "screens": {},
+      "__typename": "ObjectManagerFrontendAttribute"
+    }
+  ],
+  "screens": [
+    {
+      "name": "view",
+      "attributes": [
+        "firstname",
+        "lastname",
+        "email",
+        "web",
+        "phone",
+        "mobile",
+        "fax",
+        "organization_id",
+        "organization_ids",
+        "department",
+        "address",
+        "note"
+      ]
     },
-    "__typename": "ObjectManagerFrontendAttribute"
-  }
-]
+    {
+      "name": "edit",
+      "attributes": [
+        "firstname",
+        "lastname",
+        "email",
+        "web",
+        "phone",
+        "mobile",
+        "fax",
+        "organization_id",
+        "organization_ids",
+        "department",
+        "address",
+        "note"
+      ]
+    }
+  ]
+}

+ 3 - 3
app/frontend/apps/mobile/entities/user/__tests__/mocks/user-mocks.ts

@@ -1,7 +1,7 @@
 // Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
 
 import { defaultOrganization } from '@mobile/entities/organization/__tests__/mocks/organization-mocks'
-import { ObjectManagerFrontendAttributesDocument } from '@shared/graphql/queries/objectManagerFrontendAttributes.api'
+import { ObjectManagerFrontendAttributesDocument } from '@shared/entities/object-attributes/graphql/queries/objectManagerFrontendAttributes.api'
 import { UserUpdatesDocument } from '@shared/graphql/subscriptions/userUpdates.api'
 import type { UserQuery } from '@shared/graphql/types'
 import type { ConfidentTake } from '@shared/types/utils'
@@ -11,7 +11,7 @@ import {
 } from '@tests/support/mock-graphql-api'
 import { nullableMock } from '@tests/support/utils'
 import { UserDocument } from '../../graphql/queries/user.api'
-import managerAttrutes from './managerAttributes.json'
+import managerAttributes from './managerAttributes.json'
 
 export const defaultUser = (): ConfidentTake<UserQuery, 'user'> => {
   const organization = defaultOrganization()
@@ -76,7 +76,7 @@ export const defaultUser = (): ConfidentTake<UserQuery, 'user'> => {
 
 export const mockUserManagerAttributes = () => {
   return mockGraphQLApi(ObjectManagerFrontendAttributesDocument).willResolve({
-    objectManagerFrontendAttributes: managerAttrutes,
+    objectManagerFrontendAttributes: managerAttributes,
   })
 }
 

+ 3 - 3
app/frontend/apps/mobile/entities/user/composables/useUserDetail.ts

@@ -8,8 +8,8 @@ import type {
 import { QueryHandler } from '@shared/server/apollo/handler'
 import { whenever } from '@vueuse/shared'
 import { computed, nextTick, ref } from 'vue'
+import { useUserObjectAttributesStore } from '@shared/entities/user/stores/objectAttributes'
 import { useUserLazyQuery } from '../graphql/queries/user.api'
-import { useUserObjectManagerAttributesStore } from '../stores/objectManagerAttributes'
 
 export const useUserDetail = () => {
   const internalId = ref(0)
@@ -35,10 +35,10 @@ export const useUserDetail = () => {
 
   const user = computed(() => userResult.value?.user)
 
-  const objectAttributesManager = useUserObjectManagerAttributesStore()
+  const objectAttributesManager = useUserObjectAttributesStore()
 
   const objectAttributes = computed(
-    () => objectAttributesManager.attributes || [],
+    () => objectAttributesManager.viewScreenAttributes || [],
   )
 
   const stopWatch = whenever(

+ 0 - 19
app/frontend/apps/mobile/entities/user/stores/objectManagerAttributes.ts

@@ -1,19 +0,0 @@
-// Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
-
-import { defineStore } from 'pinia'
-import { useObjectManagerAttributes } from '@shared/entities/object-manager/composables/useObjectManagerAttributes'
-import { EnumObjectManagerObjects } from '@shared/graphql/types'
-
-export const useUserObjectManagerAttributesStore = defineStore(
-  'userObjectAttributes',
-  () => {
-    const attributes = useObjectManagerAttributes(
-      EnumObjectManagerObjects.User,
-      'view',
-    )
-
-    return {
-      ...attributes,
-    }
-  },
-)

+ 5 - 1
app/frontend/apps/mobile/form/composable.ts

@@ -2,10 +2,14 @@
 
 import type { FormSchemaNode } from '@shared/components/Form'
 
+// TODO: do we need this?
 export const defineFormSchema = (
   schema: FormSchemaNode[],
 ): FormSchemaNode[] => {
-  const needGroup = schema.every((node) => !('isLayout' in node))
+  const needGroup = schema.every(
+    (node) => !(typeof node !== 'string' && 'isLayout' in node),
+  )
+
   if (!needGroup) return schema
   return [
     {

+ 1 - 1
app/frontend/apps/mobile/form/theme/global/getCoreClasses.ts

@@ -43,7 +43,7 @@ const getCoreClasses: FormThemeExtension = (classes: FormThemeClasses) => {
     checkbox: {
       wrapper: `${
         classes.checkbox?.wrapper || ''
-      } flex-row-reverse w-full justify-between h-14 ltr:pl-2 rtl:pr-2`,
+      } w-full justify-between h-14 ltr:pl-2 rtl:pr-2`,
     },
     tags: addBlockFloatingLabel({
       ...(classes.tags || {}),

Some files were not shown because too many files changed in this diff