Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 20ca1996 authored by Nicolas Gelot's avatar Nicolas Gelot
Browse files

Merge branch 'dev/from-express-to-vite' into 'main'

Move project from express to vite

See merge request !27
parents cdc41cd7 4ebccefb
Loading
Loading
Loading
Loading

.dockerignore

deleted100644 → 0
+0 −2
Original line number Diff line number Diff line
node_modules
app/Dockerfile
 No newline at end of file

CONTRIBUTING.md

0 → 100644
+141 −0
Original line number Diff line number Diff line
# Contributing

## Install

[nodeJS](https://nodejs.org/en/download)

## Launch the app

```
npm install
npm run dev
```

Open chrome base browser and go to http://localhost:5173/.

## Add a new device

1. Get the device code from the stock ROM
    - We link device and its resources with deviceName.toLowerCase().replace(/ /g, ''); ex: One Plus Nord -> oneplusnord.json
    - Since the deviceName may not be the same in fastboot (Android), we need at least a first connexion in adb to retrieve the deviceName
2. Understand how does the flash process works
3. Configure the flash process
    - Define the steps in an array of objects describing the process
        - template: 
            ```json 
            "steps": [
                {
                  "mode": string?,
                  "command" : string?,
                  "instruction": string?,
                  "needUser": boolean?
                }
              ]
            ```
        - Options
    
            | key           | exemple                         | description                                                                 |
            |---------------|---------------------------------|-----------------------------------------------------------------------------|
            | `mode`        | `[fastboot\| adb\| bootloader]` | It's a shortcut for a reboot and a reconnect before the command is executed |
            | `needUser`    | `[true\| false]`                | The user needs to click on continue before the command is executed          |
            | `instruction` | `Please select unlock`          | String displayed to the user at this step. Command is used if not defined   |
            | `command`     | `flashing unlock unlocked`      | Command as defined in the next chapter                                      |
        - Available commands
    
            | command                                | exemple                    | description     |
            |----------------------------------------|----------------------------|-----------------|
            | `[flashing\| oem] unlock [varName?]`   | `flashing unlock unlocked` | --------------  |
            | `[flashing\|oem] lock [varName?]`      | `flashing lock`            | --------------  |
            | `flash [partitionName] [fileName.img]` | `flashing unlock unlocked` | --------------  |
            | `sideload [fileName.zip]`              | `sideload romFile.zip`     | --------------  |
            | `erase [partitionName]`                | `erase userdata`           | --------------  |
            | `reboot [fastboot\| adb\| bootloader]` | `reboot bootloader`        | --------------  |
            | `connect [adb\| bootloader]`           | `connect device`           | --------------  |

        > For oem, recovery, rom and key, we parse these command and execute them. The others commands are not analyzed and executed arbitrarily in the device.
      
    - Define the folder, an array describing the files involved in the flash process
        - template: 
            ```json
            "folder": [
              { 
                "name" : "filename.zip", # fileName used for the command.
                "path": "https://domain.com/image.zip", # path used to download the file.
                "unzip": true # optional boolean in case we have a zip we want to uncompress. 
              }
            ]
            ```

            > In case of unzip : the file is unzipped, and the retrieved files are stored in the "folder" like the other file
        - example:
    
            ```json
            {
                "folder": [
                  {
                    "name": "recovery.img"
                    "path" : "assets/sources/coral/recovery-e-latest-s-community-coral.img"
                  },
                  {
                    "name": "rom.zip",
                    "path" : "assets/sources/coral/e-latest-s-community-coral.zip"
                  },
                  {
                    "name": "pkmd_pixel.bin",
                    "path" : "assets/sources/coral/pkmd_pixel.bin"
                  },
                  {
                    "path" : "assets/sources/emerald/IMG-e-latest-s-official-emerald.zip",
                    "name": "Teracube_2e installer",
                    "unzip": true 
                  },
                ]
            }
            ```
4. Adding images
    - Add the images files within `app/public/assets/images/illustrations/fp5`
    - declare the image in the html, at `app/index.html`
        - example:
            ```html
            <!-- FP5 -->
            <div id="locking-fp5" class="card inactive">
                <div class="card-header" data-translate="locking"></div>
                <div class="card-body">
                    <p data-translate="locking-instructions-1"></p>
                    <p data-translate="locking-instructions-2"></p>
                    <div class="text-center">
                        <img class="instruction-img" src="assets/images/illustrations/fp5/Illustration - Accept warning-1.png">
                    </div>
                </div>
                <div class="card-footer">
                    <button data-translate="next" class="next"></button>
                </div>
            </div>
            ```

## Other

- Vues
    - `vue.manager.js`
        - Need log.manager.js and translation.manager.js
        - Need a div with id "process"
    - `log.manager.js`
        - Need a div with id "log-ctn" to scroll on log added
        - Need a select with id "log" to add log
    - `translation.manager.js`
        - Need a select with id "translation" to listen to.
        - On select change : download the translation file and render the DOM
    - Translation are in `static/assets/languages`
- Controller
    - `controller.manager.js`

## Doctrine

- my-class are for css class
- camelCase are for variable
- $variableName are for DOM Nodes
- MAJUSCULE are for global constant
- object.manager.js are for class directing subClass or vue. It's just my arbitrary concept to mark a class as "directive" in the process
- object.class.js are for class used by object.manager.js where functions should have a single responsibility

Please respect ♥
+4 −134
Original line number Diff line number Diff line
@@ -23,142 +23,13 @@ Install /e/OS from a chromium-based browser
    - Linux: `docker run -v "$(pwd)/src:/app/src" -p 127.0.0.1:3000:3000 eos-installer`
3. The app is available at `http://localhost:3000/`

## Usage
## Supportted devices

The list of supported devices is available [here](https://gitlab.e.foundation/e/devices/eos-installer/-/tree/main/app/public/resources).

## Contributing

### Build

```shell
docker build -t eos-installer app/.
```

### Add a new device

1. Get the device code from the stock ROM
    - We link device and its resources with deviceName.toLowerCase().replace(/ /g, ''); ex: One Plus Nord -> oneplusnord.json
    - Since the deviceName may not be the same in fastboot (Android), we need at least a first connexion in adb to retrieve the deviceName
2. Understand how does the flash process works
3. Configure the flash process
    - Define the steps in an array of objects describing the process
        - template: 
            ```json 
            "steps": [
                {
                  "mode": string?,
                  "command" : string?,
                  "instruction": string?,
                  "needUser": boolean?
                }
              ]
            ```
        - Options
    
            | key           | exemple                         | description                                                                 |
            |---------------|---------------------------------|-----------------------------------------------------------------------------|
            | `mode`        | `[fastboot\| adb\| bootloader]` | It's a shortcut for a reboot and a reconnect before the command is executed |
            | `needUser`    | `[true\| false]`                | The user needs to click on continue before the command is executed          |
            | `instruction` | `Please select unlock`          | String displayed to the user at this step. Command is used if not defined   |
            | `command`     | `flashing unlock unlocked`      | Command as defined in the next chapter                                      |
        - Available commands
    
            | command                                | exemple                    | description     |
            |----------------------------------------|----------------------------|-----------------|
            | `[flashing\| oem] unlock [varName?]`   | `flashing unlock unlocked` | --------------  |
            | `[flashing\|oem] lock [varName?]`      | `flashing lock`            | --------------  |
            | `flash [partitionName] [fileName.img]` | `flashing unlock unlocked` | --------------  |
            | `sideload [fileName.zip]`              | `sideload romFile.zip`     | --------------  |
            | `erase [partitionName]`                | `erase userdata`           | --------------  |
            | `reboot [fastboot\| adb\| bootloader]` | `reboot bootloader`        | --------------  |
            | `connect [adb\| bootloader]`           | `connect device`           | --------------  |

        > For oem, recovery, rom and key, we parse these command and execute them. The others commands are not analyzed and executed arbitrarily in the device.
      
    - Define the folder, an array describing the files involved in the flash process
        - template: 
            ```json
            "folder": [
              { 
                name : fileName used for the command ,
                path: path used to download the file,
                unzip: optional boolean in case we have a zip we want to parse
              }
            ]
            ```

            > In case of unzip : the file is unzipped, and the retrieved files are stored in the "folder" like the other file
        - example:
    
            ```json
            {
                "folder": [
                  {
                    "name": "recovery.img"
                    "path" : "assets/sources/coral/recovery-e-1.14-s-20230818321663-dev-coral.img"
                  },
                  {
                    "name": "rom.zip",
                    "path" : "assets/sources/coral/e-1.14-s-20230818321663-dev-coral.zip"
                  },
                  {
                    "name": "pkmd_pixel.bin",
                    "path" : "assets/sources/coral/pkmd_pixel.bin"
                  },
                  {
                    "path" : "assets/sources/emerald/IMG-e-1.14.2-s-20230825321006-stable-emerald.zip", 
                    "name": "Teracube_2e installer",
                    "unzip": true 
                  },
                ]
            }
            ```
4. Adding images
    - Add the images files within `app/src/static/assets/images/illustrations/fp5`
    - declare the image in the html, at `app/src/static/index.html`
        - example:
            ```html
            <!-- FP5 -->
            <div id="locking-fp5" class="card inactive">
                <div class="card-header" data-translate="locking"></div>
                <div class="card-body">
                    <p data-translate="locking-instructions-1"></p>
                    <p data-translate="locking-instructions-2"></p>
                    <div class="text-center">
                        <img class="instruction-img" src="assets/images/illustrations/fp5/Illustration - Accept warning-1.png">
                    </div>
                </div>
                <div class="card-footer">
                    <button data-translate="next" class="next" onclick="VIEW.onNext(this, 'locking-fp5')"></button>
                </div>
            </div>
            ```

### Other

- Vues
    - `vue.manager.js`
        - Need log.manager.js and translation.manager.js
        - Need a div with id "process"
    - `log.manager.js`
        - Need a div with id "log-ctn" to scroll on log added
        - Need a select with id "log" to add log
    - `translation.manager.js`
        - Need a select with id "translation" to listen to.
        - On select change : download the translation file and render the DOM
    - Translation are in `static/assets/languages`
- Controller
    - `controller.manager.js`

### Doctrine

- my-class are for css class
- camelCase are for variable
- $variableName are for DOM Nodes
- MAJUSCULE are for global constant
- object.manager.js are for class directing subClass or vue. It's just my arbitrary concept to mark a class as "directive" in the process
- object.class.js are for class used by object.manager.js where functions should have a single responsibility

Please respect ♥
See [CONTRIBUTING.md](CONTRIBUTING.md).

## License

@@ -173,4 +44,3 @@ Using:
Libraries:
- fastboot.js (License: MIT): https://github.com/kdrag0n/fastboot.js/ 
- ya-webadb (License: MIT): https://github.com/yume-chan/ya-webadb
- zip-no-worker-inflate.js (License: BSD3): https://github.com/gildas-lormeau/zip.js/blob/master/lib/zip-no-worker-inflate.js
+6 −6
Original line number Diff line number Diff line
# syntax=docker/dockerfile:1
   
FROM node:22-alpine
FROM node:23-alpine AS builder
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]
EXPOSE 3000
RUN npm install && npm run build

FROM nginx:1.27.3

COPY --from=builder /app/dist /usr/share/nginx/html
+42 −56
Original line number Diff line number Diff line
@@ -5,13 +5,12 @@
    <meta name="viewport"
          content="width=device-width, initial-scale=1, shrink-to-fit=no, maximum-scale=1.0, user-scalable=0"/>
    <meta name="version" content="0.7.1"/>
    <link rel="stylesheet" href="css/styles.css"/>
    <link rel="stylesheet" href="css/loader.css"/>
    <link rel="stylesheet" href="/css/styles.css"/>
    <link rel="stylesheet" href="/css/loader.css"/>
    <title>/e/OS Installer</title>
    <script src="js/lib/zip/zip-no-worker-inflate.min.js"></script>
    <script src="js/lib/webadb/adb.bundle.js"></script>
    <script src="js/viewManager.js"></script>
    <script src="js/before-leave-app.js"></script>
    <script type="module" src="/src/lib/webadb/adb.bundle.js"></script>
    <script type="module" src="/src/viewManager.js"></script>
    <script type="module" src="/src/before-leave-app.js"></script>
    <script>
        window.onload = function() {
            if ('usb' in navigator) {
@@ -101,7 +100,7 @@
            </div>
        </div>
        <div class="card-footer" id="let-s-get-started-button">
            <button class="next" onclick="VIEW.executeStep(this, 'let-s-get-started')">
            <button class="next">
                <span data-translate="i-m-ready"></span>
                <span class="btn-loader"></span>
            </button>
@@ -118,7 +117,7 @@
            <p class="secondary" data-translate="connect-your-phone-instructions-notes"></p>
        </div>
        <div class="card-footer">
            <button class="next" onclick="VIEW.executeStep(this, 'connect-your-phone')">
            <button class="next">
                <span data-translate="next"></span>
                <span class="btn-loader"></span>
            </button>
@@ -138,7 +137,7 @@
            </div>
        </div>
        <div class="card-footer">
            <button class="next" onclick="VIEW.executeStep(this, 'activate-developer-options')">
            <button class="next">
                <span data-translate="next"></span>
                <span class="btn-loader"></span>
            </button>
@@ -154,7 +153,7 @@
            </div>
        </div>
        <div class="card-footer">
            <button class="next" onclick="VIEW.executeStep(this, 'activate-oem-unlock')">
            <button class="next">
                <span data-translate="next"></span>
                <span class="btn-loader"></span>
            </button>
@@ -173,7 +172,7 @@
            </div>
        </div>
        <div class="card-footer">
            <button class="next" onclick="VIEW.executeStep(this, 'activate-usb-debugging')">
            <button class="next">
                <span data-translate="next"></span>
                <span class="btn-loader"></span>
            </button>
@@ -192,7 +191,7 @@
            </div>
        </div>
        <div class="card-footer">
            <button class="next" onclick="VIEW.executeStep(this, 'enable-usb-file-transfer')">
            <button class="next">
                <span data-translate="next"></span>
                <span class="btn-loader"></span>
            </button>
@@ -210,15 +209,15 @@
                <img class="instruction-img" src="assets/images/illustrations/allow-usb-debugging-2.png">
                <p data-translate="device-detection-instructions-2"></p>
            </div>
            <div class="text-center instruction-title">
        </div>
        <div class="card-footer">
            <p data-translate="device-detection-instructions-3"></p>
                <button class="connect" onclick="VIEW.executeStep(this, 'device-detection')">
            <button class="connect">
                <span data-translate="connect"></span>
                <span class="btn-loader"></span>
            </button>
        </div>
    </div>
    </div>

    <div id="device-model-not-supported" class="device-model-not-supported card inactive">
        <div class="card-header" data-translate="device-model-not-supported"></div>
@@ -255,14 +254,14 @@
        <div class="card-body">
            <p data-translate="connect-bootloader-instructions-1"></p>
            <p data-translate="connect-bootloader-instructions-2"></p>
            <div class="text-center">
                <button class="connect" onclick="VIEW.executeStep(this, 'connect-bootloader')">
        </div>
        <div class="card-footer">
            <button class="connect">
                <span data-translate="connect"></span>
                <span class="btn-loader"></span>
            </button>
        </div>
    </div>
    </div>
    <!-- Start UNLOCKING -->
    <!-- GS290-->
    <div id="unlocking-gs290" class="card inactive">
@@ -275,7 +274,7 @@
            <p data-translate="unlocking-instructions-1-teracube-a"></p>
        </div>
        <div class="card-footer">
            <button class="next" onclick="VIEW.executeStep(this, 'unlocking-gs290')">
            <button class="next">
                <span data-translate="next"></span>
                <span class="btn-loader"></span>
            </button>
@@ -295,7 +294,7 @@
            </div>
        </div>
        <div class="card-footer">
            <button class="next" onclick="VIEW.executeStep(this, 'unlocking-fp3')">
            <button class="next">
                <span data-translate="next"></span>
                <span class="btn-loader"></span>
            </button>
@@ -315,7 +314,7 @@
            </div>
        </div>
        <div class="card-footer">
            <button class="next" onclick="VIEW.executeStep(this, 'unlocking-fp4')">
            <button class="next">
                <span data-translate="next"></span>
                <span class="btn-loader"></span>
            </button>
@@ -332,7 +331,7 @@
            </div>
        </div>
        <div class="card-footer">
            <button class="next" onclick="VIEW.executeStep(this, 'unlocking-teracube-v1')">
            <button class="next">
                <span data-translate="next"></span>
                <span class="btn-loader"></span>
            </button>
@@ -348,7 +347,7 @@
            </div>
        </div>
        <div class="card-footer">
            <button class="next" onclick="VIEW.executeStep(this, 'unlocking-teracube-v2')">
            <button class="next">
                <span data-translate="next"></span>
                <span class="btn-loader"></span>
            </button>
@@ -369,7 +368,7 @@
            </div>
        </div>
        <div class="card-footer">
            <button class="next" onclick="VIEW.executeStep(this, 'unlocking-pixel')">
            <button class="next">
                <span data-translate="next"></span>
                <span class="btn-loader"></span>
            </button>
@@ -390,7 +389,7 @@
            </div>
        </div>
        <div class="card-footer">
            <button class="next" onclick="VIEW.executeStep(this, 'unlocking-oneplus')">
            <button class="next">
                <span data-translate="next"></span>
                <span class="btn-loader"></span>
            </button>
@@ -407,7 +406,7 @@
            <p data-translate="unlocking-instructions-4"></p>
        </div>
        <div class="card-footer">
            <button class="next" onclick="VIEW.executeStep(this, 'unlocking')">
            <button class="next">
                <span data-translate="next"></span>
                <span class="btn-loader"></span>
            </button>
@@ -436,7 +435,7 @@
            <p data-translate="bootloader-to-recovery-manually-instructions-3"></p>
        </div>
        <div class="card-footer">
            <button class="next" onclick="VIEW.executeStep(this, 'bootloader-to-recovery-manually')">
            <button class="next">
                <span data-translate="next"></span>
                <span class="btn-loader"></span>
            </button>
@@ -456,7 +455,7 @@
            <p data-translate="format-device-instructions-7"></p>
        </div>
        <div class="card-footer">
            <button class="next" onclick="VIEW.executeStep(this, 'format-device')">
            <button class="next">
                <span data-translate="next"></span>
                <span class="btn-loader"></span>
            </button>
@@ -471,7 +470,7 @@
            <p class="secondary" data-translate="go-to-apply-update-instructions-4"></p>
        </div>
        <div class="card-footer">
            <button class="next" onclick="VIEW.executeStep(this, 'go-to-apply-update')">
            <button class="next">
                <span data-translate="next"></span>
                <span class="btn-loader"></span>
            </button>
@@ -496,7 +495,7 @@
            <p data-translate="recovery-to-bootloader-instructions-2"></p>
        </div>
        <div class="card-footer">
            <button data-translate="next" class="next" onclick="VIEW.onNext(this)"></button>
            <button data-translate="next" class="next"></button>
        </div>
    </div>
    <!-- Start LOCKING -->
@@ -511,7 +510,7 @@
            </div>
        </div>
        <div class="card-footer">
            <button data-translate="next" class="next" onclick="VIEW.onNext(this, 'locking-fp3')"></button>
            <button data-translate="next" class="next"></button>
        </div>
    </div>
    <!-- FP4 -->
@@ -525,7 +524,7 @@
            </div>
        </div>
        <div class="card-footer">
            <button data-translate="next" class="next" onclick="VIEW.onNext(this, 'locking-fp4')"></button>
            <button data-translate="next" class="next"></button>
        </div>
    </div>
    <!-- Teracube -->
@@ -540,7 +539,7 @@
            <p data-translate="locking-instructions-3"></p>
        </div>
        <div class="card-footer">
            <button class="next" onclick="VIEW.executeStep(this, 'locking-teracube-v2')">
            <button class="next">
                <span data-translate="next"></span>
                <span class="btn-loader"></span>
            </button>
@@ -557,7 +556,7 @@
            <p data-translate="locking-instructions-4"></p>
        </div>
        <div class="card-footer">
            <button data-translate="next" class="next" onclick="VIEW.onNext(this, 'locking-pixel')"></button>
            <button data-translate="next" class="next"></button>
        </div>
    </div>
    <!-- All other -->
@@ -568,7 +567,7 @@
            <p data-translate="locking-instructions-2"></p>
        </div>
        <div class="card-footer">
            <button data-translate="next" class="next" onclick="VIEW.onNext(this)"></button>
            <button data-translate="next" class="next"></button>
        </div>
    </div>
    <!-- End LOCKING -->
@@ -582,7 +581,7 @@
            <a href="https://murena.io" target="_blank">murena.io</a>
        </div>
        <div class="card-footer">
            <button data-translate="next" class="next" onclick="VIEW.onNext(this)"></button>
            <button data-translate="next" class="next"></button>
        </div>
    </div>
    <div id="installation-complete" class="card inactive">
@@ -628,17 +627,4 @@
    </div>
</div>
</body>
<script>
    function sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }

    var VIEW = new ViewManager();
    var exports = {};
    document.addEventListener('DOMContentLoaded', async () => {
        await VIEW.init();
    });

    
</script>
</html>
Loading