Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Airtable Integration #19

Merged
merged 30 commits into from
Dec 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
6b4694f
add airtable integration
zetavg Nov 18, 2023
34e5364
integration-airtable: add more fields & fix stuff
zetavg Nov 20, 2023
533bfe9
GetSecretsModalScreen: use secureTextEntry and trim input
zetavg Nov 20, 2023
015bc07
fix tests
zetavg Nov 20, 2023
395ec60
add getChildrenItems function
zetavg Nov 20, 2023
1251e66
integration-airtable: add ability to sync items under specific contai…
zetavg Nov 20, 2023
5a6db8a
fix: data not being updated while directly assigning values in update…
zetavg Nov 21, 2023
767e3f5
for performance reasons, just do not allow directly assigning data in…
zetavg Nov 21, 2023
de1d5d3
integration-airtable: remove items that should not be synced anymore,…
zetavg Nov 22, 2023
6ccd8e2
data: add history functionality
zetavg Nov 25, 2023
2a9dd39
create history on Airtable sync & add history related views
zetavg Nov 25, 2023
b0f184b
optionally show “Integrations” directly on the “More” tab if there’re…
zetavg Nov 26, 2023
277fed2
add packages/couchdb-public-server
zetavg Nov 26, 2023
567ec11
integration-airtable: support syncing item images
zetavg Nov 26, 2023
0913069
change history id prefix
zetavg Nov 26, 2023
da98338
integration-airtable: sync more fields
zetavg Nov 26, 2023
d05920b
fix
zetavg Nov 26, 2023
b45008d
integration-airtable: do not update blank notes to undefined
zetavg Nov 26, 2023
4876758
fix generate-changelog-from-github-context
zetavg Nov 26, 2023
35d83b3
increase db sync batch size and limit
zetavg Nov 26, 2023
34776b8
ui fixes and updates
zetavg Nov 26, 2023
21f3020
update README.md for couchdb-public-server
zetavg Nov 26, 2023
ae3c71f
fix: duplicating an item should not duplicate it’s integrations metadata
zetavg Nov 26, 2023
a13e1a6
update wording
zetavg Nov 26, 2023
89808ed
use null to correctly clear fields on Airtable
zetavg Nov 26, 2023
0b62fd4
fix ui
zetavg Nov 26, 2023
743454a
integration-airtable: check if image URL works before using it
zetavg Nov 27, 2023
92e91bf
UI updates for Airtable integration
zetavg Nov 27, 2023
85cae50
SelectItemModalScreen: temporary solution for better performance
zetavg Nov 27, 2023
9b1e15c
airtable-integration: write event name in history
zetavg Nov 27, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 35 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,38 @@ jobs:
cd packages/data-storage-couchdb
COUCHDB_URI='http://127.0.0.1:5984/test' COUCHDB_USERNAME=user COUCHDB_PASSWORD=password yarn test lib/__tests__/data-storage-couchdb.test.ts --runInBand

test-integration-airtable:
name: "Test: integration-airtable"
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: 18.15.0
- name: Cache node_modules
uses: actions/cache@v3
env:
cache-name: integration-airtable-node_modules
with:
path: packages/integration-airtable/node_modules
key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('packages/integration-airtable/yarn.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.cache-name }}-
- name: Yarn Install
run: |
cd packages/integration-airtable
yarn install
- name: Typecheck
run: |
cd packages/integration-airtable
yarn run typecheck
- name: Test
run: |
cd packages/integration-airtable
FORCE_COLOR=true yarn test --verbose

test-integration-snipe-it:
name: "Test: integration-snipe-it"
runs-on: ubuntu-latest
Expand Down Expand Up @@ -237,14 +269,16 @@ jobs:
- 'packages/data-storage-couchdb/**'
epc-utils:
- 'packages/epc-utils/**'
integration-airtable:
- 'packages/integration-airtable/**'

build:
name: "Build App"
needs:
- test-app
- paths-filter
# Build if the app has changes, and event is not a pull request, or if the pull request is not a draft and the pull request is not from a fork (runs of fork PRs will not have access to secrets that are required for building the app).
if: ${{ vars.CI_ENABLE_BUILD && (github.event_name == 'release' || github.event_name == 'schedule' || needs.paths-filter.outputs.app == 'true' || needs.paths-filter.outputs.data == 'true' || needs.paths-filter.outputs.data-storage-couchdb == 'true' || needs.paths-filter.outputs.epc-utils == 'true') && ((github.event_name != 'pull_request' && github.event_name != 'pull_request_target') || (!github.event.pull_request.draft && github.actor != 'dependabot[bot]' && github.event.pull_request.head.repo.clone_url == github.event.pull_request.base.repo.clone_url)) }}
if: ${{ vars.CI_ENABLE_BUILD && (github.event_name == 'release' || github.event_name == 'schedule' || needs.paths-filter.outputs.app == 'true' || needs.paths-filter.outputs.data == 'true' || needs.paths-filter.outputs.data-storage-couchdb == 'true' || needs.paths-filter.outputs.epc-utils == 'true' || needs.paths-filter.outputs.integration-airtable == 'true') && ((github.event_name != 'pull_request' && github.event_name != 'pull_request_target') || (!github.event.pull_request.draft && github.actor != 'dependabot[bot]' && github.event.pull_request.head.repo.clone_url == github.event.pull_request.base.repo.clone_url)) }}
uses: ./.github/workflows/build_app.yml
with:
build-release: ${{ github.event_name == 'release' }}
Expand Down
81 changes: 81 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,84 @@ jobs:
run: |
cd packages/epc-utils
yarn run lint

lint-data-storage-couchdb:
name: "Lint: data-storage-couchdb"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Setup Node.js
uses: actions/setup-node@v1
with:
node-version: 18.15.0
- name: Cache node_modules
uses: actions/cache@v2
env:
cache-name: data-storage-couchdb-node_modules
with:
path: packages/data-storage-couchdb/node_modules
key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('packages/data-storage-couchdb/yarn.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.cache-name }}-
- name: Yarn Install
run: |
cd packages/data-storage-couchdb
yarn install
- name: Lint
run: |
cd packages/data-storage-couchdb
yarn run lint

lint-integration-airtable:
name: "Lint: integration-airtable"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Setup Node.js
uses: actions/setup-node@v1
with:
node-version: 18.15.0
- name: Cache node_modules
uses: actions/cache@v2
env:
cache-name: integration-airtable-node_modules
with:
path: packages/integration-airtable/node_modules
key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('packages/integration-airtable/yarn.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.cache-name }}-
- name: Yarn Install
run: |
cd packages/integration-airtable
yarn install
- name: Lint
run: |
cd packages/integration-airtable
yarn run lint

lint-integration-snipe-it:
name: "Lint: integration-snipe-it"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Setup Node.js
uses: actions/setup-node@v1
with:
node-version: 18.15.0
- name: Cache node_modules
uses: actions/cache@v2
env:
cache-name: integration-snipe-it-node_modules
with:
path: packages/integration-snipe-it/node_modules
key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('packages/integration-snipe-it/yarn.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.cache-name }}-
- name: Yarn Install
run: |
cd packages/integration-snipe-it
yarn install
- name: Lint
run: |
cd packages/integration-snipe-it
yarn run lint
Original file line number Diff line number Diff line change
Expand Up @@ -193,10 +193,10 @@ function getCommitsBetween(startSHA, endSHA) {

const commitsArray = commits.split('\n');
return commitsArray.map(arr => {
const parts = arr.split(':', 2);
const [hash, ...messageParts] = arr.split(':');
return {
hash: parts[0],
message: parts[1],
hash,
message: messageParts.join(':'),
};
});
}
Expand Down
161 changes: 161 additions & 0 deletions App/app/components/DatumHistoryItem/DatumHistoryItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import React, { useMemo } from 'react';
import { StyleSheet, View } from 'react-native';

import type { DataHistory, DataTypeName } from '@deps/data/types';

import { getHumanName, useData } from '@app/data';

import useColors from '@app/hooks/useColors';

import Text from '@app/components/Text';
import UIGroup from '@app/components/UIGroup';

function DatumHistoryItem({
history,
...restProps
}: { history: DataHistory<DataTypeName> } & React.ComponentProps<
typeof UIGroup.ListItem
>) {
const { data } = useData(history.data_type, history.data_id);
const dataName = useMemo(() => {
if (typeof data?.name === 'string') {
return data?.name;
}

if (typeof history.original_data?.name === 'string') {
return history.original_data?.name;
}

if (typeof history.new_data?.name === 'string') {
return history.new_data?.name;
}
}, [data?.name, history]);

const type = useMemo(() => {
if (history.original_data.__deleted && !history.new_data.__deleted) {
return 'CREATED';
}
if (!history.original_data.__deleted && history.new_data.__deleted) {
return 'DELETED';
}

return 'UPDATED';
}, [history.new_data.__deleted, history.original_data.__deleted]);

const { backgroundColor, contentSecondaryTextColor, contentTextColor } =
useColors();

return (
<UIGroup.ListItem {...restProps}>
<View style={styles.container}>
<View style={styles.headerContainer}>
<Text
style={[
styles.dataTypeText,
{ backgroundColor, color: contentSecondaryTextColor },
]}
>
{getHumanName(history.data_type)}
</Text>
{!!dataName && (
<Text style={[styles.dataNameText, { color: contentTextColor }]}>
{dataName}
</Text>
)}
<Text
style={[
styles.typeText,
{ backgroundColor, color: contentSecondaryTextColor },
]}
>
{type}
</Text>
</View>
{type === 'UPDATED' && (
<View style={styles.updateDetailsContainer}>
{Array.from(
new Set([
...Object.keys(history.original_data),
...Object.keys(history.new_data),
]),
)
.filter(k => !k.match(/password/))
.map(k => (
<View style={styles.updateDetailItemContainer} key={k}>
<Text>
<Text
style={[
styles.updatedKeyText,
{ color: contentSecondaryTextColor },
]}
selectable
>
{getHumanName(k, { titleCase: true })}
</Text>
<Text> </Text>
<Text
style={[
styles.updatedValueText,
{ color: contentTextColor },
]}
selectable
>
{`${history.original_data[k]} → ${history.new_data[k]}`}
</Text>
</Text>
</View>
))}
</View>
)}
</View>
</UIGroup.ListItem>
);
}

export default DatumHistoryItem;

const styles = StyleSheet.create({
container: {
flexDirection: 'column',
},
headerContainer: {
flexDirection: 'row',
alignItems: 'center',
gap: 2,
},
dataTypeText: {
textTransform: 'uppercase',
borderRadius: 2,
paddingHorizontal: 4,
paddingVertical: 2,
fontSize: 16,
},
dataNameText: {
paddingHorizontal: 4,
paddingVertical: 2,
fontSize: 16,
fontWeight: '500',
},
typeText: {
textTransform: 'uppercase',
borderRadius: 2,
paddingHorizontal: 4,
paddingVertical: 2,
fontSize: 14,
},
updateDetailsContainer: {
marginTop: 2,
},
updateDetailItemContainer: {
marginTop: 8,
flexDirection: 'row',
gap: 4,
},
updatedKeyText: {
fontSize: 16,
fontWeight: '500',
},
updatedValueText: {
fontSize: 16,
},
});
2 changes: 2 additions & 0 deletions App/app/components/DatumHistoryItem/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import DatumHistoryItem from './DatumHistoryItem';
export default DatumHistoryItem;
55 changes: 41 additions & 14 deletions App/app/components/InsetGroup/InsetGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@ const INSET_GROUP_ITEM_PADDING_HORIZONTAL = 16;
type Props = {
children: React.ReactNode;
label?: string | JSX.Element;
footerLabel?: string | JSX.Element;
footerLabel?:
| string
| JSX.Element
| ((context: {
textProps: React.ComponentProps<typeof Text>;
}) => React.ReactNode);
labelVariant?: 'normal' | 'large';
labelRight?: JSX.Element;
labelContainerStyle?: React.ComponentProps<typeof View>['style'];
Expand Down Expand Up @@ -121,18 +126,38 @@ function InsetGroup(
{loading && <LoadingOverlay show />}
</View>
)}
{footerLabel && (
<Text
style={[
styles.groupFooterLabel,
{
color: groupTitleColor,
},
]}
>
{footerLabel}
</Text>
)}
{footerLabel &&
(typeof footerLabel === 'string' ? (
<>
<Text
style={[
styles.groupFooterLabel,
{
color: groupTitleColor,
},
]}
>
{footerLabel}
</Text>
<View style={styles.groupFooterLabelAfter} />
</>
) : typeof footerLabel === 'function' ? (
<>
{footerLabel({
textProps: {
style: [
styles.groupFooterLabel,
{
color: groupTitleColor,
},
],
},
})}
<View style={styles.groupFooterLabelAfter} />
</>
) : (
footerLabel
))}
</>
);
}
Expand Down Expand Up @@ -693,7 +718,9 @@ export const styles = StyleSheet.create({
groupFooterLabel: {
marginHorizontal: 32,
marginTop: 8,
marginBottom: 35,
},
groupFooterLabelAfter: {
height: 35,
},
insetGroupLeftElementContainer: {
justifyContent: 'center',
Expand Down
Loading
Loading