@simsustech/quasar-components 0.8.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # @simsustech/quasar-components
2
2
 
3
+ ## 0.9.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 9fe6cd0: feat: add AccountsTable component
8
+
9
+ ### Patch Changes
10
+
11
+ - eec2e00: fix(DateInput): fix locale prop
12
+
3
13
  ## 0.8.1
4
14
 
5
15
  ### Patch Changes
@@ -1,6 +1,6 @@
1
- import { useQuasar, QForm, QInput, QStep, QStepperNavigation, QStepper, QIcon, QBtn, QSlider, QItemSection, QItem, QList, QMenu } from "quasar";
2
- import { ref, defineComponent, watch, computed, openBlock, createBlock, unref, mergeProps, withCtx, createVNode, renderSlot, toRef, createCommentVNode, createElementBlock, Fragment, renderList, createTextVNode, toDisplayString } from "vue";
3
- import { _ as _sfc_main$c } from "./QSubmitButton.vue_vue_type_script_setup_true_lang-DAnZaTMl.js";
1
+ import { useQuasar, QForm, QInput, QStep, QStepperNavigation, QStepper, QIcon, QBtn, QSlider, QItemSection, QItem, QList, QMenu, QTable, QTh, QTr, QSelect, QTd, QItemLabel } from "quasar";
2
+ import { ref, defineComponent, watch, computed, openBlock, createBlock, unref, mergeProps, withCtx, createVNode, renderSlot, toRef, createCommentVNode, createElementBlock, Fragment, renderList, createTextVNode, toDisplayString, toRefs, createElementVNode } from "vue";
3
+ import { _ as _sfc_main$d } from "./QSubmitButton.vue_vue_type_script_setup_true_lang-DAnZaTMl.js";
4
4
  const lang$1 = {
5
5
  isoName: "en-US",
6
6
  myAccount: "Account",
@@ -88,6 +88,22 @@ const lang$1 = {
88
88
  },
89
89
  verification: {
90
90
  slider: "Please drag the slider below all the way to the right."
91
+ },
92
+ account: {
93
+ title: "Accounts",
94
+ fields: {
95
+ name: "Name",
96
+ email: "Email",
97
+ roles: "Roles"
98
+ },
99
+ labels: {
100
+ addRole: "Add role",
101
+ removeRole: "Remove role"
102
+ },
103
+ messages: {
104
+ addRole: ({ email }) => `Select the role which you want to add to ${email}.`,
105
+ removeRole: ({ email }) => `Select the role which you want to remove from ${email}.`
106
+ }
91
107
  }
92
108
  };
93
109
  const enUS = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
@@ -98,7 +114,7 @@ var define_import_meta_env_default = { BASE_URL: "/", MODE: "production", DEV: f
98
114
  const lang = ref(lang$1);
99
115
  const locales = /* @__PURE__ */ Object.assign({
100
116
  "./en-US.ts": () => Promise.resolve().then(() => enUS),
101
- "./nl.ts": () => import("./nl-D4kRrjEa.js")
117
+ "./nl.ts": () => import("./nl-jHKPHlmh.js")
102
118
  });
103
119
  const useLang = () => {
104
120
  return lang;
@@ -382,7 +398,7 @@ function isEmail(str, options) {
382
398
  const __default__$a = {
383
399
  name: "RequestOtpForm"
384
400
  };
385
- const _sfc_main$b = /* @__PURE__ */ defineComponent({
401
+ const _sfc_main$c = /* @__PURE__ */ defineComponent({
386
402
  ...__default__$a,
387
403
  props: {
388
404
  form: {},
@@ -454,7 +470,7 @@ const _sfc_main$b = /* @__PURE__ */ defineComponent({
454
470
  };
455
471
  }
456
472
  });
457
- const _sfc_main$a = /* @__PURE__ */ defineComponent({
473
+ const _sfc_main$b = /* @__PURE__ */ defineComponent({
458
474
  __name: "OtpInput",
459
475
  props: {
460
476
  modelValue: {}
@@ -482,7 +498,7 @@ const _sfc_main$a = /* @__PURE__ */ defineComponent({
482
498
  const __default__$9 = {
483
499
  name: "EmailChangeForm"
484
500
  };
485
- const _sfc_main$9 = /* @__PURE__ */ defineComponent({
501
+ const _sfc_main$a = /* @__PURE__ */ defineComponent({
486
502
  ...__default__$9,
487
503
  props: {
488
504
  email: {},
@@ -550,7 +566,7 @@ const _sfc_main$9 = /* @__PURE__ */ defineComponent({
550
566
  onSubmit: _cache[3] || (_cache[3] = (e) => submit)
551
567
  }), {
552
568
  default: withCtx(() => [
553
- createVNode(_sfc_main$a, mergeProps(_ctx.input, {
569
+ createVNode(_sfc_main$b, mergeProps(_ctx.input, {
554
570
  modelValue: otp.value,
555
571
  "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => otp.value = $event)
556
572
  }), null, 16, ["modelValue"]),
@@ -584,7 +600,7 @@ const _sfc_main$9 = /* @__PURE__ */ defineComponent({
584
600
  const __default__$8 = {
585
601
  name: "EmailChangeStepper"
586
602
  };
587
- const _sfc_main$8 = /* @__PURE__ */ defineComponent({
603
+ const _sfc_main$9 = /* @__PURE__ */ defineComponent({
588
604
  ...__default__$8,
589
605
  props: {
590
606
  input: {}
@@ -667,13 +683,13 @@ const _sfc_main$8 = /* @__PURE__ */ defineComponent({
667
683
  default: withCtx(() => {
668
684
  var _a, _b;
669
685
  return [
670
- step.value === "requestOtp" ? (openBlock(), createBlock(_sfc_main$c, {
686
+ step.value === "requestOtp" ? (openBlock(), createBlock(_sfc_main$d, {
671
687
  key: 0,
672
688
  "is-next-button": "",
673
689
  form: "requestOtpForm",
674
690
  onSubmit: (_a = requestOtpFormRef.value) == null ? void 0 : _a.functions.submit
675
691
  }, null, 8, ["onSubmit"])) : createCommentVNode("", true),
676
- step.value === "changeEmail" ? (openBlock(), createBlock(_sfc_main$c, {
692
+ step.value === "changeEmail" ? (openBlock(), createBlock(_sfc_main$d, {
677
693
  key: 1,
678
694
  form: "emailChangeForm",
679
695
  onSubmit: (_b = emailChangeFormRef.value) == null ? void 0 : _b.functions.submit
@@ -689,7 +705,7 @@ const _sfc_main$8 = /* @__PURE__ */ defineComponent({
689
705
  title: requestOtpHeader.value
690
706
  }, {
691
707
  default: withCtx(() => [
692
- createVNode(_sfc_main$b, {
708
+ createVNode(_sfc_main$c, {
693
709
  ref_key: "requestOtpFormRef",
694
710
  ref: requestOtpFormRef,
695
711
  form: { id: "requestOtpForm" },
@@ -704,7 +720,7 @@ const _sfc_main$8 = /* @__PURE__ */ defineComponent({
704
720
  title: emailChangeHeader.value
705
721
  }, {
706
722
  default: withCtx(() => [
707
- createVNode(_sfc_main$9, {
723
+ createVNode(_sfc_main$a, {
708
724
  ref_key: "emailChangeFormRef",
709
725
  ref: emailChangeFormRef,
710
726
  form: { id: "emailChangeForm" },
@@ -728,7 +744,7 @@ function equals(str, comparison) {
728
744
  const __default__$7 = {
729
745
  name: "PasswordChangeForm"
730
746
  };
731
- const _sfc_main$7 = /* @__PURE__ */ defineComponent({
747
+ const _sfc_main$8 = /* @__PURE__ */ defineComponent({
732
748
  ...__default__$7,
733
749
  props: {
734
750
  email: {},
@@ -800,7 +816,7 @@ const _sfc_main$7 = /* @__PURE__ */ defineComponent({
800
816
  onSubmit: _cache[5] || (_cache[5] = (e) => submit)
801
817
  }), {
802
818
  default: withCtx(() => [
803
- createVNode(_sfc_main$a, mergeProps(_ctx.input, {
819
+ createVNode(_sfc_main$b, mergeProps(_ctx.input, {
804
820
  modelValue: otp.value,
805
821
  "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => otp.value = $event)
806
822
  }), null, 16, ["modelValue"]),
@@ -855,7 +871,7 @@ const __default__$6 = {
855
871
  name: "PasswordChangeStepper",
856
872
  useLang
857
873
  };
858
- const _sfc_main$6 = /* @__PURE__ */ defineComponent({
874
+ const _sfc_main$7 = /* @__PURE__ */ defineComponent({
859
875
  ...__default__$6,
860
876
  props: {
861
877
  input: {}
@@ -920,13 +936,13 @@ const _sfc_main$6 = /* @__PURE__ */ defineComponent({
920
936
  default: withCtx(() => {
921
937
  var _a, _b;
922
938
  return [
923
- step.value === "requestOtp" ? (openBlock(), createBlock(_sfc_main$c, {
939
+ step.value === "requestOtp" ? (openBlock(), createBlock(_sfc_main$d, {
924
940
  key: 0,
925
941
  "is-next-button": "",
926
942
  form: "requestOtpForm",
927
943
  onSubmit: (_a = requestOtpFormRef.value) == null ? void 0 : _a.functions.submit
928
944
  }, null, 8, ["onSubmit"])) : createCommentVNode("", true),
929
- step.value === "changePassword" ? (openBlock(), createBlock(_sfc_main$c, {
945
+ step.value === "changePassword" ? (openBlock(), createBlock(_sfc_main$d, {
930
946
  key: 1,
931
947
  form: "passwordChangeForm",
932
948
  onSubmit: (_b = passwordChangeFormRef.value) == null ? void 0 : _b.functions.submit
@@ -942,7 +958,7 @@ const _sfc_main$6 = /* @__PURE__ */ defineComponent({
942
958
  title: requestOtpHeader.value
943
959
  }, {
944
960
  default: withCtx(() => [
945
- createVNode(_sfc_main$b, {
961
+ createVNode(_sfc_main$c, {
946
962
  ref_key: "requestOtpFormRef",
947
963
  ref: requestOtpFormRef,
948
964
  form: { id: "requestOtpForm" },
@@ -957,7 +973,7 @@ const _sfc_main$6 = /* @__PURE__ */ defineComponent({
957
973
  title: passwordChangeHeader.value
958
974
  }, {
959
975
  default: withCtx(() => [
960
- createVNode(_sfc_main$7, {
976
+ createVNode(_sfc_main$8, {
961
977
  ref_key: "passwordChangeFormRef",
962
978
  ref: passwordChangeFormRef,
963
979
  form: { id: "passwordChangeForm" },
@@ -977,7 +993,7 @@ const _sfc_main$6 = /* @__PURE__ */ defineComponent({
977
993
  const __default__$5 = {
978
994
  name: "LoginForm"
979
995
  };
980
- const _sfc_main$5 = /* @__PURE__ */ defineComponent({
996
+ const _sfc_main$6 = /* @__PURE__ */ defineComponent({
981
997
  ...__default__$5,
982
998
  props: {
983
999
  useUsername: { type: Boolean },
@@ -1196,7 +1212,7 @@ function isAlphanumeric(_str) {
1196
1212
  const __default__$4 = {
1197
1213
  name: "RegisterForm"
1198
1214
  };
1199
- const _sfc_main$4 = /* @__PURE__ */ defineComponent({
1215
+ const _sfc_main$5 = /* @__PURE__ */ defineComponent({
1200
1216
  ...__default__$4,
1201
1217
  props: {
1202
1218
  useUsername: { type: Boolean },
@@ -1371,7 +1387,7 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
1371
1387
  const __default__$3 = {
1372
1388
  name: "VerificationSlider"
1373
1389
  };
1374
- const _sfc_main$3 = /* @__PURE__ */ defineComponent({
1390
+ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
1375
1391
  ...__default__$3,
1376
1392
  props: {
1377
1393
  useVerificationSlider: { type: Boolean }
@@ -1426,7 +1442,7 @@ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
1426
1442
  const __default__$2 = {
1427
1443
  name: "ConsentList"
1428
1444
  };
1429
- const _sfc_main$2 = /* @__PURE__ */ defineComponent({
1445
+ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
1430
1446
  ...__default__$2,
1431
1447
  props: {
1432
1448
  scopes: {},
@@ -1544,7 +1560,7 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
1544
1560
  const __default__$1 = {
1545
1561
  name: "UserMenuButton"
1546
1562
  };
1547
- const _sfc_main$1 = /* @__PURE__ */ defineComponent({
1563
+ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
1548
1564
  ...__default__$1,
1549
1565
  props: {
1550
1566
  userRoute: {}
@@ -1619,12 +1635,12 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
1619
1635
  };
1620
1636
  }
1621
1637
  });
1622
- const _hoisted_1 = { key: 0 };
1638
+ const _hoisted_1$1 = { key: 0 };
1623
1639
  const _hoisted_2 = { key: 1 };
1624
1640
  const __default__ = {
1625
1641
  name: "LoginButton"
1626
1642
  };
1627
- const _sfc_main = /* @__PURE__ */ defineComponent({
1643
+ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
1628
1644
  ...__default__,
1629
1645
  props: {
1630
1646
  withNetwork: {}
@@ -1638,29 +1654,369 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1638
1654
  loadLang($q.lang.isoName);
1639
1655
  });
1640
1656
  return (_ctx, _cache) => {
1641
- return openBlock(), createBlock(_sfc_main$c, null, {
1657
+ return openBlock(), createBlock(_sfc_main$d, null, {
1642
1658
  default: withCtx(() => [
1643
1659
  renderSlot(_ctx.$slots, "icon"),
1644
- _ctx.withNetwork ? (openBlock(), createElementBlock("div", _hoisted_1, toDisplayString(unref(lang2).login.loginWith) + " " + toDisplayString(_ctx.withNetwork), 1)) : (openBlock(), createElementBlock("div", _hoisted_2, toDisplayString(unref(lang2).login.login), 1))
1660
+ _ctx.withNetwork ? (openBlock(), createElementBlock("div", _hoisted_1$1, toDisplayString(unref(lang2).login.loginWith) + " " + toDisplayString(_ctx.withNetwork), 1)) : (openBlock(), createElementBlock("div", _hoisted_2, toDisplayString(unref(lang2).login.login), 1))
1645
1661
  ]),
1646
1662
  _: 3
1647
1663
  });
1648
1664
  };
1649
1665
  }
1650
1666
  });
1667
+ const _hoisted_1 = { class: "q-pa-sm" };
1668
+ const _sfc_main = /* @__PURE__ */ defineComponent({
1669
+ __name: "AccountsTable",
1670
+ props: {
1671
+ modelValue: {},
1672
+ count: {},
1673
+ pagination: {},
1674
+ mappedRoles: {},
1675
+ columns: {}
1676
+ },
1677
+ emits: ["update:pagination", "update:criteria", "addRole", "removeRole"],
1678
+ setup(__props, { emit: __emit }) {
1679
+ const props = __props;
1680
+ const emit = __emit;
1681
+ const { modelValue, count, mappedRoles, columns } = toRefs(props);
1682
+ const lang2 = useLang();
1683
+ const $q = useQuasar();
1684
+ const sortBy = ref(props.pagination.sortBy);
1685
+ const descending = ref(props.pagination.descending);
1686
+ const rowsPerPage = ref(props.pagination.limit);
1687
+ const page = ref(props.pagination.offset / props.pagination.limit + 1);
1688
+ const name = ref("");
1689
+ const email = ref("");
1690
+ const roles = ref([]);
1691
+ const criteria = computed(() => ({
1692
+ name: name.value,
1693
+ email: email.value,
1694
+ roles: roles.value
1695
+ }));
1696
+ const tablePagination = computed({
1697
+ // getter
1698
+ get() {
1699
+ return {
1700
+ sortBy: sortBy.value,
1701
+ descending: descending.value,
1702
+ page: page.value,
1703
+ rowsPerPage: rowsPerPage.value,
1704
+ rowsNumber: count.value || 0
1705
+ };
1706
+ },
1707
+ // setter
1708
+ set(newValue) {
1709
+ sortBy.value = newValue.sortBy;
1710
+ descending.value = newValue.descending;
1711
+ page.value = newValue.page;
1712
+ rowsPerPage.value = newValue.rowsPerPage;
1713
+ }
1714
+ });
1715
+ watch(criteria, () => emit("update:criteria", criteria.value));
1716
+ const onRequest = ({ pagination }) => {
1717
+ descending.value = pagination.descending;
1718
+ sortBy.value = pagination.sortBy;
1719
+ page.value = pagination.page;
1720
+ rowsPerPage.value = pagination.rowsPerPage;
1721
+ emit("update:pagination", {
1722
+ limit: rowsPerPage.value,
1723
+ offset: (page.value - 1) * rowsPerPage.value,
1724
+ sortBy: sortBy.value,
1725
+ descending: descending.value
1726
+ });
1727
+ return;
1728
+ };
1729
+ const accountColumns = ref([
1730
+ {
1731
+ name: "id",
1732
+ required: true,
1733
+ label: "#",
1734
+ align: "left",
1735
+ field: (row) => row.id,
1736
+ format: (val) => `${val}`,
1737
+ sortable: true
1738
+ },
1739
+ {
1740
+ name: "name",
1741
+ required: true,
1742
+ label: lang2.value.account.fields.name,
1743
+ align: "left",
1744
+ field: (row) => row.name,
1745
+ format: (val) => `${val || ""}`,
1746
+ sortable: false
1747
+ },
1748
+ {
1749
+ name: "email",
1750
+ required: true,
1751
+ label: lang2.value.account.fields.email,
1752
+ align: "left",
1753
+ field: (row) => row.email,
1754
+ format: (val) => `${val}`,
1755
+ sortable: false
1756
+ },
1757
+ {
1758
+ name: "roles",
1759
+ required: true,
1760
+ label: lang2.value.account.fields.roles,
1761
+ align: "right",
1762
+ field: (row) => row.roles,
1763
+ format: (val) => val.map((role) => mappedRoles.value[role]).join(", ")
1764
+ }
1765
+ ]);
1766
+ if (columns == null ? void 0 : columns.value)
1767
+ accountColumns.value.push(...columns.value);
1768
+ const roleOptions = computed(
1769
+ () => Object.entries(mappedRoles.value).map(([key, value]) => ({
1770
+ label: value,
1771
+ value: key
1772
+ }))
1773
+ );
1774
+ const openAddRoleDialog = (account) => {
1775
+ $q.dialog({
1776
+ message: lang2.value.account.messages.addRole(account),
1777
+ options: {
1778
+ type: "radio",
1779
+ model: "role",
1780
+ items: roleOptions.value.filter(
1781
+ (newRole) => !account.roles.includes(newRole.value)
1782
+ )
1783
+ },
1784
+ cancel: true,
1785
+ persistent: true
1786
+ }).onOk((role) => {
1787
+ emit("addRole", { id: account.id, role });
1788
+ });
1789
+ };
1790
+ const openRemoveRoleDialog = (account) => {
1791
+ var _a;
1792
+ $q.dialog({
1793
+ message: lang2.value.account.messages.removeRole(account),
1794
+ options: {
1795
+ type: "radio",
1796
+ model: "role",
1797
+ items: (_a = account.roles) == null ? void 0 : _a.map((role) => ({
1798
+ label: mappedRoles.value[role],
1799
+ value: role
1800
+ }))
1801
+ },
1802
+ cancel: true,
1803
+ persistent: true
1804
+ }).onOk((role) => {
1805
+ emit("removeRole", { id: account.id, role });
1806
+ });
1807
+ };
1808
+ return (_ctx, _cache) => {
1809
+ const _component_q_th = QTh;
1810
+ const _component_q_tr = QTr;
1811
+ const _component_q_icon = QIcon;
1812
+ const _component_q_input = QInput;
1813
+ const _component_q_select = QSelect;
1814
+ const _component_q_menu = QMenu;
1815
+ const _component_q_btn = QBtn;
1816
+ const _component_q_td = QTd;
1817
+ const _component_q_item_label = QItemLabel;
1818
+ const _component_q_item_section = QItemSection;
1819
+ const _component_q_item = QItem;
1820
+ const _component_q_list = QList;
1821
+ return unref(modelValue) ? (openBlock(), createBlock(unref(QTable), {
1822
+ key: 0,
1823
+ pagination: tablePagination.value,
1824
+ "onUpdate:pagination": _cache[6] || (_cache[6] = ($event) => tablePagination.value = $event),
1825
+ title: unref(lang2).account.title,
1826
+ class: "full-width",
1827
+ rows: unref(modelValue),
1828
+ columns: accountColumns.value,
1829
+ "row-key": "id",
1830
+ onRequest
1831
+ }, {
1832
+ header: withCtx((props2) => [
1833
+ createVNode(_component_q_tr, { props: props2 }, {
1834
+ default: withCtx(() => [
1835
+ (openBlock(true), createElementBlock(Fragment, null, renderList(props2.cols, (col) => {
1836
+ return openBlock(), createBlock(_component_q_th, {
1837
+ key: col.name,
1838
+ props: props2
1839
+ }, {
1840
+ default: withCtx(() => [
1841
+ createTextVNode(toDisplayString(col.label), 1)
1842
+ ]),
1843
+ _: 2
1844
+ }, 1032, ["props"]);
1845
+ }), 128))
1846
+ ]),
1847
+ _: 2
1848
+ }, 1032, ["props"])
1849
+ ]),
1850
+ "top-right": withCtx(() => [
1851
+ createVNode(_component_q_btn, {
1852
+ icon: "search",
1853
+ flat: ""
1854
+ }, {
1855
+ default: withCtx(() => [
1856
+ createVNode(_component_q_menu, null, {
1857
+ default: withCtx(() => [
1858
+ createElementVNode("div", _hoisted_1, [
1859
+ createVNode(_component_q_input, {
1860
+ modelValue: name.value,
1861
+ "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => name.value = $event),
1862
+ label: unref(lang2).account.fields.name
1863
+ }, {
1864
+ append: withCtx(() => [
1865
+ name.value ? (openBlock(), createBlock(_component_q_icon, {
1866
+ key: 0,
1867
+ name: "cancel",
1868
+ onClick: _cache[0] || (_cache[0] = ($event) => name.value = ""),
1869
+ class: "q-field__focusable-action",
1870
+ role: "button"
1871
+ })) : createCommentVNode("", true)
1872
+ ]),
1873
+ _: 1
1874
+ }, 8, ["modelValue", "label"]),
1875
+ createVNode(_component_q_input, {
1876
+ modelValue: email.value,
1877
+ "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => email.value = $event),
1878
+ label: unref(lang2).account.fields.email
1879
+ }, {
1880
+ append: withCtx(() => [
1881
+ email.value ? (openBlock(), createBlock(_component_q_icon, {
1882
+ key: 0,
1883
+ name: "cancel",
1884
+ onClick: _cache[2] || (_cache[2] = ($event) => email.value = ""),
1885
+ class: "q-field__focusable-action",
1886
+ role: "button"
1887
+ })) : createCommentVNode("", true)
1888
+ ]),
1889
+ _: 1
1890
+ }, 8, ["modelValue", "label"]),
1891
+ createVNode(_component_q_select, {
1892
+ modelValue: roles.value,
1893
+ "onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => roles.value = $event),
1894
+ multiple: "",
1895
+ style: { "min-width": "200px" },
1896
+ label: unref(lang2).account.fields.roles,
1897
+ options: roleOptions.value,
1898
+ "map-options": "",
1899
+ "emit-value": ""
1900
+ }, {
1901
+ append: withCtx(() => [
1902
+ roles.value.length ? (openBlock(), createBlock(_component_q_icon, {
1903
+ key: 0,
1904
+ name: "cancel",
1905
+ onClick: _cache[4] || (_cache[4] = ($event) => roles.value = []),
1906
+ class: "q-field__focusable-action",
1907
+ role: "button"
1908
+ })) : createCommentVNode("", true)
1909
+ ]),
1910
+ _: 1
1911
+ }, 8, ["modelValue", "label", "options"])
1912
+ ])
1913
+ ]),
1914
+ _: 1
1915
+ })
1916
+ ]),
1917
+ _: 1
1918
+ })
1919
+ ]),
1920
+ body: withCtx((props2) => [
1921
+ createVNode(_component_q_tr, { props: props2 }, {
1922
+ default: withCtx(() => [
1923
+ (openBlock(true), createElementBlock(Fragment, null, renderList(props2.cols, (col) => {
1924
+ return openBlock(), createBlock(_component_q_td, {
1925
+ key: col.name,
1926
+ props: props2
1927
+ }, {
1928
+ default: withCtx(() => [
1929
+ createTextVNode(toDisplayString(col.value), 1)
1930
+ ]),
1931
+ _: 2
1932
+ }, 1032, ["props"]);
1933
+ }), 128)),
1934
+ createVNode(_component_q_td, { "auto-width": "" }, {
1935
+ default: withCtx(() => [
1936
+ createVNode(_component_q_btn, {
1937
+ size: "sm",
1938
+ round: "",
1939
+ flat: "",
1940
+ icon: "more_vert"
1941
+ }, {
1942
+ default: withCtx(() => [
1943
+ createVNode(_component_q_menu, null, {
1944
+ default: withCtx(() => [
1945
+ createVNode(_component_q_list, null, {
1946
+ default: withCtx(() => [
1947
+ createVNode(_component_q_item, {
1948
+ clickable: "",
1949
+ onClick: ($event) => openAddRoleDialog(props2.row)
1950
+ }, {
1951
+ default: withCtx(() => [
1952
+ createVNode(_component_q_item_section, null, {
1953
+ default: withCtx(() => [
1954
+ createVNode(_component_q_item_label, null, {
1955
+ default: withCtx(() => [
1956
+ createTextVNode(toDisplayString(unref(lang2).account.labels.addRole), 1)
1957
+ ]),
1958
+ _: 1
1959
+ })
1960
+ ]),
1961
+ _: 1
1962
+ })
1963
+ ]),
1964
+ _: 2
1965
+ }, 1032, ["onClick"]),
1966
+ createVNode(_component_q_item, {
1967
+ clickable: "",
1968
+ onClick: ($event) => openRemoveRoleDialog(props2.row)
1969
+ }, {
1970
+ default: withCtx(() => [
1971
+ createVNode(_component_q_item_section, null, {
1972
+ default: withCtx(() => [
1973
+ createVNode(_component_q_item_label, null, {
1974
+ default: withCtx(() => [
1975
+ createTextVNode(toDisplayString(unref(lang2).account.labels.removeRole), 1)
1976
+ ]),
1977
+ _: 1
1978
+ })
1979
+ ]),
1980
+ _: 1
1981
+ })
1982
+ ]),
1983
+ _: 2
1984
+ }, 1032, ["onClick"])
1985
+ ]),
1986
+ _: 2
1987
+ }, 1024)
1988
+ ]),
1989
+ _: 2
1990
+ }, 1024)
1991
+ ]),
1992
+ _: 2
1993
+ }, 1024)
1994
+ ]),
1995
+ _: 2
1996
+ }, 1024)
1997
+ ]),
1998
+ _: 2
1999
+ }, 1032, ["props"])
2000
+ ]),
2001
+ _: 1
2002
+ }, 8, ["pagination", "title", "rows", "columns"])) : createCommentVNode("", true);
2003
+ };
2004
+ }
2005
+ });
1651
2006
  export {
1652
- _sfc_main$2 as ConsentList,
1653
- _sfc_main$9 as EmailChangeForm,
1654
- _sfc_main$8 as EmailChangeStepper,
1655
- _sfc_main as LoginButton,
1656
- _sfc_main$5 as LoginForm,
1657
- _sfc_main$a as OtpInput,
1658
- _sfc_main$7 as PasswordChangeForm,
1659
- _sfc_main$6 as PasswordChangeStepper,
1660
- _sfc_main$4 as RegisterForm,
1661
- _sfc_main$b as RequestOtpForm,
1662
- _sfc_main$1 as UserMenuButton,
1663
- _sfc_main$3 as VerificationSlider,
2007
+ _sfc_main as AccountsTable,
2008
+ _sfc_main$3 as ConsentList,
2009
+ _sfc_main$a as EmailChangeForm,
2010
+ _sfc_main$9 as EmailChangeStepper,
2011
+ _sfc_main$1 as LoginButton,
2012
+ _sfc_main$6 as LoginForm,
2013
+ _sfc_main$b as OtpInput,
2014
+ _sfc_main$8 as PasswordChangeForm,
2015
+ _sfc_main$7 as PasswordChangeStepper,
2016
+ _sfc_main$5 as RegisterForm,
2017
+ _sfc_main$c as RequestOtpForm,
2018
+ _sfc_main$2 as UserMenuButton,
2019
+ _sfc_main$4 as VerificationSlider,
1664
2020
  loadLang,
1665
2021
  useLang
1666
2022
  };
@@ -85,6 +85,22 @@ const lang = {
85
85
  },
86
86
  verification: {
87
87
  slider: "Sleep a.u.b. het onderstaande bolletje helemaal naar rechts."
88
+ },
89
+ account: {
90
+ title: "Accounts",
91
+ fields: {
92
+ name: "Naam",
93
+ email: "Email",
94
+ roles: "Rollen"
95
+ },
96
+ labels: {
97
+ addRole: "Rol toevoegen",
98
+ removeRole: "Rol verwijderen"
99
+ },
100
+ messages: {
101
+ addRole: ({ email }) => `Selecteer de rol die u wilt toevoegen aan ${email}.`,
102
+ removeRole: ({ email }) => `Selecteer de rol die u wilt verwijderen van ${email}.`
103
+ }
88
104
  }
89
105
  };
90
106
  export {
@@ -18,7 +18,6 @@ declare const _default: import("vue").DefineComponent<__VLS_TypePropsToOption<Pr
18
18
  functions: import("vue").Ref<{}>;
19
19
  }, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<__VLS_TypePropsToOption<Props>>>, {}, {}>;
20
20
  export default _default;
21
-
22
21
  type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
23
22
  type __VLS_TypePropsToOption<T> = {
24
23
  [K in keyof T]-?: {} extends Pick<T, K> ? {
@@ -10,4 +10,5 @@ export { default as VerificationSlider } from './VerificationSlider.vue';
10
10
  export { default as ConsentList } from './ConsentList.vue';
11
11
  export { default as UserMenuButton } from './UserMenuButton.vue';
12
12
  export { default as LoginButton } from './LoginButton.vue';
13
+ export { default as AccountsTable } from './AccountsTable.vue';
13
14
  export { useLang, loadLang } from './lang/index.js';
@@ -86,6 +86,26 @@ export interface Language {
86
86
  verification: {
87
87
  slider: string;
88
88
  };
89
+ account: {
90
+ title: string;
91
+ fields: {
92
+ name: string;
93
+ email: string;
94
+ roles: string;
95
+ };
96
+ labels: {
97
+ addRole: string;
98
+ removeRole: string;
99
+ };
100
+ messages: {
101
+ addRole: ({ email }: {
102
+ email: string;
103
+ }) => string;
104
+ removeRole: ({ email }: {
105
+ email: string;
106
+ }) => string;
107
+ };
108
+ };
89
109
  }
90
110
  import type { Ref } from 'vue';
91
111
  export declare const lang: Ref<{
@@ -176,6 +196,26 @@ export declare const lang: Ref<{
176
196
  verification: {
177
197
  slider: string;
178
198
  };
199
+ account: {
200
+ title: string;
201
+ fields: {
202
+ name: string;
203
+ email: string;
204
+ roles: string;
205
+ };
206
+ labels: {
207
+ addRole: string;
208
+ removeRole: string;
209
+ };
210
+ messages: {
211
+ addRole: ({ email }: {
212
+ email: string;
213
+ }) => string;
214
+ removeRole: ({ email }: {
215
+ email: string;
216
+ }) => string;
217
+ };
218
+ };
179
219
  }>;
180
220
  export declare const defineLang: (lang: Language) => Language;
181
221
  export declare const useLang: () => Ref<Language>;
@@ -2,7 +2,7 @@ import { QDateProps, QuasarLanguageCodes } from 'quasar';
2
2
  export interface Props {
3
3
  modelValue: string | null;
4
4
  format?: 'YYYY-MM-DD' | 'DD-MM-YYYY' | 'MM-DD-YYYY';
5
- locale?: QuasarLanguageCodes;
5
+ locale?: QuasarLanguageCodes[number];
6
6
  label?: string;
7
7
  required?: boolean;
8
8
  clearable?: boolean;
@@ -24,9 +24,9 @@ declare const _default: import("vue").DefineComponent<__VLS_WithDefaults<__VLS_T
24
24
  "onUpdate:modelValue"?: ((val: string | null) => any) | undefined;
25
25
  }, {
26
26
  label: string;
27
- date: Partial<QDateProps>;
28
- locale: keyof import("quasar").QuasarLanguageCodesHolder;
29
27
  format: "YYYY-MM-DD" | "DD-MM-YYYY" | "MM-DD-YYYY";
28
+ date: Partial<QDateProps>;
29
+ locale: string;
30
30
  }, {}>;
31
31
  export default _default;
32
32
  type __VLS_WithDefaults<P, D> = {
@@ -20,7 +20,6 @@ declare const _default: <T extends {
20
20
  hint?: string | undefined;
21
21
  } & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, __VLS_ctx?: {
22
22
  attrs: any;
23
- slots: Partial<Record<NonNullable<string | number>, (_: any) => any>>;
24
23
  emit: {
25
24
  (e: 'update:model-value', id: number): void;
26
25
  (e: 'filter', { ids, searchPhrase, done }: {
@@ -29,6 +28,7 @@ declare const _default: <T extends {
29
28
  done: (success?: boolean) => void;
30
29
  }): void;
31
30
  };
31
+ slots: Partial<Record<NonNullable<string | number>, (_: any) => any>>;
32
32
  } | undefined, __VLS_expose?: ((exposed: import('vue').ShallowUnwrapRef<{}>) => void) | undefined, __VLS_setup?: Promise<{
33
33
  props: {
34
34
  onFilter?: ((args_0: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simsustech/quasar-components",
3
- "version": "0.8.1",
3
+ "version": "0.9.0",
4
4
  "author": "Stefan van Herwijnen",
5
5
  "description": "High level components for Quasar Framework",
6
6
  "license": "MIT",
@@ -0,0 +1,279 @@
1
+ <template>
2
+ <q-table
3
+ v-if="modelValue"
4
+ v-model:pagination="tablePagination"
5
+ :title="lang.account.title"
6
+ class="full-width"
7
+ :rows="modelValue"
8
+ :columns="accountColumns"
9
+ row-key="id"
10
+ @request="onRequest"
11
+ >
12
+ <template #header="props">
13
+ <q-tr :props="props">
14
+ <q-th v-for="col in props.cols" :key="col.name" :props="props">
15
+ {{ col.label }}
16
+ </q-th>
17
+ </q-tr>
18
+ </template>
19
+ <template #top-right>
20
+ <q-btn icon="search" flat>
21
+ <q-menu>
22
+ <div class="q-pa-sm">
23
+ <q-input v-model="name" :label="lang.account.fields.name">
24
+ <template #append>
25
+ <q-icon
26
+ v-if="name"
27
+ name="cancel"
28
+ @click="name = ''"
29
+ class="q-field__focusable-action"
30
+ role="button"
31
+ />
32
+ </template>
33
+ </q-input>
34
+ <q-input v-model="email" :label="lang.account.fields.email">
35
+ <template #append>
36
+ <q-icon
37
+ v-if="email"
38
+ name="cancel"
39
+ @click="email = ''"
40
+ class="q-field__focusable-action"
41
+ role="button"
42
+ />
43
+ </template>
44
+ </q-input>
45
+
46
+ <q-select
47
+ v-model="roles"
48
+ multiple
49
+ style="min-width: 200px"
50
+ :label="lang.account.fields.roles"
51
+ :options="roleOptions"
52
+ map-options
53
+ emit-value
54
+ >
55
+ <template #append>
56
+ <q-icon
57
+ v-if="roles.length"
58
+ name="cancel"
59
+ @click="roles = []"
60
+ class="q-field__focusable-action"
61
+ role="button"
62
+ />
63
+ </template>
64
+ </q-select>
65
+ </div>
66
+ </q-menu>
67
+ </q-btn>
68
+ </template>
69
+ <template #body="props">
70
+ <q-tr :props="props">
71
+ <q-td v-for="col in props.cols" :key="col.name" :props="props">
72
+ {{ col.value }}
73
+ </q-td>
74
+ <q-td auto-width>
75
+ <q-btn size="sm" round flat icon="more_vert">
76
+ <q-menu>
77
+ <q-list>
78
+ <q-item clickable @click="openAddRoleDialog(props.row)">
79
+ <q-item-section>
80
+ <q-item-label>
81
+ {{ lang.account.labels.addRole }}
82
+ </q-item-label>
83
+ </q-item-section>
84
+ </q-item>
85
+ <q-item clickable @click="openRemoveRoleDialog(props.row)">
86
+ <q-item-section>
87
+ <q-item-label>
88
+ {{ lang.account.labels.removeRole }}
89
+ </q-item-label>
90
+ </q-item-section>
91
+ </q-item>
92
+ </q-list>
93
+ </q-menu>
94
+ </q-btn>
95
+ </q-td>
96
+ </q-tr>
97
+ </template>
98
+ </q-table>
99
+ </template>
100
+
101
+ <script lang="ts" setup generic="T extends Account">
102
+ import { computed, ref, toRefs, watch } from 'vue'
103
+ import { QTable, QTableColumn, useQuasar } from 'quasar'
104
+ import { useLang } from './lang/index.js'
105
+
106
+ export interface Account {
107
+ id: number
108
+ name?: string
109
+ email: string
110
+ roles: string[]
111
+ }
112
+
113
+ interface Pagination {
114
+ limit: number
115
+ offset: number
116
+ sortBy: keyof Account
117
+ descending: boolean
118
+ }
119
+
120
+ interface Criteria {
121
+ roles: string[]
122
+ }
123
+ interface Props {
124
+ modelValue: T[]
125
+ count: number
126
+ pagination: Pagination
127
+ mappedRoles: Record<string, string> // value: label
128
+ columns?: QTableColumn[]
129
+ }
130
+
131
+ const props = defineProps<Props>()
132
+
133
+ const emit = defineEmits<{
134
+ (e: 'update:pagination', pagination: Pagination): void
135
+ (e: 'update:criteria', criteria: Criteria): void
136
+ (e: 'addRole', { id, role }: { id: number; role: string }): void
137
+ (e: 'removeRole', { id, role }: { id: number; role: string }): void
138
+ }>()
139
+
140
+ const { modelValue, count, mappedRoles, columns } = toRefs(props)
141
+
142
+ // const { useQuery } = await createUseTrpc()
143
+ const lang = useLang()
144
+ const $q = useQuasar()
145
+
146
+ const sortBy = ref<keyof Account>(props.pagination.sortBy)
147
+ const descending = ref(props.pagination.descending)
148
+ const rowsPerPage = ref(props.pagination.limit)
149
+ const page = ref(props.pagination.offset / props.pagination.limit + 1)
150
+
151
+ const name = ref<string>('')
152
+ const email = ref<string>('')
153
+ const roles = ref<string[]>([])
154
+ const criteria = computed(() => ({
155
+ name: name.value,
156
+ email: email.value,
157
+ roles: roles.value
158
+ }))
159
+
160
+ const tablePagination = computed({
161
+ // getter
162
+ get() {
163
+ return {
164
+ sortBy: sortBy.value,
165
+ descending: descending.value,
166
+ page: page.value,
167
+ rowsPerPage: rowsPerPage.value,
168
+ rowsNumber: count.value || 0
169
+ }
170
+ },
171
+ // setter
172
+ set(newValue) {
173
+ sortBy.value = newValue.sortBy
174
+ descending.value = newValue.descending
175
+ page.value = newValue.page
176
+ rowsPerPage.value = newValue.rowsPerPage
177
+ }
178
+ })
179
+
180
+ watch(criteria, () => emit('update:criteria', criteria.value))
181
+
182
+ const onRequest: QTable['$props']['onRequest'] = ({ pagination }) => {
183
+ descending.value = pagination.descending
184
+ sortBy.value = pagination.sortBy as keyof Account
185
+ page.value = pagination.page
186
+ rowsPerPage.value = pagination.rowsPerPage
187
+
188
+ emit('update:pagination', {
189
+ limit: rowsPerPage.value,
190
+ offset: (page.value - 1) * rowsPerPage.value,
191
+ sortBy: sortBy.value as keyof Account,
192
+ descending: descending.value
193
+ })
194
+ return
195
+ }
196
+
197
+ const accountColumns = ref<QTableColumn[]>([
198
+ {
199
+ name: 'id',
200
+ required: true,
201
+ label: '#',
202
+ align: 'left',
203
+ field: (row) => row.id,
204
+ format: (val) => `${val}`,
205
+ sortable: true
206
+ },
207
+ {
208
+ name: 'name',
209
+ required: true,
210
+ label: lang.value.account.fields.name,
211
+ align: 'left',
212
+ field: (row) => row.name,
213
+ format: (val) => `${val || ''}`,
214
+ sortable: false
215
+ },
216
+ {
217
+ name: 'email',
218
+ required: true,
219
+ label: lang.value.account.fields.email,
220
+ align: 'left',
221
+ field: (row) => row.email,
222
+ format: (val) => `${val}`,
223
+ sortable: false
224
+ },
225
+ {
226
+ name: 'roles',
227
+ required: true,
228
+ label: lang.value.account.fields.roles,
229
+ align: 'right',
230
+ field: (row) => row.roles,
231
+ format: (val) =>
232
+ val.map((role: string) => mappedRoles.value[role]).join(', ')
233
+ }
234
+ ])
235
+
236
+ if (columns?.value) accountColumns.value.push(...columns.value)
237
+
238
+ const roleOptions = computed(() =>
239
+ Object.entries(mappedRoles.value).map(([key, value]) => ({
240
+ label: value,
241
+ value: key
242
+ }))
243
+ )
244
+
245
+ const openAddRoleDialog = (account: Account) => {
246
+ $q.dialog({
247
+ message: lang.value.account.messages.addRole(account),
248
+ options: {
249
+ type: 'radio',
250
+ model: 'role',
251
+ items: roleOptions.value.filter(
252
+ (newRole) => !account.roles.includes(newRole.value)
253
+ )
254
+ },
255
+ cancel: true,
256
+ persistent: true
257
+ }).onOk((role: string) => {
258
+ emit('addRole', { id: account.id, role })
259
+ })
260
+ }
261
+
262
+ const openRemoveRoleDialog = (account: Account) => {
263
+ $q.dialog({
264
+ message: lang.value.account.messages.removeRole(account),
265
+ options: {
266
+ type: 'radio',
267
+ model: 'role',
268
+ items: account.roles?.map((role) => ({
269
+ label: mappedRoles.value[role],
270
+ value: role
271
+ }))
272
+ },
273
+ cancel: true,
274
+ persistent: true
275
+ }).onOk((role) => {
276
+ emit('removeRole', { id: account.id, role })
277
+ })
278
+ }
279
+ </script>
@@ -10,4 +10,5 @@ export { default as VerificationSlider } from './VerificationSlider.vue'
10
10
  export { default as ConsentList } from './ConsentList.vue'
11
11
  export { default as UserMenuButton } from './UserMenuButton.vue'
12
12
  export { default as LoginButton } from './LoginButton.vue'
13
+ export { default as AccountsTable } from './AccountsTable.vue'
13
14
  export { useLang, loadLang } from './lang/index.js'
@@ -90,6 +90,24 @@ const lang: Language = {
90
90
  },
91
91
  verification: {
92
92
  slider: 'Please drag the slider below all the way to the right.'
93
+ },
94
+ account: {
95
+ title: 'Accounts',
96
+ fields: {
97
+ name: 'Name',
98
+ email: 'Email',
99
+ roles: 'Roles'
100
+ },
101
+ labels: {
102
+ addRole: 'Add role',
103
+ removeRole: 'Remove role'
104
+ },
105
+ messages: {
106
+ addRole: ({ email }) =>
107
+ `Select the role which you want to add to ${email}.`,
108
+ removeRole: ({ email }) =>
109
+ `Select the role which you want to remove from ${email}.`
110
+ }
93
111
  }
94
112
  }
95
113
 
@@ -86,6 +86,22 @@ export interface Language {
86
86
  verification: {
87
87
  slider: string
88
88
  }
89
+ account: {
90
+ title: string
91
+ fields: {
92
+ name: string
93
+ email: string
94
+ roles: string
95
+ }
96
+ labels: {
97
+ addRole: string
98
+ removeRole: string
99
+ }
100
+ messages: {
101
+ addRole: ({ email }: { email: string }) => string
102
+ removeRole: ({ email }: { email: string }) => string
103
+ }
104
+ }
89
105
  }
90
106
 
91
107
  import type { Ref } from 'vue'
@@ -90,6 +90,24 @@ const lang: Language = {
90
90
  },
91
91
  verification: {
92
92
  slider: 'Sleep a.u.b. het onderstaande bolletje helemaal naar rechts.'
93
+ },
94
+ account: {
95
+ title: 'Accounts',
96
+ fields: {
97
+ name: 'Naam',
98
+ email: 'Email',
99
+ roles: 'Rollen'
100
+ },
101
+ labels: {
102
+ addRole: 'Rol toevoegen',
103
+ removeRole: 'Rol verwijderen'
104
+ },
105
+ messages: {
106
+ addRole: ({ email }) =>
107
+ `Selecteer de rol die u wilt toevoegen aan ${email}.`,
108
+ removeRole: ({ email }) =>
109
+ `Selecteer de rol die u wilt verwijderen van ${email}.`
110
+ }
93
111
  }
94
112
  }
95
113
 
@@ -68,7 +68,7 @@ import { useLang } from './lang'
68
68
  export interface Props {
69
69
  modelValue: string | null
70
70
  format?: 'YYYY-MM-DD' | 'DD-MM-YYYY' | 'MM-DD-YYYY'
71
- locale?: QuasarLanguageCodes
71
+ locale?: QuasarLanguageCodes[number]
72
72
  label?: string
73
73
  required?: boolean
74
74
  clearable?: boolean