@adminforth/crud-approve-plugin 1.0.21 → 1.1.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/build.log CHANGED
@@ -4,6 +4,7 @@
4
4
 
5
5
  sending incremental file list
6
6
  custom/
7
+ custom/ApprovalDiff.vue
7
8
  custom/ListPageDiffView.vue
8
9
  custom/ShowPageDiffView.vue
9
10
  custom/package-lock.json
@@ -11,5 +12,5 @@ custom/package.json
11
12
  custom/pnpm-lock.yaml
12
13
  custom/tsconfig.json
13
14
 
14
- sent 32,790 bytes received 134 bytes 65,848.00 bytes/sec
15
- total size is 32,287 speedup is 0.98
15
+ sent 35,137 bytes received 153 bytes 70,580.00 bytes/sec
16
+ total size is 34,571 speedup is 0.98
@@ -0,0 +1,192 @@
1
+ <script setup>
2
+ import { useCoreStore } from '@/stores/core';
3
+ import { computed, ref, watch, defineAsyncComponent, onMounted, useTemplateRef } from 'vue';
4
+ import { useElementSize } from '@vueuse/core';
5
+ import { useI18n } from 'vue-i18n';
6
+ import { callAdminForthApi } from '@/utils';
7
+ import adminforth from '@/adminforth';
8
+ import { Button } from '@/afcl';
9
+
10
+ const DiffView = defineAsyncComponent(async () => {
11
+ // pure styles come without tailwind preflight, which would otherwise reset fonts of the whole SPA
12
+ await import("@git-diff-view/vue/styles/diff-view-pure.css");
13
+ const { DiffView } = await import("@git-diff-view/vue");
14
+ return DiffView;
15
+ });
16
+
17
+ // old and new records go side by side only when the container fits two JSON columns
18
+ const SPLIT_MIN_WIDTH_PX = 768;
19
+ const PENDING_STATUS = 1;
20
+
21
+ const props = defineProps({
22
+ record: Object,
23
+ meta: Object,
24
+ resource: Object,
25
+ // only for a container whose width does not follow its content, a table cell of auto layout would toggle the modes
26
+ splitWhenWide: Boolean,
27
+ });
28
+ const emit = defineEmits(['decided']);
29
+ const { t } = useI18n();
30
+ const coreStore = useCoreStore();
31
+ const theme = computed(() => coreStore.theme === 'dark' ? 'dark' : 'light');
32
+
33
+ const { oldRecord, newRecord } = props.record[props.meta.resourceColumns.dataColumnName];
34
+ const oldContent = JSON.stringify(oldRecord, null, 2);
35
+ const newContent = JSON.stringify(newRecord, null, 2);
36
+ const hasChanges = oldContent !== newContent;
37
+ const isPending = props.record[props.meta.resourceColumns.statusColumnName] === PENDING_STATUS;
38
+
39
+ const { width } = useElementSize(useTemplateRef('container'));
40
+ const split = computed(() => props.splitWhenWide && width.value >= SPLIT_MIN_WIDTH_PX);
41
+
42
+ const diffFile = ref();
43
+ const diffModes = ref();
44
+ const sending = ref(null);
45
+
46
+ function buildDiffLines() {
47
+ if (split.value) {
48
+ diffFile.value.buildSplitDiffLines();
49
+ } else {
50
+ diffFile.value.buildUnifiedDiffLines();
51
+ }
52
+ }
53
+
54
+ onMounted(async () => {
55
+ if (!hasChanges) {
56
+ return;
57
+ }
58
+ const { DiffModeEnum } = await import("@git-diff-view/vue");
59
+ const { generateDiffFile } = await import("@git-diff-view/file");
60
+ diffModes.value = DiffModeEnum;
61
+ const file = generateDiffFile('diff.json', oldContent, 'diff.json', newContent, 'json', 'json');
62
+ file.initTheme(theme.value);
63
+ file.init();
64
+ diffFile.value = file;
65
+ buildDiffLines();
66
+ });
67
+
68
+ watch([split, theme], () => {
69
+ if (!diffFile.value) return;
70
+ diffFile.value.initTheme(theme.value);
71
+ buildDiffLines();
72
+ });
73
+
74
+ async function sendApproveRequest(approved) {
75
+ sending.value = approved ? 'approve' : 'reject';
76
+ const data = await callAdminForthApi({
77
+ path: `/plugin/crud-approve/update-status`,
78
+ method: 'POST',
79
+ body: {
80
+ connectorId: props.resource.connectorId,
81
+ resourceId: props.resource.resourceId,
82
+ action: props.record[props.meta.resourceColumns.actionColumnName],
83
+ recordId: props.record[props.meta.resourceColumns.recordIdColumnName],
84
+ diffId: props.record[props.meta.resourceColumns.idColumnName],
85
+ approved: approved
86
+ }
87
+ });
88
+ sending.value = null;
89
+ if (data.error && data.error !== 'Operation aborted by hook') {
90
+ adminforth.alert({ message: t('Error: {error}', { error: data.error }), variant: 'danger' });
91
+ } else {
92
+ adminforth.alert({ message: approved ? t('Change approved') : t('Change rejected'), variant: 'success' });
93
+ emit('decided');
94
+ }
95
+ }
96
+ </script>
97
+
98
+ <template>
99
+ <div ref="container" class="af-crud-approve">
100
+ <div
101
+ v-if="diffFile"
102
+ class="af-crud-approve-diff overflow-hidden rounded-default border border-lightCardBorder dark:border-darkCardBorder"
103
+ >
104
+ <DiffView
105
+ :diff-file="diffFile"
106
+ :diff-view-mode="split ? diffModes.Split : diffModes.Unified"
107
+ :diff-view-theme="theme"
108
+ :diff-view-highlight="true"
109
+ :diff-view-wrap="true"
110
+ :diff-view-font-size="13"
111
+ />
112
+ </div>
113
+ <p v-else-if="!hasChanges" class="text-lightInputPlaceholderText dark:text-darkInputPlaceholderText">
114
+ {{ $t('No changes to display') }}
115
+ </p>
116
+ <div v-if="isPending" class="af-crud-approve-actions mt-4 flex gap-2">
117
+ <Button
118
+ class="af-crud-approve-approve-button flex-1"
119
+ :loader="sending === 'approve'"
120
+ :disabled="!!sending"
121
+ @click="sendApproveRequest(true)"
122
+ >
123
+ {{ $t('Approve') }}
124
+ </Button>
125
+ <Button
126
+ class="af-crud-approve-reject-button flex-1"
127
+ variant="danger"
128
+ :loader="sending === 'reject'"
129
+ :disabled="!!sending"
130
+ @click="sendApproveRequest(false)"
131
+ >
132
+ {{ $t('Reject') }}
133
+ </Button>
134
+ </div>
135
+ </div>
136
+ </template>
137
+
138
+ <style>
139
+ /* the diff view sets Menlo inline on the tables of both modes */
140
+ .af-crud-approve-diff .diff-table-scroll-container,
141
+ .af-crud-approve-diff .diff-table-wrapper {
142
+ font-family: theme('fontFamily.mono') !important;
143
+ }
144
+
145
+ .af-crud-approve-diff .diff-tailwindcss-wrapper[data-theme="light"] .diff-style-root {
146
+ --diff-border--: theme('colors.lightCardBorder');
147
+ --diff-plain-content--: theme('colors.lightCardBackground');
148
+ --diff-plain-lineNumber--: theme('colors.lightCardBackground');
149
+ --diff-plain-lineNumber-color--: theme('colors.lightInputPlaceholderText');
150
+ --diff-expand-content--: theme('colors.lightCardBackgroundHover');
151
+ --diff-expand-lineNumber--: theme('colors.lightCardBackgroundHover');
152
+ --diff-expand-lineNumber-color--: theme('colors.lightInputPlaceholderText');
153
+ --diff-empty-content--: theme('colors.lightCardBackgroundHover');
154
+ --diff-hunk-content--: theme('colors.lightCardBackgroundHover');
155
+ --diff-hunk-lineNumber--: theme('colors.lightCardBackgroundHover');
156
+ --diff-hunk-lineNumber-hover--: theme('colors.lightPrimary');
157
+ --diff-hunk-content-color--: theme('colors.lightShowTableUnderHeadingText');
158
+ --diff-add-widget--: theme('colors.lightPrimary');
159
+ --diff-add-widget-color--: theme('colors.lightPrimaryContrast');
160
+ --diff-add-content--: theme('colors.lightSuccessSoft');
161
+ --diff-add-lineNumber--: theme('colors.lightSuccessSoft');
162
+ --diff-add-content-highlight--: theme('colors.lightSuccessBorder');
163
+ --diff-del-content--: theme('colors.lightDangerSoft');
164
+ --diff-del-lineNumber--: theme('colors.lightDangerSoft');
165
+ --diff-del-content-highlight--: theme('colors.lightDangerBorder');
166
+ color: theme('colors.lightShowTableBodyText');
167
+ }
168
+
169
+ .af-crud-approve-diff .diff-tailwindcss-wrapper[data-theme="dark"] .diff-style-root {
170
+ --diff-border--: theme('colors.darkCardBorder');
171
+ --diff-plain-content--: theme('colors.darkCardBackground');
172
+ --diff-plain-lineNumber--: theme('colors.darkCardBackground');
173
+ --diff-plain-lineNumber-color--: theme('colors.darkInputPlaceholderText');
174
+ --diff-expand-content--: theme('colors.darkCardBackgroundHover');
175
+ --diff-expand-lineNumber--: theme('colors.darkCardBackgroundHover');
176
+ --diff-expand-lineNumber-color--: theme('colors.darkInputPlaceholderText');
177
+ --diff-empty-content--: theme('colors.darkCardBackgroundHover');
178
+ --diff-hunk-content--: theme('colors.darkCardBackgroundHover');
179
+ --diff-hunk-lineNumber--: theme('colors.darkCardBackgroundHover');
180
+ --diff-hunk-lineNumber-hover--: theme('colors.darkPrimary');
181
+ --diff-hunk-content-color--: theme('colors.darkShowTableUnderHeadingText');
182
+ --diff-add-widget--: theme('colors.darkPrimary');
183
+ --diff-add-widget-color--: theme('colors.darkPrimaryContrast');
184
+ --diff-add-content--: theme('colors.darkSuccessSoft');
185
+ --diff-add-lineNumber--: theme('colors.darkSuccessSoft');
186
+ --diff-add-content-highlight--: theme('colors.darkSuccessBorder');
187
+ --diff-del-content--: theme('colors.darkDangerSoft');
188
+ --diff-del-lineNumber--: theme('colors.darkDangerSoft');
189
+ --diff-del-content-highlight--: theme('colors.darkDangerBorder');
190
+ color: theme('colors.darkShowTableBodyText');
191
+ }
192
+ </style>
@@ -1,84 +1,10 @@
1
1
  <script setup>
2
- import { useCoreStore } from '@/stores/core';
3
- import { computed, ref, watch } from 'vue';
4
- import "@git-diff-view/vue/styles/diff-view.css";
5
- import { DiffView, DiffModeEnum } from "@git-diff-view/vue";
6
- import { generateDiffFile } from "@git-diff-view/file";
7
- import { callAdminForthApi } from '@/utils';
8
2
  import adminforth from '@/adminforth';
9
- import { Button } from '@/afcl'
10
-
3
+ import ApprovalDiff from './ApprovalDiff.vue';
11
4
 
12
5
  const props = defineProps(['column', 'record', 'meta', 'resource', 'adminUser']);
13
- const coreStore = useCoreStore();
14
- const theme = computed(() => coreStore.theme);
15
-
16
- const oldContent = JSON.stringify(props.record[props.meta.resourceColumns.dataColumnName].oldRecord, null, 2)
17
- const newContent = JSON.stringify(props.record[props.meta.resourceColumns.dataColumnName].newRecord, null, 2)
18
- const hasChanges = oldContent !== newContent;
19
-
20
- const diffFile = ref();
21
-
22
-
23
- async function sendApproveRequest(approved) {
24
- const data = await callAdminForthApi({
25
- path: `/plugin/crud-approve/update-status`,
26
- method: 'POST',
27
- body: {
28
- connectorId: props.resource.connectorId,
29
- resourceId: props.resource.resourceId,
30
- action: props.record[props.meta.resourceColumns.actionColumnName],
31
- recordId: props.record[props.meta.resourceColumns.recordIdColumnName],
32
- diffId: props.record[props.meta.resourceColumns.idColumnName],
33
- approved: approved
34
- }
35
- });
36
- if (data.error && data.error !== 'Operation aborted by hook') {
37
- adminforth.alert({ message: `Error: ${data.error}`, variant: 'warning' });
38
- } else {
39
- adminforth.alert({ message: `Successfully ${approved ? 'approved' : 'rejected'} the change.`, variant: 'success' });
40
- // reload page
41
- adminforth.list.refresh();
42
- }
43
- }
44
-
45
- function initDiffFile() {
46
- const file = generateDiffFile(
47
- 'diff.json', oldContent,
48
- 'diff.json', newContent,
49
- 'json', 'json'
50
- );
51
- file.initTheme(theme.value === 'dark' ? 'dark' : 'light');
52
- file.init();
53
- file.buildUnifiedDiffLines();
54
- diffFile.value = file;
55
- }
56
-
57
- if (hasChanges) {
58
- initDiffFile();
59
- }
60
-
61
- watch([theme], ([t]) => {
62
- if (!diffFile.value) return;
63
- diffFile.value.initTheme(t === 'dark' ? 'dark' : 'light');
64
- diffFile.value.buildUnifiedDiffLines();
65
- });
66
-
67
6
  </script>
68
7
 
69
8
  <template>
70
- <DiffView
71
- v-if="hasChanges"
72
- :diff-file="diffFile"
73
- :diff-view-mode="DiffModeEnum.Unified"
74
- :diff-view-theme="theme === 'dark' ? 'dark' : 'light'"
75
- :diff-view-highlight="true"
76
- :diff-view-wrap="true"
77
- :diff-view-font-size="14"
78
- />
79
- <div v-else>No changes</div>
80
- <div v-if="record[meta.resourceColumns.statusColumnName] === 1" style="margin-top: 16px; display: flex; gap: 8px;">
81
- <Button style="background-color: green; color: white;" @click="sendApproveRequest(true)" :loader="false" class="w-full">Approve</Button>
82
- <Button style="background-color: red; color: white;" @click="sendApproveRequest(false)" :loader="false" class="w-full">Reject</Button>
83
- </div>
9
+ <ApprovalDiff :record="record" :meta="meta" :resource="resource" @decided="adminforth.list.refresh()" />
84
10
  </template>
@@ -1,93 +1,17 @@
1
1
  <script setup>
2
- import { useCoreStore } from '@/stores/core';
3
- import { computed, ref, watch } from 'vue';
4
- import "@git-diff-view/vue/styles/diff-view.css";
5
- import { DiffView, DiffModeEnum } from "@git-diff-view/vue";
6
- import { generateDiffFile } from "@git-diff-view/file";
7
- import { callAdminForthApi } from '@/utils';
8
- import adminforth from '@/adminforth';
9
- import { Button } from '@/afcl'
10
2
  import { useRouter } from 'vue-router';
3
+ import ApprovalDiff from './ApprovalDiff.vue';
11
4
 
12
5
  const router = useRouter();
13
6
  const props = defineProps(['column', 'record', 'meta', 'resource', 'adminUser']);
14
- const coreStore = useCoreStore();
15
- const theme = computed(() => coreStore.theme);
16
- const isMobile = computed(() => /(Android|iPhone|iPad|iPod)/i.test(navigator.userAgent));
17
- const mode = computed(() => isMobile.value ? DiffModeEnum.Unified : DiffModeEnum.Split);
18
-
19
- const oldContent = JSON.stringify(props.record[props.meta.resourceColumns.dataColumnName].oldRecord, null, 2)
20
- const newContent = JSON.stringify(props.record[props.meta.resourceColumns.dataColumnName].newRecord, null, 2)
21
- const hasChanges = oldContent !== newContent;
22
-
23
- const diffFile = ref();
24
-
25
- async function sendApproveRequest(approved) {
26
- const data = await callAdminForthApi({
27
- path: `/plugin/crud-approve/update-status`,
28
- method: 'POST',
29
- body: {
30
- connectorId: props.resource.connectorId,
31
- resourceId: props.resource.resourceId,
32
- action: props.record[props.meta.resourceColumns.actionColumnName],
33
- recordId: props.record[props.meta.resourceColumns.recordIdColumnName],
34
- diffId: props.record[props.meta.resourceColumns.idColumnName],
35
- approved: approved
36
- }
37
- });
38
- if (data.error && data.error !== 'Operation aborted by hook') {
39
- adminforth.alert({ message: `Error: ${data.error}`, variant: 'warning' });
40
- } else {
41
- adminforth.alert({ message: `Successfully ${approved ? 'approved' : 'rejected'} the change.`, variant: 'success' });
42
- router.push(router.currentRoute.value.fullPath.split('/show')[0]);
43
- }
44
- }
45
-
46
- function initDiffFile() {
47
- const file = generateDiffFile(
48
- 'diff.json', oldContent,
49
- 'diff.json', newContent,
50
- 'json', 'json'
51
- );
52
- file.initTheme(theme.value === 'dark' ? 'dark' : 'light');
53
- file.init();
54
- if (mode.value === DiffModeEnum.Split) {
55
- file.buildSplitDiffLines();
56
- } else {
57
- file.buildUnifiedDiffLines();
58
- }
59
- diffFile.value = file;
60
- }
61
-
62
- if (hasChanges) {
63
- initDiffFile();
64
- }
65
-
66
- watch([mode, theme], ([m, t]) => {
67
- if (!diffFile.value) return;
68
- diffFile.value.initTheme(t === 'dark' ? 'dark' : 'light');
69
- if (m === DiffModeEnum.Split) {
70
- diffFile.value.buildSplitDiffLines();
71
- } else {
72
- diffFile.value.buildUnifiedDiffLines();
73
- }
74
- });
75
-
76
7
  </script>
77
8
 
78
9
  <template>
79
- <DiffView
80
- v-if="hasChanges"
81
- :diff-file="diffFile"
82
- :diff-view-mode="mode"
83
- :diff-view-theme="theme === 'dark' ? 'dark' : 'light'"
84
- :diff-view-highlight="true"
85
- :diff-view-wrap="true"
86
- :diff-view-font-size="14"
10
+ <ApprovalDiff
11
+ :record="record"
12
+ :meta="meta"
13
+ :resource="resource"
14
+ splitWhenWide
15
+ @decided="router.push({ name: 'resource-list', params: { resourceId: resource.resourceId } })"
87
16
  />
88
- <div v-else>No changes</div>
89
- <div v-if="record[meta.resourceColumns.statusColumnName] === 1" style="margin-top: 16px; display: flex; gap: 8px;">
90
- <Button style="background-color: green; color: white;" @click="sendApproveRequest(true)" :loader="false" class="w-full">Approve</Button>
91
- <Button style="background-color: red; color: white;" @click="sendApproveRequest(false)" :loader="false" class="w-full">Reject</Button>
92
- </div>
93
17
  </template>
@@ -0,0 +1,192 @@
1
+ <script setup>
2
+ import { useCoreStore } from '@/stores/core';
3
+ import { computed, ref, watch, defineAsyncComponent, onMounted, useTemplateRef } from 'vue';
4
+ import { useElementSize } from '@vueuse/core';
5
+ import { useI18n } from 'vue-i18n';
6
+ import { callAdminForthApi } from '@/utils';
7
+ import adminforth from '@/adminforth';
8
+ import { Button } from '@/afcl';
9
+
10
+ const DiffView = defineAsyncComponent(async () => {
11
+ // pure styles come without tailwind preflight, which would otherwise reset fonts of the whole SPA
12
+ await import("@git-diff-view/vue/styles/diff-view-pure.css");
13
+ const { DiffView } = await import("@git-diff-view/vue");
14
+ return DiffView;
15
+ });
16
+
17
+ // old and new records go side by side only when the container fits two JSON columns
18
+ const SPLIT_MIN_WIDTH_PX = 768;
19
+ const PENDING_STATUS = 1;
20
+
21
+ const props = defineProps({
22
+ record: Object,
23
+ meta: Object,
24
+ resource: Object,
25
+ // only for a container whose width does not follow its content, a table cell of auto layout would toggle the modes
26
+ splitWhenWide: Boolean,
27
+ });
28
+ const emit = defineEmits(['decided']);
29
+ const { t } = useI18n();
30
+ const coreStore = useCoreStore();
31
+ const theme = computed(() => coreStore.theme === 'dark' ? 'dark' : 'light');
32
+
33
+ const { oldRecord, newRecord } = props.record[props.meta.resourceColumns.dataColumnName];
34
+ const oldContent = JSON.stringify(oldRecord, null, 2);
35
+ const newContent = JSON.stringify(newRecord, null, 2);
36
+ const hasChanges = oldContent !== newContent;
37
+ const isPending = props.record[props.meta.resourceColumns.statusColumnName] === PENDING_STATUS;
38
+
39
+ const { width } = useElementSize(useTemplateRef('container'));
40
+ const split = computed(() => props.splitWhenWide && width.value >= SPLIT_MIN_WIDTH_PX);
41
+
42
+ const diffFile = ref();
43
+ const diffModes = ref();
44
+ const sending = ref(null);
45
+
46
+ function buildDiffLines() {
47
+ if (split.value) {
48
+ diffFile.value.buildSplitDiffLines();
49
+ } else {
50
+ diffFile.value.buildUnifiedDiffLines();
51
+ }
52
+ }
53
+
54
+ onMounted(async () => {
55
+ if (!hasChanges) {
56
+ return;
57
+ }
58
+ const { DiffModeEnum } = await import("@git-diff-view/vue");
59
+ const { generateDiffFile } = await import("@git-diff-view/file");
60
+ diffModes.value = DiffModeEnum;
61
+ const file = generateDiffFile('diff.json', oldContent, 'diff.json', newContent, 'json', 'json');
62
+ file.initTheme(theme.value);
63
+ file.init();
64
+ diffFile.value = file;
65
+ buildDiffLines();
66
+ });
67
+
68
+ watch([split, theme], () => {
69
+ if (!diffFile.value) return;
70
+ diffFile.value.initTheme(theme.value);
71
+ buildDiffLines();
72
+ });
73
+
74
+ async function sendApproveRequest(approved) {
75
+ sending.value = approved ? 'approve' : 'reject';
76
+ const data = await callAdminForthApi({
77
+ path: `/plugin/crud-approve/update-status`,
78
+ method: 'POST',
79
+ body: {
80
+ connectorId: props.resource.connectorId,
81
+ resourceId: props.resource.resourceId,
82
+ action: props.record[props.meta.resourceColumns.actionColumnName],
83
+ recordId: props.record[props.meta.resourceColumns.recordIdColumnName],
84
+ diffId: props.record[props.meta.resourceColumns.idColumnName],
85
+ approved: approved
86
+ }
87
+ });
88
+ sending.value = null;
89
+ if (data.error && data.error !== 'Operation aborted by hook') {
90
+ adminforth.alert({ message: t('Error: {error}', { error: data.error }), variant: 'danger' });
91
+ } else {
92
+ adminforth.alert({ message: approved ? t('Change approved') : t('Change rejected'), variant: 'success' });
93
+ emit('decided');
94
+ }
95
+ }
96
+ </script>
97
+
98
+ <template>
99
+ <div ref="container" class="af-crud-approve">
100
+ <div
101
+ v-if="diffFile"
102
+ class="af-crud-approve-diff overflow-hidden rounded-default border border-lightCardBorder dark:border-darkCardBorder"
103
+ >
104
+ <DiffView
105
+ :diff-file="diffFile"
106
+ :diff-view-mode="split ? diffModes.Split : diffModes.Unified"
107
+ :diff-view-theme="theme"
108
+ :diff-view-highlight="true"
109
+ :diff-view-wrap="true"
110
+ :diff-view-font-size="13"
111
+ />
112
+ </div>
113
+ <p v-else-if="!hasChanges" class="text-lightInputPlaceholderText dark:text-darkInputPlaceholderText">
114
+ {{ $t('No changes to display') }}
115
+ </p>
116
+ <div v-if="isPending" class="af-crud-approve-actions mt-4 flex gap-2">
117
+ <Button
118
+ class="af-crud-approve-approve-button flex-1"
119
+ :loader="sending === 'approve'"
120
+ :disabled="!!sending"
121
+ @click="sendApproveRequest(true)"
122
+ >
123
+ {{ $t('Approve') }}
124
+ </Button>
125
+ <Button
126
+ class="af-crud-approve-reject-button flex-1"
127
+ variant="danger"
128
+ :loader="sending === 'reject'"
129
+ :disabled="!!sending"
130
+ @click="sendApproveRequest(false)"
131
+ >
132
+ {{ $t('Reject') }}
133
+ </Button>
134
+ </div>
135
+ </div>
136
+ </template>
137
+
138
+ <style>
139
+ /* the diff view sets Menlo inline on the tables of both modes */
140
+ .af-crud-approve-diff .diff-table-scroll-container,
141
+ .af-crud-approve-diff .diff-table-wrapper {
142
+ font-family: theme('fontFamily.mono') !important;
143
+ }
144
+
145
+ .af-crud-approve-diff .diff-tailwindcss-wrapper[data-theme="light"] .diff-style-root {
146
+ --diff-border--: theme('colors.lightCardBorder');
147
+ --diff-plain-content--: theme('colors.lightCardBackground');
148
+ --diff-plain-lineNumber--: theme('colors.lightCardBackground');
149
+ --diff-plain-lineNumber-color--: theme('colors.lightInputPlaceholderText');
150
+ --diff-expand-content--: theme('colors.lightCardBackgroundHover');
151
+ --diff-expand-lineNumber--: theme('colors.lightCardBackgroundHover');
152
+ --diff-expand-lineNumber-color--: theme('colors.lightInputPlaceholderText');
153
+ --diff-empty-content--: theme('colors.lightCardBackgroundHover');
154
+ --diff-hunk-content--: theme('colors.lightCardBackgroundHover');
155
+ --diff-hunk-lineNumber--: theme('colors.lightCardBackgroundHover');
156
+ --diff-hunk-lineNumber-hover--: theme('colors.lightPrimary');
157
+ --diff-hunk-content-color--: theme('colors.lightShowTableUnderHeadingText');
158
+ --diff-add-widget--: theme('colors.lightPrimary');
159
+ --diff-add-widget-color--: theme('colors.lightPrimaryContrast');
160
+ --diff-add-content--: theme('colors.lightSuccessSoft');
161
+ --diff-add-lineNumber--: theme('colors.lightSuccessSoft');
162
+ --diff-add-content-highlight--: theme('colors.lightSuccessBorder');
163
+ --diff-del-content--: theme('colors.lightDangerSoft');
164
+ --diff-del-lineNumber--: theme('colors.lightDangerSoft');
165
+ --diff-del-content-highlight--: theme('colors.lightDangerBorder');
166
+ color: theme('colors.lightShowTableBodyText');
167
+ }
168
+
169
+ .af-crud-approve-diff .diff-tailwindcss-wrapper[data-theme="dark"] .diff-style-root {
170
+ --diff-border--: theme('colors.darkCardBorder');
171
+ --diff-plain-content--: theme('colors.darkCardBackground');
172
+ --diff-plain-lineNumber--: theme('colors.darkCardBackground');
173
+ --diff-plain-lineNumber-color--: theme('colors.darkInputPlaceholderText');
174
+ --diff-expand-content--: theme('colors.darkCardBackgroundHover');
175
+ --diff-expand-lineNumber--: theme('colors.darkCardBackgroundHover');
176
+ --diff-expand-lineNumber-color--: theme('colors.darkInputPlaceholderText');
177
+ --diff-empty-content--: theme('colors.darkCardBackgroundHover');
178
+ --diff-hunk-content--: theme('colors.darkCardBackgroundHover');
179
+ --diff-hunk-lineNumber--: theme('colors.darkCardBackgroundHover');
180
+ --diff-hunk-lineNumber-hover--: theme('colors.darkPrimary');
181
+ --diff-hunk-content-color--: theme('colors.darkShowTableUnderHeadingText');
182
+ --diff-add-widget--: theme('colors.darkPrimary');
183
+ --diff-add-widget-color--: theme('colors.darkPrimaryContrast');
184
+ --diff-add-content--: theme('colors.darkSuccessSoft');
185
+ --diff-add-lineNumber--: theme('colors.darkSuccessSoft');
186
+ --diff-add-content-highlight--: theme('colors.darkSuccessBorder');
187
+ --diff-del-content--: theme('colors.darkDangerSoft');
188
+ --diff-del-lineNumber--: theme('colors.darkDangerSoft');
189
+ --diff-del-content-highlight--: theme('colors.darkDangerBorder');
190
+ color: theme('colors.darkShowTableBodyText');
191
+ }
192
+ </style>
@@ -1,84 +1,10 @@
1
1
  <script setup>
2
- import { useCoreStore } from '@/stores/core';
3
- import { computed, ref, watch } from 'vue';
4
- import "@git-diff-view/vue/styles/diff-view.css";
5
- import { DiffView, DiffModeEnum } from "@git-diff-view/vue";
6
- import { generateDiffFile } from "@git-diff-view/file";
7
- import { callAdminForthApi } from '@/utils';
8
2
  import adminforth from '@/adminforth';
9
- import { Button } from '@/afcl'
10
-
3
+ import ApprovalDiff from './ApprovalDiff.vue';
11
4
 
12
5
  const props = defineProps(['column', 'record', 'meta', 'resource', 'adminUser']);
13
- const coreStore = useCoreStore();
14
- const theme = computed(() => coreStore.theme);
15
-
16
- const oldContent = JSON.stringify(props.record[props.meta.resourceColumns.dataColumnName].oldRecord, null, 2)
17
- const newContent = JSON.stringify(props.record[props.meta.resourceColumns.dataColumnName].newRecord, null, 2)
18
- const hasChanges = oldContent !== newContent;
19
-
20
- const diffFile = ref();
21
-
22
-
23
- async function sendApproveRequest(approved) {
24
- const data = await callAdminForthApi({
25
- path: `/plugin/crud-approve/update-status`,
26
- method: 'POST',
27
- body: {
28
- connectorId: props.resource.connectorId,
29
- resourceId: props.resource.resourceId,
30
- action: props.record[props.meta.resourceColumns.actionColumnName],
31
- recordId: props.record[props.meta.resourceColumns.recordIdColumnName],
32
- diffId: props.record[props.meta.resourceColumns.idColumnName],
33
- approved: approved
34
- }
35
- });
36
- if (data.error && data.error !== 'Operation aborted by hook') {
37
- adminforth.alert({ message: `Error: ${data.error}`, variant: 'warning' });
38
- } else {
39
- adminforth.alert({ message: `Successfully ${approved ? 'approved' : 'rejected'} the change.`, variant: 'success' });
40
- // reload page
41
- adminforth.list.refresh();
42
- }
43
- }
44
-
45
- function initDiffFile() {
46
- const file = generateDiffFile(
47
- 'diff.json', oldContent,
48
- 'diff.json', newContent,
49
- 'json', 'json'
50
- );
51
- file.initTheme(theme.value === 'dark' ? 'dark' : 'light');
52
- file.init();
53
- file.buildUnifiedDiffLines();
54
- diffFile.value = file;
55
- }
56
-
57
- if (hasChanges) {
58
- initDiffFile();
59
- }
60
-
61
- watch([theme], ([t]) => {
62
- if (!diffFile.value) return;
63
- diffFile.value.initTheme(t === 'dark' ? 'dark' : 'light');
64
- diffFile.value.buildUnifiedDiffLines();
65
- });
66
-
67
6
  </script>
68
7
 
69
8
  <template>
70
- <DiffView
71
- v-if="hasChanges"
72
- :diff-file="diffFile"
73
- :diff-view-mode="DiffModeEnum.Unified"
74
- :diff-view-theme="theme === 'dark' ? 'dark' : 'light'"
75
- :diff-view-highlight="true"
76
- :diff-view-wrap="true"
77
- :diff-view-font-size="14"
78
- />
79
- <div v-else>No changes</div>
80
- <div v-if="record[meta.resourceColumns.statusColumnName] === 1" style="margin-top: 16px; display: flex; gap: 8px;">
81
- <Button style="background-color: green; color: white;" @click="sendApproveRequest(true)" :loader="false" class="w-full">Approve</Button>
82
- <Button style="background-color: red; color: white;" @click="sendApproveRequest(false)" :loader="false" class="w-full">Reject</Button>
83
- </div>
9
+ <ApprovalDiff :record="record" :meta="meta" :resource="resource" @decided="adminforth.list.refresh()" />
84
10
  </template>
@@ -1,93 +1,17 @@
1
1
  <script setup>
2
- import { useCoreStore } from '@/stores/core';
3
- import { computed, ref, watch } from 'vue';
4
- import "@git-diff-view/vue/styles/diff-view.css";
5
- import { DiffView, DiffModeEnum } from "@git-diff-view/vue";
6
- import { generateDiffFile } from "@git-diff-view/file";
7
- import { callAdminForthApi } from '@/utils';
8
- import adminforth from '@/adminforth';
9
- import { Button } from '@/afcl'
10
2
  import { useRouter } from 'vue-router';
3
+ import ApprovalDiff from './ApprovalDiff.vue';
11
4
 
12
5
  const router = useRouter();
13
6
  const props = defineProps(['column', 'record', 'meta', 'resource', 'adminUser']);
14
- const coreStore = useCoreStore();
15
- const theme = computed(() => coreStore.theme);
16
- const isMobile = computed(() => /(Android|iPhone|iPad|iPod)/i.test(navigator.userAgent));
17
- const mode = computed(() => isMobile.value ? DiffModeEnum.Unified : DiffModeEnum.Split);
18
-
19
- const oldContent = JSON.stringify(props.record[props.meta.resourceColumns.dataColumnName].oldRecord, null, 2)
20
- const newContent = JSON.stringify(props.record[props.meta.resourceColumns.dataColumnName].newRecord, null, 2)
21
- const hasChanges = oldContent !== newContent;
22
-
23
- const diffFile = ref();
24
-
25
- async function sendApproveRequest(approved) {
26
- const data = await callAdminForthApi({
27
- path: `/plugin/crud-approve/update-status`,
28
- method: 'POST',
29
- body: {
30
- connectorId: props.resource.connectorId,
31
- resourceId: props.resource.resourceId,
32
- action: props.record[props.meta.resourceColumns.actionColumnName],
33
- recordId: props.record[props.meta.resourceColumns.recordIdColumnName],
34
- diffId: props.record[props.meta.resourceColumns.idColumnName],
35
- approved: approved
36
- }
37
- });
38
- if (data.error && data.error !== 'Operation aborted by hook') {
39
- adminforth.alert({ message: `Error: ${data.error}`, variant: 'warning' });
40
- } else {
41
- adminforth.alert({ message: `Successfully ${approved ? 'approved' : 'rejected'} the change.`, variant: 'success' });
42
- router.push(router.currentRoute.value.fullPath.split('/show')[0]);
43
- }
44
- }
45
-
46
- function initDiffFile() {
47
- const file = generateDiffFile(
48
- 'diff.json', oldContent,
49
- 'diff.json', newContent,
50
- 'json', 'json'
51
- );
52
- file.initTheme(theme.value === 'dark' ? 'dark' : 'light');
53
- file.init();
54
- if (mode.value === DiffModeEnum.Split) {
55
- file.buildSplitDiffLines();
56
- } else {
57
- file.buildUnifiedDiffLines();
58
- }
59
- diffFile.value = file;
60
- }
61
-
62
- if (hasChanges) {
63
- initDiffFile();
64
- }
65
-
66
- watch([mode, theme], ([m, t]) => {
67
- if (!diffFile.value) return;
68
- diffFile.value.initTheme(t === 'dark' ? 'dark' : 'light');
69
- if (m === DiffModeEnum.Split) {
70
- diffFile.value.buildSplitDiffLines();
71
- } else {
72
- diffFile.value.buildUnifiedDiffLines();
73
- }
74
- });
75
-
76
7
  </script>
77
8
 
78
9
  <template>
79
- <DiffView
80
- v-if="hasChanges"
81
- :diff-file="diffFile"
82
- :diff-view-mode="mode"
83
- :diff-view-theme="theme === 'dark' ? 'dark' : 'light'"
84
- :diff-view-highlight="true"
85
- :diff-view-wrap="true"
86
- :diff-view-font-size="14"
10
+ <ApprovalDiff
11
+ :record="record"
12
+ :meta="meta"
13
+ :resource="resource"
14
+ splitWhenWide
15
+ @decided="router.push({ name: 'resource-list', params: { resourceId: resource.resourceId } })"
87
16
  />
88
- <div v-else>No changes</div>
89
- <div v-if="record[meta.resourceColumns.statusColumnName] === 1" style="margin-top: 16px; display: flex; gap: 8px;">
90
- <Button style="background-color: green; color: white;" @click="sendApproveRequest(true)" :loader="false" class="w-full">Approve</Button>
91
- <Button style="background-color: red; color: white;" @click="sendApproveRequest(false)" :loader="false" class="w-full">Reject</Button>
92
- </div>
93
17
  </template>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminforth/crud-approve-plugin",
3
- "version": "1.0.21",
3
+ "version": "1.1.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -23,7 +23,7 @@
23
23
  "dayjs": "^1.11.11"
24
24
  },
25
25
  "peerDependencies": {
26
- "adminforth": "^3.1.2"
26
+ "adminforth": "^4.7.3"
27
27
  },
28
28
  "release": {
29
29
  "plugins": [