Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
dea63a5
Add inspection data models
roncodes Jun 17, 2026
aa3d8d0
Add work order category attribute
roncodes Jun 18, 2026
a0105c6
Add is-waypoint-record util
roncodes Aug 7, 2026
0ffa200
Add coverage infrastructure and repair the test harness
roncodes Aug 8, 2026
de91ac3
Cover serializer wire contracts and the driver serializer overrides
roncodes Aug 8, 2026
9b09ca8
Cover model relationship, default and date-formatting contracts
roncodes Aug 8, 2026
9e2063e
Reach 100% coverage of all reachable addon code
roncodes Aug 8, 2026
e0803f7
Add the Codecov badge to the README
roncodes Aug 8, 2026
eeb337d
Correct the README licence to AGPL-3.0-or-later
roncodes Aug 8, 2026
31e1ee9
feat: add trailer data models and serializers
roncodes Sep 3, 2026
10e5d5a
fix: complete Trailer data contracts for the console
roncodes Sep 7, 2026
9fac46a
feat(vehicle): embed current trailers on the vehicle serializer
roncodes Sep 8, 2026
af28c00
chore(release): open v0.2.0 release branch
roncodes Sep 8, 2026
a66ec82
fix: guard the date getters in payload, integrated-vendor and service…
roncodes Sep 8, 2026
d3af324
fix: drop the dead vehicle-array branch from the driver serializer
roncodes Sep 8, 2026
cf87eab
fix: point the order missing_* macros at properties that exist
roncodes Sep 8, 2026
d081616
fix: re-export the geojson barrel's named exports from the app tree
roncodes Sep 8, 2026
fe7dffc
fix: reconcile saved fee drafts by shape in the service-rate serializer
roncodes Sep 8, 2026
39ebd4d
fix: stop the relation loaders re-fetching records already in hand
roncodes Sep 8, 2026
556d259
fix: clear customer_type instead of throwing in the entity serializer
roncodes Sep 8, 2026
1e6bf3e
refactor(order): drop two loader guards already implied by the checks…
roncodes Sep 8, 2026
e008077
refactor(payload): drop the orderWaypoints fallback for an unsettable…
roncodes Sep 8, 2026
d4eb508
refactor(service-rate): collapse the fee ranking and drop the hasMany…
roncodes Sep 8, 2026
b09a5f8
refactor(device): call the inherited serializePolymorphicType directly
roncodes Sep 8, 2026
51496cc
fix(coverage-gate): verify zero-statement files and refuse colliding …
roncodes Sep 8, 2026
b1bf393
ci: run on release branches, keep Codecov upload errors from failing …
roncodes Sep 8, 2026
79c8b16
docs: describe the end state in DEFECTS.md
roncodes Sep 8, 2026
20e6531
Merge pull request #72 from fleetbase/feature/test-coverage-and-codecov
roncodes Sep 9, 2026
4c5105a
Merge pull request #68 from fleetbase/feature/maintenance-platform-up…
roncodes Sep 9, 2026
cb19f11
Merge pull request #71 from fleetbase/feature/add-is-waypoint-record
roncodes Sep 9, 2026
4429898
Merge branch 'release/v0.2.0' into feature/first-class-trailers
roncodes Sep 9, 2026
0f9186c
Merge pull request #75 from fleetbase/feature/first-class-trailers
roncodes Sep 9, 2026
3c3a077
fix: restore the peer suffixes the lockfile merge dropped
roncodes Sep 9, 2026
6d5a0e8
fix: repair the tests the release merges broke and drop the equipment…
roncodes Sep 9, 2026
dbf30e1
test: cover the trailer, asset-connection and inspection additions
roncodes Sep 9, 2026
7b7167a
docs: remove DEFECTS.md before the release
roncodes Sep 9, 2026
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
9 changes: 9 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ module.exports = {
'./testem.js',
'./blueprints/*/index.js',
'./config/**/*.js',
'./scripts/**/*.js',
'./tests/dummy/config/**/*.js',
],
parserOptions: {
Expand All @@ -45,6 +46,14 @@ module.exports = {
node: true,
},
extends: ['plugin:n/recommended'],
rules: {
// `ember-cli-code-coverage` is a devDependency that is only
// required when COVERAGE=true, which never happens in a consumer
// build. The coverage gate under `scripts/` is likewise a
// development-only tool that ships with the repository, not with
// the published package.
'n/no-unpublished-require': 'off',
},
},
],
};
131 changes: 87 additions & 44 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,86 +2,129 @@ name: Ember CI

on:
push:
branches: [ main ]
branches: [main, 'release/**']
tags:
- 'v*'
pull_request:
branches: [ main ]
branches: [main, 'release/**']

# Least privilege by default; the publishing jobs opt into what they need.
permissions:
contents: read

# A newer push to the same branch or pull request supersedes the run in flight.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

env:
NODE_VERSION: 22.x

jobs:
build:
test:
name: Lint, test, coverage and build
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4

# `version` is intentionally omitted: pnpm/action-setup reads the pinned
# version from the `packageManager` field in package.json.
- name: Setup pnpm
uses: pnpm/action-setup@v4

- name: Setup Node.js ${{ env.NODE_VERSION }}
uses: actions/setup-node@v2
with:
node-version: ${{ env.NODE_VERSION }}
- name: Setup Node.js ${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: pnpm

- name: Setup pnpm
uses: pnpm/action-setup@v2.0.1
with:
version: latest
- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Install Dependencies
run: pnpm install
- name: Lint
run: pnpm run lint

- name: Build
run: pnpm run build
# The coverage gate is the thing that proves the coverage number; test it
# before trusting what it reports.
- name: Test the coverage gate
run: pnpm run test:coverage-gate

- name: Run tests with coverage
run: pnpm run coverage

# Uploaded before the gate so a shortfall is still visible on the pull
# request rather than being hidden behind a failed step. The upload is
# reporting, not enforcement: the gate below is what proves coverage, so
# a Codecov outage or rate limit must not fail a build that passed.
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
with:
files: ./coverage/lcov.info
flags: fleetops-data
name: fleetops-data
fail_ci_if_error: false
# Forked pull requests cannot read secrets; Codecov accepts tokenless
# uploads from public repositories, so this is empty rather than absent.
token: ${{ secrets.CODECOV_TOKEN }}

- name: Enforce 100% coverage
run: pnpm run coverage:check

- name: Build
run: pnpm run build

npm_publish:
needs: build
name: Publish to npm
needs: test
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4

- name: Setup Node.js ${{ env.NODE_VERSION }}
uses: actions/setup-node@v2
with:
node-version: ${{ env.NODE_VERSION }}
- name: Setup pnpm
uses: pnpm/action-setup@v4

- name: Setup pnpm
uses: pnpm/action-setup@v2.0.1
with:
version: latest
- name: Setup Node.js ${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: pnpm

- name: Install Dependencies
run: pnpm install
- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Build
run: pnpm run build
- name: Build
run: pnpm run build

- name: Set up npm
run: echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_AUTH_TOKEN }}" > ~/.npmrc
- name: Set up npm
run: echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_AUTH_TOKEN }}" > ~/.npmrc

- name: Publish
run: npm publish --access public
- name: Publish
run: npm publish --access public

github_publish:
needs: build
name: Publish to GitHub Packages
needs: test
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4

- name: Setup pnpm
uses: pnpm/action-setup@v4

- name: Setup Node.js ${{ env.NODE_VERSION }}
uses: actions/setup-node@v2
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: pnpm

- name: Setup pnpm
uses: pnpm/action-setup@v2.0.1
with:
version: latest

- name: Install Dependencies
run: pnpm install
- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Build
run: pnpm run build
Expand Down
3 changes: 3 additions & 0 deletions .stylelintignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@
# compiled output
/dist/

# generated coverage reports
/coverage/

# addons
/.node_modules.ember-try/
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# @fleetbase/fleetops-data

[![codecov](https://codecov.io/gh/fleetbase/fleetops-data/graph/badge.svg)](https://codecov.io/gh/fleetbase/fleetops-data)

[Short description of the addon.]


Expand Down Expand Up @@ -29,4 +31,4 @@ See the [Contributing](CONTRIBUTING.md) guide for details.

## License

This project is licensed under the [MIT License](LICENSE.md).
This project is licensed under the [GNU Affero General Public License v3.0 or later](LICENSE.md) (`AGPL-3.0-or-later`).
11 changes: 5 additions & 6 deletions RELEASE.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
> v0.1.40 ~ "RELEASE_NOTES_PLACEHOLDER — replace this line with the release title"
> v0.2.0 ~ "First-class trailers, inspections and full test coverage"

---
## Highlights

RELEASE_NOTES_PLACEHOLDER

Describe what changed in this release. The first line above must name the version
being released, and both placeholder markers must be gone, or the release workflow
refuses to tag.
- **First-class Trailer data models** — trailer models, serializers and data contracts for the console, with current trailers embedded on the vehicle serializer.
- **Inspection data models** — models and serializers backing the maintenance platform upgrade.
- **`is-waypoint-record` util** — moved out of `ember-core` and into this package.
- **Test coverage campaign** — a 100% coverage gate wired into CI, with Codecov reporting.

---
## Need help?
Expand Down
47 changes: 47 additions & 0 deletions addon/models/asset-connection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import Model, { attr, belongsTo } from '@ember-data/model';
import { computed } from '@ember/object';
import { format as formatDate, isValid as isValidDate, formatDistanceStrict } from 'date-fns';

export default class AssetConnectionModel extends Model {
@attr('string') uuid;
@attr('string') public_id;
@attr('string') company_uuid;
@attr('string') connector_type;
@attr('string') connector_uuid;
@attr('string') connected_type;
@attr('string') connected_uuid;
@attr('string', { defaultValue: 'towing' }) relationship_type;
@attr('number', { defaultValue: 1 }) position;
@attr('string') source;
@attr('string') confidence;
@attr('string') notes;
@attr('raw') meta;
@attr('boolean') active;
@attr('date') connected_at;
@attr('date') disconnected_at;
@attr('date') created_at;
@attr('date') updated_at;

@belongsTo('vehicle', { async: false, inverse: null }) vehicle;
@belongsTo('trailer', { async: false, inverse: null }) trailer;

@computed('active', 'disconnected_at') get isActive() {
return this.active === true || (this.active !== false && !this.disconnected_at);
}

@computed('connected_at') get connectedAt() {
return isValidDate(this.connected_at) ? formatDate(this.connected_at, 'yyyy-MM-dd HH:mm') : null;
}

@computed('disconnected_at') get disconnectedAt() {
return isValidDate(this.disconnected_at) ? formatDate(this.disconnected_at, 'yyyy-MM-dd HH:mm') : null;
}

@computed('connected_at', 'disconnected_at') get duration() {
if (!isValidDate(this.connected_at)) {
return null;
}

return formatDistanceStrict(this.connected_at, isValidDate(this.disconnected_at) ? this.disconnected_at : new Date());
}
}
16 changes: 15 additions & 1 deletion addon/models/asset.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,22 @@ export default class AssetModel extends Model {
@attr('string') odometer_unit;
@attr('string') transmission;
@attr('string') fuel_volume_unit;
@attr('string') fuel_Type;
@attr('string') fuel_type;
@attr('string') ownership_type;
@attr('string') engine_hours;
@attr('string') gvw;
@attr('number') width;
@attr('number') length;
@attr('number') height;
@attr('number') tare_weight;
@attr('number') gvwr;
@attr('number') payload_capacity;
@attr('number') cargo_volume;
@attr('string') currency;
@attr('string') acquisition_cost;
@attr('string') current_value;
@attr('string') insurance_value;
@attr('string') depreciation_rate;
@attr('raw') capacity;
@attr('raw') specs;
@attr('raw') attributes;
Expand All @@ -77,6 +89,8 @@ export default class AssetModel extends Model {

/** @dates */
@attr('date') deleted_at;
@attr('date') purchased_at;
@attr('date') lease_expires_at;
@attr('date') created_at;
@attr('date') updated_at;

Expand Down
18 changes: 18 additions & 0 deletions addon/models/attachable-driver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import AttachableModel from './attachable';
import { attr } from '@ember-data/model';

/**
* Concrete polymorphic model for a Driver that equipment is issued to.
*
* Drivers are not telematics attachables, but equipment can be equipped to a driver
* (`fleet-ops:driver`), and the equipment serializer resolves that polymorphic
* relationship through the attachable model family.
*/
export default class AttachableDriverModel extends AttachableModel {
@attr('string') internal_id;
@attr('string') phone;
@attr('string') email;
@attr('string') drivers_license_number;
@attr('string') vehicle_name;
@attr('string') vendor_name;
}
11 changes: 11 additions & 0 deletions addon/models/attachable-trailer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import AttachableAssetModel from './attachable-asset';
import { attr } from '@ember-data/model';

/** Concrete polymorphic model for a Trailer attached to a device. */
export default class AttachableTrailerModel extends AttachableAssetModel {
@attr('string') body_type;
@attr('string') coupling_type;
@attr('number') axle_count;
@attr('boolean') refrigerated;
@attr('string') current_vehicle_name;
}
2 changes: 1 addition & 1 deletion addon/models/attachable.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { format as formatDate, isValid as isValidDate, formatDistanceToNow } fro

/**
* Abstract base model for resources a device can be attached to.
* Concrete types: attachable-vehicle, attachable-asset.
* Concrete types: attachable-vehicle, attachable-asset, attachable-trailer.
*/
export default class AttachableModel extends Model {
/** @ids */
Expand Down
2 changes: 1 addition & 1 deletion addon/models/driver.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { computed, get } from '@ember/object';
import { not } from '@ember/object/computed';
import { getOwner } from '@ember/application';
import { format as formatDate, isValid as isValidDate, formatDistanceToNow } from 'date-fns';
import isRelationMissing from '@fleetbase/ember-core/utils/is-relation-missing';
import isRelationMissing from '../utils/is-relation-missing';
import isValidCoordinates from '@fleetbase/ember-core/utils/is-valid-coordinates';
import config from 'ember-get-config';

Expand Down
1 change: 1 addition & 0 deletions addon/models/equipment.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export default class EquipmentModel extends Model {
/** @relationships */
@belongsTo('warranty', { async: false }) warranty;
@belongsTo('file', { async: false }) photo;
@belongsTo('attachable', { polymorphic: true, async: false }) equipable;
@hasMany('maintenance', { async: false }) maintenances;
@hasMany('custom-field-value', { async: false }) custom_field_values;

Expand Down
2 changes: 1 addition & 1 deletion addon/models/fuel-report.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Model, { attr, belongsTo, hasMany } from '@ember-data/model';
import { computed } from '@ember/object';
import { getOwner } from '@ember/application';
import { format as formatDate, isValid as isValidDate, formatDistanceToNow } from 'date-fns';
import isRelationMissing from '@fleetbase/ember-core/utils/is-relation-missing';
import isRelationMissing from '../utils/is-relation-missing';

export default class FuelReportModel extends Model {
/** @ids */
Expand Down
Loading
Loading