Google Sheet integration fix (#493)
* Google Sheet integration fix * fix testcase --------- Co-authored-by: Julien Nahum <julien@nahum.net>
This commit is contained in:
parent
6ec1f4d745
commit
a2c1757815
|
|
@ -12,6 +12,7 @@ use Google\Service\Sheets\BatchUpdateValuesRequest;
|
||||||
use Google\Service\Sheets\Spreadsheet;
|
use Google\Service\Sheets\Spreadsheet;
|
||||||
use Google\Service\Sheets\ValueRange;
|
use Google\Service\Sheets\ValueRange;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class SpreadsheetManager
|
class SpreadsheetManager
|
||||||
{
|
{
|
||||||
|
|
@ -30,19 +31,12 @@ class SpreadsheetManager
|
||||||
url: $this->integration->data->url,
|
url: $this->integration->data->url,
|
||||||
spreadsheet_id: $this->integration->data->spreadsheet_id,
|
spreadsheet_id: $this->integration->data->spreadsheet_id,
|
||||||
columns: array_map(
|
columns: array_map(
|
||||||
fn ($column) => (array) $column,
|
fn ($column) => (array)$column,
|
||||||
$this->integration->data->columns
|
$this->integration->data->columns
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function convertToArray(mixed $object): array
|
|
||||||
{
|
|
||||||
return is_scalar($object) || is_null($object)
|
|
||||||
? $object
|
|
||||||
: $this->convertToArray((array) $object);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function get(string $id): Spreadsheet
|
public function get(string $id): Spreadsheet
|
||||||
{
|
{
|
||||||
$spreadsheet = $this->driver
|
$spreadsheet = $this->driver
|
||||||
|
|
@ -73,9 +67,12 @@ class SpreadsheetManager
|
||||||
|
|
||||||
public function buildColumns(): array
|
public function buildColumns(): array
|
||||||
{
|
{
|
||||||
$properties = $this->integration->form->properties;
|
collect($this->integration->form->properties)->each(function ($property) {
|
||||||
|
// Skip custom blocks
|
||||||
|
if (Str::of($property['type'])->startsWith('nf-')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($properties as $property) {
|
|
||||||
$key = Arr::first(
|
$key = Arr::first(
|
||||||
array_keys($this->data->columns),
|
array_keys($this->data->columns),
|
||||||
fn (int $key) => $this->data->columns[$key]['id'] === $property['id']
|
fn (int $key) => $this->data->columns[$key]['id'] === $property['id']
|
||||||
|
|
@ -88,12 +85,11 @@ class SpreadsheetManager
|
||||||
} else {
|
} else {
|
||||||
$this->data->columns[] = $column;
|
$this->data->columns[] = $column;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
$this->integration->update([
|
$this->integration->update([
|
||||||
'data' => $this->data,
|
'data' => $this->data,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $this->data->columns;
|
return $this->data->columns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -184,6 +180,20 @@ class SpreadsheetManager
|
||||||
|
|
||||||
protected function buildRange(array $values): string
|
protected function buildRange(array $values): string
|
||||||
{
|
{
|
||||||
return "A1:" . chr(64 + count($values)) . "1";
|
$columnsCount = count($values);
|
||||||
|
$endColumn = $this->getColumnLetter($columnsCount);
|
||||||
|
return "A1:{$endColumn}1";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected function getColumnLetter(int $columnIndex): string
|
||||||
|
{
|
||||||
|
$columnLetter = '';
|
||||||
|
while ($columnIndex > 0) {
|
||||||
|
$columnIndex--;
|
||||||
|
$columnLetter = chr(65 + ($columnIndex % 26)) . $columnLetter;
|
||||||
|
$columnIndex = (int)($columnIndex / 26);
|
||||||
|
}
|
||||||
|
return $columnLetter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<input-wrapper v-bind="inputWrapperProps">
|
<InputWrapper v-bind="inputWrapperProps">
|
||||||
<template #label>
|
<template #label>
|
||||||
<slot name="label" />
|
<slot name="label" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<vue-editor
|
<VueEditor
|
||||||
:id="id ? id : name"
|
:id="id ? id : name"
|
||||||
ref="editor"
|
ref="editor"
|
||||||
v-model="compVal"
|
v-model="compVal"
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
theme.RichTextAreaInput.input,
|
theme.RichTextAreaInput.input,
|
||||||
theme.RichTextAreaInput.borderRadius,
|
theme.RichTextAreaInput.borderRadius,
|
||||||
]"
|
]"
|
||||||
|
:editor-options="editorOptions"
|
||||||
:editor-toolbar="editorToolbar"
|
:editor-toolbar="editorToolbar"
|
||||||
class="rich-editor resize-y"
|
class="rich-editor resize-y"
|
||||||
:style="inputStyle"
|
:style="inputStyle"
|
||||||
|
|
@ -29,40 +30,58 @@
|
||||||
<template #error>
|
<template #error>
|
||||||
<slot name="error" />
|
<slot name="error" />
|
||||||
</template>
|
</template>
|
||||||
</input-wrapper>
|
</InputWrapper>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { inputProps, useFormInput } from "./useFormInput.js"
|
import { Quill, VueEditor } from 'vue3-editor'
|
||||||
import InputWrapper from "./components/InputWrapper.vue"
|
import { inputProps, useFormInput } from './useFormInput.js'
|
||||||
import { VueEditor, Quill } from "vue3-editor"
|
import InputWrapper from './components/InputWrapper.vue'
|
||||||
|
|
||||||
Quill.imports["formats/link"].PROTOCOL_WHITELIST.push("notion")
|
Quill.imports['formats/link'].PROTOCOL_WHITELIST.push('notion')
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "RichTextAreaInput",
|
name: 'RichTextAreaInput',
|
||||||
components: { InputWrapper, VueEditor },
|
components: { InputWrapper, VueEditor },
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
...inputProps,
|
...inputProps,
|
||||||
|
editorOptions: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {
|
||||||
|
return {
|
||||||
|
formats: [
|
||||||
|
'bold',
|
||||||
|
'color',
|
||||||
|
'font',
|
||||||
|
'italic',
|
||||||
|
'link',
|
||||||
|
'underline',
|
||||||
|
'header',
|
||||||
|
'indent',
|
||||||
|
'list'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
editorToolbar: {
|
editorToolbar: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => {
|
default: () => {
|
||||||
return [
|
return [
|
||||||
[{ header: 1 }, { header: 2 }],
|
[{ header: 1 }, { header: 2 }],
|
||||||
["bold", "italic", "underline", "link"],
|
['bold', 'italic', 'underline', 'link'],
|
||||||
[{ list: "ordered" }, { list: "bullet" }],
|
[{ list: 'ordered' }, { list: 'bullet' }],
|
||||||
[{ color: [] }],
|
[{ color: [] }]
|
||||||
]
|
]
|
||||||
},
|
}
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
setup(props, context) {
|
|
||||||
return {
|
|
||||||
...useFormInput(props, context),
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setup (props, context) {
|
||||||
|
return {
|
||||||
|
...useFormInput(props, context)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@
|
||||||
theme.SelectInput.fontSize,
|
theme.SelectInput.fontSize,
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
{{ option.name }}
|
{{ getOptionName(option) }}
|
||||||
</p>
|
</p>
|
||||||
<span
|
<span
|
||||||
v-if="selected"
|
v-if="selected"
|
||||||
|
|
@ -157,7 +157,8 @@ export default {
|
||||||
methods: {
|
methods: {
|
||||||
getOptionName(val) {
|
getOptionName(val) {
|
||||||
const option = this.finalOptions.find((optionCandidate) => {
|
const option = this.finalOptions.find((optionCandidate) => {
|
||||||
return optionCandidate[this.optionKey] === val
|
return optionCandidate[this.optionKey] === val ||
|
||||||
|
(typeof val === 'object' && optionCandidate[this.optionKey] === val[this.optionKey])
|
||||||
})
|
})
|
||||||
if (option) return option[this.displayKey]
|
if (option) return option[this.displayKey]
|
||||||
return null
|
return null
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,7 @@
|
||||||
:alt="field.name"
|
:alt="field.name"
|
||||||
:src="field.image_block"
|
:src="field.image_block"
|
||||||
class="max-w-full"
|
class="max-w-full"
|
||||||
|
:class="theme.default.borderRadius"
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -517,6 +517,17 @@
|
||||||
:form="field"
|
:form="field"
|
||||||
:editor-toolbar="editorToolbarCustom"
|
:editor-toolbar="editorToolbarCustom"
|
||||||
label="Field Help"
|
label="Field Help"
|
||||||
|
:editor-options="{
|
||||||
|
formats: [
|
||||||
|
'bold',
|
||||||
|
'color',
|
||||||
|
'font',
|
||||||
|
'italic',
|
||||||
|
'link',
|
||||||
|
'underline',
|
||||||
|
'list'
|
||||||
|
]
|
||||||
|
}"
|
||||||
help="Your field help will be shown below/above the field, just like this text."
|
help="Your field help will be shown below/above the field, just like this text."
|
||||||
:help-position="field.help_position"
|
:help-position="field.help_position"
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
v-model="integrationData.oauth_id"
|
v-model="integrationData.oauth_id"
|
||||||
name="provider"
|
name="provider"
|
||||||
:options="providers"
|
:options="providers"
|
||||||
|
display-key="email"
|
||||||
option-key="id"
|
option-key="id"
|
||||||
emit-key="id"
|
emit-key="id"
|
||||||
:required="true"
|
:required="true"
|
||||||
|
|
@ -43,19 +44,19 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import IntegrationWrapper from "./components/IntegrationWrapper.vue"
|
import IntegrationWrapper from './components/IntegrationWrapper.vue'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
integration: { type: Object, required: true },
|
integration: { type: Object, required: true },
|
||||||
form: { type: Object, required: true },
|
form: { type: Object, required: true },
|
||||||
integrationData: { type: Object, required: true },
|
integrationData: { type: Object, required: true },
|
||||||
formIntegrationId: { type: Number, required: false, default: null },
|
formIntegrationId: { type: Number, required: false, default: null }
|
||||||
})
|
})
|
||||||
|
|
||||||
const providersStore = useOAuthProvidersStore()
|
const providersStore = useOAuthProvidersStore()
|
||||||
const providers = computed(() => providersStore.getAll.filter(provider => provider.provider == 'google'))
|
const providers = computed(() => providersStore.getAll.filter(provider => provider.provider == 'google'))
|
||||||
|
|
||||||
function connect() {
|
function connect () {
|
||||||
providersStore.connect('google', true)
|
providersStore.connect('google', true)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@
|
||||||
"section_name": "Databases",
|
"section_name": "Databases",
|
||||||
"file_name": "GoogleSheetsIntegration",
|
"file_name": "GoogleSheetsIntegration",
|
||||||
"actions_file_name": "GoogleSheetsIntegrationActions",
|
"actions_file_name": "GoogleSheetsIntegrationActions",
|
||||||
"is_pro": false
|
"is_pro": false,
|
||||||
|
"crisp_help_page_slug": "how-do-i-integrate-google-sheets-for-my-database-goefny"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@
|
||||||
"section_name": "Databases",
|
"section_name": "Databases",
|
||||||
"file_name": "GoogleSheetsIntegration",
|
"file_name": "GoogleSheetsIntegration",
|
||||||
"actions_file_name": "GoogleSheetsIntegrationActions",
|
"actions_file_name": "GoogleSheetsIntegrationActions",
|
||||||
"is_pro": false
|
"is_pro": false,
|
||||||
|
"crisp_help_page_slug": "how-do-i-integrate-google-sheets-for-my-database-goefny"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ test('build columns', function () {
|
||||||
|
|
||||||
assertCount(14, $columns);
|
assertCount(14, $columns);
|
||||||
|
|
||||||
foreach($columns as $key => $column) {
|
foreach ($columns as $key => $column) {
|
||||||
assertEquals($form->properties[$key]['id'], $column['id']);
|
assertEquals($form->properties[$key]['id'], $column['id']);
|
||||||
assertEquals($form->properties[$key]['name'], $column['name']);
|
assertEquals($form->properties[$key]['name'], $column['name']);
|
||||||
}
|
}
|
||||||
|
|
@ -63,8 +63,8 @@ test('update columns', function () {
|
||||||
|
|
||||||
$form->update([
|
$form->update([
|
||||||
'properties' => [
|
'properties' => [
|
||||||
['id' => '000', 'name' => 'First'],
|
['id' => '000', 'name' => 'First', 'type' => 'text'],
|
||||||
['id' => '001', 'name' => 'Second'],
|
['id' => '001', 'name' => 'Second', 'type' => 'text'],
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
@ -82,8 +82,8 @@ test('update columns', function () {
|
||||||
url: 'https://google.com',
|
url: 'https://google.com',
|
||||||
spreadsheet_id: 'sp_test',
|
spreadsheet_id: 'sp_test',
|
||||||
columns: [
|
columns: [
|
||||||
['id' => '000', 'name' => 'First'],
|
['id' => '000', 'name' => 'First', 'type' => 'text'],
|
||||||
['id' => '001', 'name' => 'Second'],
|
['id' => '001', 'name' => 'Second', 'type' => 'text'],
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
]);
|
]);
|
||||||
|
|
@ -96,8 +96,8 @@ test('update columns', function () {
|
||||||
|
|
||||||
$form->update([
|
$form->update([
|
||||||
'properties' => [
|
'properties' => [
|
||||||
['id' => '000', 'name' => 'First name'],
|
['id' => '000', 'name' => 'First name', 'type' => 'text'],
|
||||||
['id' => '002', 'name' => 'Email'],
|
['id' => '002', 'name' => 'Email', 'type' => 'text'],
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue