@vixoniccom/aqi 0.0.3-dev.3 → 0.0.3-dev.5
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/.env +1 -0
- package/.github/workflows/npm-publish.yml +105 -0
- package/CHANGELOG.md +8 -4
- package/build/main.js +1 -1
- package/build/test/parameters.json +1 -1
- package/build.zip +0 -0
- package/configuration/appeareanceGroup/AppeareanceInputs.ts +2 -10
- package/configuration.json +0 -19
- package/package.json +3 -3
- package/sonar-project.properties +1 -2
- package/src/App.tsx +11 -5
- package/src/components/Card.tsx +1 -3
- package/src/parameters.d.ts +0 -1
- package/src/services/index.ts +26 -4
- package/src/test/parameters.json +1 -1
- package/.github/workflows/main.yml +0 -131
package/build.zip
CHANGED
|
Binary file
|
|
@@ -1,17 +1,9 @@
|
|
|
1
|
-
import { Label, NumberInput, SelectAssetKna,
|
|
1
|
+
import { Label, NumberInput, SelectAssetKna, TextFormat, TextInput } from '@vixoniccom/modules'
|
|
2
2
|
|
|
3
3
|
export const appeareanceInputs = [
|
|
4
4
|
new Label({ label: 'General' }),
|
|
5
5
|
new SelectAssetKna({ id: 'backgroundImage', label: 'Fondo', required: false, extensions: ['jpg', 'png'] }),
|
|
6
|
-
|
|
7
|
-
new SelectInput({
|
|
8
|
-
id: 'positionCard',
|
|
9
|
-
label: 'Tipo de posición',
|
|
10
|
-
items: [
|
|
11
|
-
{ label: 'Horizontal', value: 'horizontal' },
|
|
12
|
-
{ label: 'Vertical', value: 'vertical' },
|
|
13
|
-
],
|
|
14
|
-
}),
|
|
6
|
+
|
|
15
7
|
new Label({ label: 'Diseño de la tarjeta' }),
|
|
16
8
|
new NumberInput({
|
|
17
9
|
id: 'topSeparationCard',
|
package/configuration.json
CHANGED
|
@@ -20,25 +20,6 @@
|
|
|
20
20
|
],
|
|
21
21
|
"multiple": false
|
|
22
22
|
},
|
|
23
|
-
{
|
|
24
|
-
"type": "label",
|
|
25
|
-
"label": "Posición"
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
"id": "positionCard",
|
|
29
|
-
"label": "Tipo de posición",
|
|
30
|
-
"type": "select-input",
|
|
31
|
-
"items": [
|
|
32
|
-
{
|
|
33
|
-
"value": "horizontal",
|
|
34
|
-
"label": "Horizontal"
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
"value": "vertical",
|
|
38
|
-
"label": "Vertical"
|
|
39
|
-
}
|
|
40
|
-
]
|
|
41
|
-
},
|
|
42
23
|
{
|
|
43
24
|
"type": "label",
|
|
44
25
|
"label": "Diseño de la tarjeta"
|
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"author": {
|
|
9
9
|
"name": "Daniel Alvayay"
|
|
10
10
|
},
|
|
11
|
-
"version": "0.0.3-dev.
|
|
11
|
+
"version": "0.0.3-dev.5",
|
|
12
12
|
"scripts": {
|
|
13
13
|
"prepublish": "vixonic-module-packager --mode=build",
|
|
14
14
|
"watch": "vixonic-module-packager --mode=watch",
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@types/react": "^18.3.23",
|
|
30
30
|
"@types/react-dom": "^18.3.7",
|
|
31
|
-
"@vixoniccom/module-packager": "^2.13.0",
|
|
32
|
-
"@vixoniccom/modules": "^2.
|
|
31
|
+
"@vixoniccom/module-packager": "^2.13.0-dev.1",
|
|
32
|
+
"@vixoniccom/modules": "^2.20.5-dev.1",
|
|
33
33
|
"standard-version": "^9.5.0"
|
|
34
34
|
}
|
|
35
35
|
}
|
package/sonar-project.properties
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
sonar.projectKey=Vixonic_store-air-quality-index_de6b8e55-8f87-4d53-b9d5-7e514a2702d9
|
|
2
|
-
sonar.exclusions=.github/**/*
|
|
1
|
+
sonar.projectKey=Vixonic_store-air-quality-index_de6b8e55-8f87-4d53-b9d5-7e514a2702d9
|
package/src/App.tsx
CHANGED
|
@@ -14,19 +14,26 @@ export const App: React.FunctionComponent<Props> = ({ data, start }) => {
|
|
|
14
14
|
const { parameters, downloadsPath } = data
|
|
15
15
|
const backgroundImageState = parameters.backgroundImage ? `url('${downloadsPath}/${parameters.backgroundImage.filename}')` : ''
|
|
16
16
|
const [formattedData, setFormattedData] = useState<AqiData>()
|
|
17
|
-
const cityInput = parameters?.cityInput || "
|
|
17
|
+
const cityInput = parameters?.cityInput || "Santiago"
|
|
18
18
|
const msj0 = parameters?.msj0 || 'No hay datos para mostrar'
|
|
19
19
|
const updateTime = 600000
|
|
20
20
|
|
|
21
21
|
useEffect(() => {
|
|
22
|
-
|
|
22
|
+
console.log('[App] useEffect triggered | start:', start, '| cityInput:', cityInput, '| updateTime:', updateTime)
|
|
23
|
+
if (!start) {
|
|
24
|
+
console.warn('[App] start=false → skipping fetch')
|
|
25
|
+
return
|
|
26
|
+
}
|
|
23
27
|
|
|
24
28
|
const fetchData = async () => {
|
|
29
|
+
console.log('[App] fetchData: starting fetch for city:', cityInput)
|
|
25
30
|
try {
|
|
26
31
|
const data = await getData(cityInput, updateTime, msj0)
|
|
32
|
+
console.log('[App] fetchData: received data:', data)
|
|
33
|
+
console.log('[App] fetchData: has aqi?', data?.aqi !== undefined, '| aqi value:', data?.aqi)
|
|
27
34
|
setFormattedData(data)
|
|
28
35
|
} catch (error) {
|
|
29
|
-
console.error('
|
|
36
|
+
console.error('[App] fetchData: error:', error)
|
|
30
37
|
setFormattedData(undefined)
|
|
31
38
|
}
|
|
32
39
|
}
|
|
@@ -67,8 +74,7 @@ export const App: React.FunctionComponent<Props> = ({ data, start }) => {
|
|
|
67
74
|
cardGap: parameters?.cardGap,
|
|
68
75
|
aqiFormat: parameters?.aqiFormat,
|
|
69
76
|
stationFormat: parameters?.stationFormat,
|
|
70
|
-
qualityFormat: parameters?.qualityFormat
|
|
71
|
-
positionCard: parameters?.positionCard
|
|
77
|
+
qualityFormat: parameters?.qualityFormat
|
|
72
78
|
}} />
|
|
73
79
|
</div>
|
|
74
80
|
) : (
|
package/src/components/Card.tsx
CHANGED
|
@@ -13,7 +13,6 @@ interface Props {
|
|
|
13
13
|
aqiFormat?: TextFormat.Value;
|
|
14
14
|
stationFormat?: TextFormat.Value;
|
|
15
15
|
qualityFormat?: TextFormat.Value;
|
|
16
|
-
positionCard?: string;
|
|
17
16
|
};
|
|
18
17
|
}
|
|
19
18
|
|
|
@@ -26,8 +25,7 @@ export const Card: React.FunctionComponent<Props> = ({ data, format }) => {
|
|
|
26
25
|
display: 'flex',
|
|
27
26
|
width: `${format.cardWidth || 300}px`,
|
|
28
27
|
height: `${format.cardHeight || 200}px`,
|
|
29
|
-
flexDirection:
|
|
30
|
-
alignItems: `${format.positionCard === 'horizontal' ? 'center' : ''}`,
|
|
28
|
+
flexDirection: 'column',
|
|
31
29
|
backgroundColor: color,
|
|
32
30
|
borderRadius: "10px"
|
|
33
31
|
}}>
|
package/src/parameters.d.ts
CHANGED
|
@@ -6,7 +6,6 @@ declare type VixonicData = {
|
|
|
6
6
|
|
|
7
7
|
declare type VixonicParameters = Partial<{
|
|
8
8
|
backgroundImage: { id?: string; filename?: string; extension?: string }
|
|
9
|
-
positionCard: 'horizontal' | 'vertical'
|
|
10
9
|
topSeparationCard: number
|
|
11
10
|
leftSeparationCard: number
|
|
12
11
|
cardWidth: number
|
package/src/services/index.ts
CHANGED
|
@@ -3,8 +3,9 @@ import localforage from 'localforage'
|
|
|
3
3
|
import { AirQuality, AqiData, StorageData } from '../types'
|
|
4
4
|
import { API_RESPONSE_STATUS } from '../utils'
|
|
5
5
|
|
|
6
|
-
if (!process.env.AQI_TOKEN) console.warn('Env variable not found. Skipping API call.')
|
|
6
|
+
if (!process.env.AQI_TOKEN) console.warn('[AQI] Env variable AQI_TOKEN not found. Skipping API call.')
|
|
7
7
|
const TOKEN = process.env.AQI_TOKEN
|
|
8
|
+
console.log('[AQI] Token loaded:', TOKEN ? `${TOKEN.slice(0, 4)}...` : 'MISSING')
|
|
8
9
|
|
|
9
10
|
const refetchData = (referenceDate: Date, updateTime: number): boolean => {
|
|
10
11
|
const now = new Date()
|
|
@@ -15,26 +16,34 @@ const refetchData = (referenceDate: Date, updateTime: number): boolean => {
|
|
|
15
16
|
|
|
16
17
|
if (sameYear && sameMonth && sameDay) {
|
|
17
18
|
const differenceMilliseconds = Math.abs(now.getTime() - referenceDate.getTime())
|
|
18
|
-
|
|
19
|
+
const shouldRefetch = differenceMilliseconds >= updateTime
|
|
20
|
+
console.log(`[AQI] refetchData: same day, elapsed=${differenceMilliseconds}ms, updateTime=${updateTime}ms, shouldRefetch=${shouldRefetch}`)
|
|
21
|
+
return shouldRefetch
|
|
19
22
|
}
|
|
23
|
+
console.log('[AQI] refetchData: different day → forcing refetch')
|
|
20
24
|
return true
|
|
21
25
|
}
|
|
22
26
|
|
|
23
27
|
const requestData = async (cityInput: string): Promise<AirQuality | null> => {
|
|
24
28
|
const URL = `https://api.waqi.info/feed/${cityInput}/?token=${TOKEN}`
|
|
29
|
+
console.log('[AQI] requestData: calling API for city:', cityInput)
|
|
25
30
|
try {
|
|
26
31
|
const response = await axios.get<AirQuality>(URL)
|
|
32
|
+
console.log('[AQI] requestData: HTTP status:', response?.status)
|
|
33
|
+
console.log('[AQI] requestData: response data:', JSON.stringify(response?.data, null, 2))
|
|
27
34
|
if (response?.status === 200) {
|
|
28
35
|
return response.data
|
|
29
36
|
}
|
|
37
|
+
console.warn('[AQI] requestData: unexpected HTTP status, returning null')
|
|
30
38
|
return null
|
|
31
39
|
} catch (error) {
|
|
32
|
-
console.error('Error fetching AQI data:', error)
|
|
40
|
+
console.error('[AQI] requestData: Error fetching AQI data:', error)
|
|
33
41
|
return null
|
|
34
42
|
}
|
|
35
43
|
}
|
|
36
44
|
|
|
37
45
|
const processData = (response: AirQuality | null, cityInput: string, defaultMsg: string): AqiData => {
|
|
46
|
+
console.log('[AQI] processData: raw response status:', response?.status)
|
|
38
47
|
let data: AqiData = { city: cityInput, station: defaultMsg }
|
|
39
48
|
if (response?.status === API_RESPONSE_STATUS.OK) {
|
|
40
49
|
data = {
|
|
@@ -42,20 +51,33 @@ const processData = (response: AirQuality | null, cityInput: string, defaultMsg:
|
|
|
42
51
|
city: cityInput,
|
|
43
52
|
station: response.data.city.name
|
|
44
53
|
}
|
|
54
|
+
console.log('[AQI] processData: API OK → processed data:', data)
|
|
55
|
+
} else {
|
|
56
|
+
console.warn('[AQI] processData: API status is not OK → using default message. Response:', response)
|
|
45
57
|
}
|
|
46
58
|
return data
|
|
47
59
|
}
|
|
48
60
|
|
|
49
61
|
export const getData = async (cityInput: string, updateTime: number, defaultMsg: string): Promise<AqiData> => {
|
|
62
|
+
console.log('[AQI] getData called with city:', cityInput, '| updateTime:', updateTime, '| defaultMsg:', defaultMsg)
|
|
50
63
|
const storageData: StorageData | null = await localforage.getItem('aqi')
|
|
64
|
+
console.log('[AQI] getData: cached data:', storageData ? { city: storageData.item?.city, date: storageData.date, aqi: storageData.item?.aqi } : 'null')
|
|
65
|
+
|
|
51
66
|
let data
|
|
52
67
|
if (!storageData?.item || storageData?.item.city !== cityInput || !storageData?.date || refetchData(new Date(storageData.date), updateTime)) {
|
|
68
|
+
console.log('[AQI] getData: cache MISS or stale → fetching from API')
|
|
53
69
|
data = await requestData(cityInput)
|
|
54
70
|
const processedData = processData(data, cityInput, defaultMsg)
|
|
55
|
-
|
|
71
|
+
if (processedData.aqi !== undefined) {
|
|
72
|
+
await localforage.setItem('aqi', { item: processedData, date: new Date() })
|
|
73
|
+
console.log('[AQI] getData: saved to cache and returning:', processedData)
|
|
74
|
+
} else {
|
|
75
|
+
console.warn('[AQI] getData: data invalid (no aqi) → skipping cache save')
|
|
76
|
+
}
|
|
56
77
|
return processedData
|
|
57
78
|
} else {
|
|
58
79
|
data = storageData.item
|
|
80
|
+
console.log('[AQI] getData: cache HIT → returning cached data:', data)
|
|
59
81
|
return data
|
|
60
82
|
}
|
|
61
83
|
}
|
package/src/test/parameters.json
CHANGED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
name: Deploy job
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
pull_request:
|
|
5
|
-
branches:
|
|
6
|
-
- master
|
|
7
|
-
types: [closed]
|
|
8
|
-
workflow_dispatch:
|
|
9
|
-
|
|
10
|
-
jobs:
|
|
11
|
-
build:
|
|
12
|
-
name: Build and Publish Package
|
|
13
|
-
runs-on: ubuntu-latest
|
|
14
|
-
environment: production
|
|
15
|
-
if: github.event_name == 'workflow_dispatch' || github.event.pull_request.merged == true
|
|
16
|
-
|
|
17
|
-
outputs:
|
|
18
|
-
version: ${{ steps.extract_version.outputs.version }}
|
|
19
|
-
deployment-start: ${{ steps.deployment_start.outputs.deployment_start }}
|
|
20
|
-
|
|
21
|
-
steps:
|
|
22
|
-
- name: Log deployment start
|
|
23
|
-
id: deployment_start
|
|
24
|
-
run: |
|
|
25
|
-
echo "deployment_start=$(date +"%Y-%m-%dT%H:%M:%S%:z")" >> "$GITHUB_OUTPUT"
|
|
26
|
-
|
|
27
|
-
- name: Checkout repository
|
|
28
|
-
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
29
|
-
with:
|
|
30
|
-
fetch-depth: 0
|
|
31
|
-
token: ${{ secrets.PRIVATE_TOKEN_GITHUB }}
|
|
32
|
-
|
|
33
|
-
- name: Setup Node.js 20
|
|
34
|
-
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
|
35
|
-
with:
|
|
36
|
-
node-version: '20'
|
|
37
|
-
registry-url: 'https://registry.npmjs.org'
|
|
38
|
-
scope: '@vixoniccom'
|
|
39
|
-
|
|
40
|
-
- name: Configure npm authentication
|
|
41
|
-
run: |
|
|
42
|
-
echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc
|
|
43
|
-
echo "@vixoniccom:registry=https://registry.npmjs.org/" >> ~/.npmrc
|
|
44
|
-
echo "registry=https://registry.npmjs.org/" >> ~/.npmrc
|
|
45
|
-
|
|
46
|
-
- name: Cache node modules
|
|
47
|
-
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
|
|
48
|
-
with:
|
|
49
|
-
path: ~/.npm
|
|
50
|
-
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
|
51
|
-
restore-keys: |
|
|
52
|
-
${{ runner.os }}-node-
|
|
53
|
-
|
|
54
|
-
- name: Install dependencies
|
|
55
|
-
run: npm ci
|
|
56
|
-
env:
|
|
57
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
58
|
-
|
|
59
|
-
- name: Bump version
|
|
60
|
-
run: |
|
|
61
|
-
git config user.name "github-actions[bot]"
|
|
62
|
-
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
63
|
-
npm run release -- --no-verify
|
|
64
|
-
git push --follow-tags origin main
|
|
65
|
-
env:
|
|
66
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
67
|
-
|
|
68
|
-
- name: Extract changelog for this release
|
|
69
|
-
id: changelog
|
|
70
|
-
run: |
|
|
71
|
-
BODY=$(awk '/^## \[/{if(p) exit; p=1} p' CHANGELOG.md)
|
|
72
|
-
echo "body<<EOF" >> $GITHUB_OUTPUT
|
|
73
|
-
echo "$BODY" >> $GITHUB_OUTPUT
|
|
74
|
-
echo "EOF" >> $GITHUB_OUTPUT
|
|
75
|
-
|
|
76
|
-
- name: Extract version from package.json
|
|
77
|
-
id: extract_version
|
|
78
|
-
run: echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
|
|
79
|
-
|
|
80
|
-
- name: Build package
|
|
81
|
-
run: npm run prepublish
|
|
82
|
-
env:
|
|
83
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
84
|
-
|
|
85
|
-
- name: Verify build.zip exists
|
|
86
|
-
run: |
|
|
87
|
-
if [ ! -f "build.zip" ]; then
|
|
88
|
-
echo "❌ Error: build.zip not found after build process"
|
|
89
|
-
exit 1
|
|
90
|
-
fi
|
|
91
|
-
echo "✅ build.zip found successfully"
|
|
92
|
-
ls -la build.zip
|
|
93
|
-
|
|
94
|
-
- name: Publish to npm
|
|
95
|
-
run: npm publish --access public
|
|
96
|
-
env:
|
|
97
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
98
|
-
|
|
99
|
-
- name: Create GitHub Release
|
|
100
|
-
uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2
|
|
101
|
-
with:
|
|
102
|
-
tag_name: v${{ steps.extract_version.outputs.version }}
|
|
103
|
-
name: v${{ steps.extract_version.outputs.version }}
|
|
104
|
-
body: ${{ steps.changelog.outputs.body }}
|
|
105
|
-
files: build.zip
|
|
106
|
-
env:
|
|
107
|
-
GITHUB_TOKEN: ${{ secrets.PRIVATE_TOKEN_GITHUB }}
|
|
108
|
-
|
|
109
|
-
report-ep:
|
|
110
|
-
name: Report EP Metrics
|
|
111
|
-
runs-on: ubuntu-latest
|
|
112
|
-
needs: [build]
|
|
113
|
-
if: always()
|
|
114
|
-
|
|
115
|
-
steps:
|
|
116
|
-
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
117
|
-
with:
|
|
118
|
-
fetch-depth: 0
|
|
119
|
-
token: ${{ secrets.PRIVATE_TOKEN_GITHUB }}
|
|
120
|
-
|
|
121
|
-
- uses: vismagroup/Jira-SDOP-Reporter@v1
|
|
122
|
-
with:
|
|
123
|
-
token: ${{ github.token }}
|
|
124
|
-
deployment-start: ${{ needs.build.outputs.deployment-start }}
|
|
125
|
-
deployment-status: ${{ needs.build.result == 'success' && 'success' || 'failure' }}
|
|
126
|
-
jira-token: ${{ secrets.JIRA_TOKEN }}
|
|
127
|
-
jira-issue-summary: "store-gallery-image release v${{ needs.build.outputs.version }}"
|
|
128
|
-
jira-issue-project: "SDOP"
|
|
129
|
-
jira-issue-components: |
|
|
130
|
-
${{ secrets.EP_JIRA_COMPONENT }}
|
|
131
|
-
jira-issue-build-info: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|