Skip to content

Commit

Permalink
adds: Symfony UX Controller online/offline status (#98)
Browse files Browse the repository at this point in the history
adds: Symfony UX Controller online/offline status
  • Loading branch information
Spomky authored Mar 5, 2024
1 parent ed0cd40 commit cbe1cb9
Show file tree
Hide file tree
Showing 21 changed files with 549 additions and 25 deletions.
7 changes: 6 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,9 @@
/phpstan.neon export-ignore
/phpstan-baseline.neon export-ignore
/phpunit.xml.dist export-ignore
/rector export-ignore
/rector.php export-ignore
/bin export-ignore
/babel.config.js export-ignore
/jest.config.js export-ignore
/rollup.config.js export-ignore
/tsconfig.json export-ignore
18 changes: 18 additions & 0 deletions .github/workflows/exported_files.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: Exported files

on: [push]

jobs:
tests:
runs-on: ubuntu-latest
steps:
- name: "Checkout code"
uses: "actions/checkout@v4"

- name: "Check exported files"
run: |
EXPECTED="LICENSE,README.md,RELEASES.md,SECURITY.md,composer.json,package.json"
CURRENT="$(git archive HEAD | tar --list --exclude="assets" --exclude="assets/*" --exclude="src" --exclude="src/*" | paste -s -d ",")"
echo "CURRENT =${CURRENT}"
echo "EXPECTED=${EXPECTED}"
test "${CURRENT}" == "${EXPECTED}"
9 changes: 7 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/vendor/
.phpunit.result.cache
*.cache
*.log
node_modules
package-lock.json
/composer.lock
/.phpunit.cache
/vendor
/.phpunit.cache/
20 changes: 10 additions & 10 deletions CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@ In the interest of fostering an open and welcoming environment, we as contributo

Examples of behavior that contributes to creating a positive environment include:

* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
- The use of sexualized language or imagery and unwelcome sexual attention or advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting

## Our Responsibilities

Expand Down
13 changes: 6 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
Progressive Web App for Symfony
===============================
# Progressive Web App for Symfony

![Build Status](https://github.com/Spomky-Labs/pwa-bundle/workflows/Coding%20Standards/badge.svg)
![Build Status](https://github.com/Spomky-Labs/pwa-bundle/workflows/Static%20Analyze/badge.svg)
Expand All @@ -24,7 +23,7 @@ Please have a look at the [Web app manifests](https://developer.mozilla.org/en-U

# Installation

Install the bundle with Composer:
Install the bundle with Composer:

```bash
composer require spomky-labs/pwa-bundle
Expand All @@ -42,9 +41,9 @@ I bring solutions to your problems and answer your questions.

If you really love that project and the work I have done or if you want I prioritize your issues, then you can help me out for a couple of :beers: or more!

* [Become a sponsor](https://github.com/sponsors/Spomky)
* [Become a Patreon](https://www.patreon.com/FlorentMorselli)
* [Buy me a coffee](https://www.buymeacoffee.com/FlorentMorselli)
- [Become a sponsor](https://github.com/sponsors/Spomky)
- [Become a Patreon](https://www.patreon.com/FlorentMorselli)
- [Buy me a coffee](https://www.buymeacoffee.com/FlorentMorselli)

# Contributing

Expand All @@ -58,7 +57,7 @@ Please make sure to [follow these best practices](.github/CONTRIBUTING.md).
# Security Issues

If you discover a security vulnerability within the project, please **don't use the bug tracker and don't publish it publicly**.
Instead, all security issues must be sent to security [at] spomky-labs.com.
Instead, all security issues must be sent to security [at] spomky-labs.com.

# Licence

Expand Down
2 changes: 1 addition & 1 deletion RELEASES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
## Supported Versions

| Version | Supported |
|---------|--------------------|
| ------- | ------------------ |
| 1.0.x | :white_check_mark: |
| < 1.0.x | :x: |
21 changes: 21 additions & 0 deletions assets/dist/controller.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Controller } from '@hotwired/stimulus';
export default class extends Controller {
static targets: string[];
static values: {
onlineMessage: {
type: StringConstructor;
default: string;
};
offlineMessage: {
type: StringConstructor;
default: string;
};
};
readonly onlineMessageValue: string;
readonly offlineMessageValue: string;
readonly attributeTargets: HTMLElement[];
readonly messageTargets: HTMLElement[];
connect(): void;
dispatchEvent(name: any, payload: any): void;
statusChanged(data: any): void;
}
55 changes: 55 additions & 0 deletions assets/dist/controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { Controller } from '@hotwired/stimulus';

var Status;
(function (Status) {
Status["OFFLINE"] = "OFFLINE";
Status["ONLINE"] = "ONLINE";
})(Status || (Status = {}));
class default_1 extends Controller {
connect() {
this.dispatchEvent('connect', {});
if (navigator.onLine) {
this.statusChanged({
status: Status.ONLINE,
message: this.onlineMessageValue,
});
}
else {
this.statusChanged({
status: Status.OFFLINE,
message: this.offlineMessageValue,
});
}
window.addEventListener("offline", () => {
this.statusChanged({
status: Status.OFFLINE,
message: this.offlineMessageValue,
});
});
window.addEventListener("online", () => {
this.statusChanged({
status: Status.ONLINE,
message: this.onlineMessageValue,
});
});
}
dispatchEvent(name, payload) {
this.dispatch(name, { detail: payload, prefix: 'connection-status' });
}
statusChanged(data) {
this.messageTargets.forEach((element) => {
element.innerHTML = data.message;
});
this.attributeTargets.forEach((element) => {
element.setAttribute('data-connection-status', data.status);
});
this.dispatchEvent('status-changed', { detail: data });
}
}
default_1.targets = ['message', 'attribute'];
default_1.values = {
onlineMessage: { type: String, default: 'You are online.' },
offlineMessage: { type: String, default: 'You are offline.' },
};

export { default_1 as default };
1 change: 1 addition & 0 deletions assets/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('../jest.config.js');
28 changes: 28 additions & 0 deletions assets/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "@pwa/connection-status",
"description": "PWA for Symfony",
"license": "MIT",
"version": "1.0.0",
"main": "dist/controller.js",
"types": "dist/controller.d.ts",
"symfony": {
"controllers": {
"connection-status": {
"main": "dist/controller.js",
"name": "pwa/connection-status",
"webpackMode": "eager",
"fetch": "eager",
"enabled": true
}
},
"importmap": {
"@hotwired/stimulus": "^3.0.0"
}
},
"peerDependencies": {
"@hotwired/stimulus": "^3.0.0"
},
"devDependencies": {
"@hotwired/stimulus": "^3.0.0"
}
}
61 changes: 61 additions & 0 deletions assets/src/controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
'use strict';

import { Controller } from '@hotwired/stimulus';

enum Status {
OFFLINE = 'OFFLINE',
ONLINE = 'ONLINE',
}
export default class extends Controller {
static targets = ['message', 'attribute'];
static values = {
onlineMessage: { type: String, default: 'You are online.' },
offlineMessage: { type: String, default: 'You are offline.' },
};

declare readonly onlineMessageValue: string;
declare readonly offlineMessageValue: string;
declare readonly attributeTargets: HTMLElement[];
declare readonly messageTargets: HTMLElement[];

connect() {
this.dispatchEvent('connect', {});
if (navigator.onLine) {
this.statusChanged({
status: Status.ONLINE,
message: this.onlineMessageValue,
});
} else {
this.statusChanged({
status: Status.OFFLINE,
message: this.offlineMessageValue,
});
}

window.addEventListener('offline', () => {
this.statusChanged({
status: Status.OFFLINE,
message: this.offlineMessageValue,
});
});
window.addEventListener('online', () => {
this.statusChanged({
status: Status.ONLINE,
message: this.onlineMessageValue,
});
});
}
dispatchEvent(name, payload) {
this.dispatch(name, { detail: payload, prefix: 'connection-status' });
}

statusChanged(data) {
this.messageTargets.forEach((element) => {
element.innerHTML = data.message;
});
this.attributeTargets.forEach((element) => {
element.setAttribute('data-connection-status', data.status);
});
this.dispatchEvent('status-changed', { detail: data });
}
}
53 changes: 53 additions & 0 deletions assets/test/controller.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
'use strict';

import {Application, Controller} from '@hotwired/stimulus';
import {getByTestId, waitFor} from '@testing-library/dom';
import {clearDOM, mountDOM} from '@symfony/stimulus-testing';
import StatusController from '../src/controller';

// Controller used to check the actual controller was properly booted
class CheckController extends Controller {
connect() {
this.element.addEventListener('pwa-status:connect', () => {
this.element.classList.add('connected');
});
}
}

const startStimulus = () => {
const application: Application = Application.start();
application.register('check', CheckController);
application.register('pwa-status', StatusController);
};

describe('StatusController', () => {
let container: any;

beforeEach(() => {
container = mountDOM(`
<html lang="en">
<head>
<title>Symfony UX</title>
</head>
<body>
<form
data-testid="pwa-status"
data-controller="check pwa-status"
>
</form>
</body>
</html>
`);
});

afterEach(() => {
clearDOM();
});

it('connect', async () => {
expect(getByTestId(container, 'pwa-status')).not.toHaveClass('connected');

startStimulus();
await waitFor(() => expect(getByTestId(container, 'pwa-status')).toHaveClass('connected'));
});
});
7 changes: 7 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = {
presets: [
['@babel/preset-env', {targets: {node: 'current'}}],
'@babel/react',
['@babel/preset-typescript', { allowDeclareFields: true }]
],
};
29 changes: 29 additions & 0 deletions bin/build_javascript.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* This file is used to compile the TypeScript files in the assets/src directory
* of each package.
*
* It allows each package to spawn its own rollup process, which is necessary
* to keep memory usage down.
*/
const { spawnSync } = require('child_process');
const glob = require('glob');

const files = [
...glob.sync('assets/src/*controller.ts'),
];

files.forEach((file) => {
const result = spawnSync('node', [
'node_modules/.bin/rollup',
'-c',
'--environment',
`INPUT_FILE:${file}`,
], {
stdio: 'inherit',
shell: true
});

if (result.error) {
console.error(`Error compiling ${file}:`, result.error);
}
});
Loading

0 comments on commit cbe1cb9

Please sign in to comment.